mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
Merge branch 'main' of https://github.com/sipeed/NanoKVM
This commit is contained in:
@@ -107,7 +107,7 @@ The NanoKVM image is built on LicheeRV Nano SDK and MaixCDK, and is compatible w
|
||||
Note: Out of the 256MB memory in SG2002, 158MB is currently allocated for the multimedia subsystem, which NanoKVM will use for video image acquisition and processing.
|
||||
|
||||
+ [NanoKVM-A Schematic](https://cn.dl.sipeed.com/fileList/KVM/nanoKVM/HDK/02_Schematic/SCH_RV_Nano_KVM_A_30111.pdf)
|
||||
+ [NanoKVM-B Schematic](https://cn.dl.sipeed.com/fileList/KVM/nanoKVM/HDK/02_Schematic/SCH_HDMI_MIPI_31011.pdf)
|
||||
+ [NanoKVM-B Schematic](https://cn.dl.sipeed.com/fileList/KVM/nanoKVM/HDK/02_Schematic/SCH_RV_Nano_KVM_B_30131.pdf)
|
||||
+ [NanoKVM img](https://github.com/sipeed/NanoKVM/releases/tag/NanoKVM)
|
||||
|
||||
## Roadmap
|
||||
|
||||
@@ -2,41 +2,38 @@ import os
|
||||
import shutil
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
import pathlib
|
||||
import requests
|
||||
|
||||
temporary = "/root/.kvm-cache/"
|
||||
temporary: str = "/root/.kvm-cache/"
|
||||
|
||||
|
||||
def mkdir():
|
||||
is_exists = os.path.exists(temporary)
|
||||
if is_exists:
|
||||
def mkdir() -> None:
|
||||
if pathlib.Path(temporary).exists():
|
||||
shutil.rmtree(temporary)
|
||||
os.mkdir(temporary)
|
||||
print(f"create temporary directory {temporary}")
|
||||
pathlib.Path(temporary).mkdir()
|
||||
print(f"Created temporary directory {temporary}")
|
||||
|
||||
|
||||
def read(file):
|
||||
with open(file, "r") as f:
|
||||
content = f.read()
|
||||
return content.replace("\n", "")
|
||||
def read(file: str) -> str:
|
||||
return pathlib.Path(file).read_text().replace("\n", "")
|
||||
|
||||
|
||||
def download_firmware():
|
||||
print("download firmware...")
|
||||
def download_firmware() -> None:
|
||||
print("Downloading firmware...")
|
||||
|
||||
now = int(time.time())
|
||||
url = f"https://cdn.sipeed.com/nanokvm/latest.zip?n={now}"
|
||||
print(f"download from {url}")
|
||||
print(f"Downloading firmware from {url}")
|
||||
|
||||
response = requests.get(url)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"download firmware failed, status: {response.status_code}")
|
||||
raise Exception(f"Failed to download firmware, status: {response.status_code}")
|
||||
|
||||
content_type = response.headers.get("content-type")
|
||||
if content_type != "application/zip":
|
||||
raise Exception(f"download firmware failed, content_type: {content_type}")
|
||||
raise Exception(f"Failed to download firmware, content_type: {content_type}")
|
||||
|
||||
zip_file = f"{temporary}/latest.zip"
|
||||
with open(zip_file, "wb") as f:
|
||||
@@ -46,7 +43,7 @@ def download_firmware():
|
||||
with zipfile.ZipFile(zip_file, "r") as f:
|
||||
f.extractall(temporary)
|
||||
|
||||
print("download firmware done")
|
||||
print("Completed downloading firmware.")
|
||||
|
||||
|
||||
def download_lib():
|
||||
@@ -75,20 +72,20 @@ def download_lib():
|
||||
print("download lib done")
|
||||
|
||||
|
||||
def update():
|
||||
backup_dir = "/root/old"
|
||||
firmware_dir = "/kvmapp"
|
||||
def update() -> None:
|
||||
backup_dir = pathlib.Path("/root/old")
|
||||
firmware_dir = pathlib.Path("/kvmapp")
|
||||
|
||||
if os.path.exists(backup_dir):
|
||||
shutil.rmtree(backup_dir)
|
||||
if backup_dir.exists():
|
||||
shutil.rmtree(backup_dir)
|
||||
|
||||
if os.path.exists(firmware_dir):
|
||||
shutil.move(firmware_dir, backup_dir)
|
||||
if firmware_dir.exists():
|
||||
firmware_dir.rename(backup_dir)
|
||||
|
||||
shutil.move(f"{temporary}/latest", firmware_dir)
|
||||
pathlib.Path(f"{temporary}/latest").rename(firmware_dir)
|
||||
|
||||
|
||||
def change_permissions():
|
||||
def change_permissions() -> None:
|
||||
for root, dirs, files in os.walk("/kvmapp"):
|
||||
os.chmod(root, 0o755)
|
||||
|
||||
@@ -99,12 +96,12 @@ def change_permissions():
|
||||
print("change permissions done")
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
try:
|
||||
print("stop service...")
|
||||
print("Stopping nanokvm service...")
|
||||
os.system("/etc/init.d/S95nanokvm stop")
|
||||
|
||||
print("start update......")
|
||||
print("Staring update...")
|
||||
|
||||
mkdir()
|
||||
download_firmware()
|
||||
@@ -113,7 +110,7 @@ def main():
|
||||
change_permissions()
|
||||
|
||||
version = read("/kvmapp/version")
|
||||
print(f"update to {version} success.")
|
||||
print(f"Successfully updated to version: {version}")
|
||||
print("restart service\nthe nanokvm will reboot")
|
||||
except Exception as e:
|
||||
print(f"update failed\n{e}")
|
||||
@@ -123,4 +120,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -133,6 +133,16 @@ const en = {
|
||||
serialPort: 'Serial Port',
|
||||
serialPortPlaceholder: 'Please enter the serial port',
|
||||
baudrate: 'Baud rate',
|
||||
parity: 'Parity',
|
||||
parityNone: 'None',
|
||||
parityEven: 'Even',
|
||||
parityOdd: 'Odd',
|
||||
flowControl: 'Flow control',
|
||||
flowControlNone: 'None',
|
||||
flowControlSoft: 'Soft',
|
||||
flowControlHard: 'Hard',
|
||||
dataBits: 'Data bits',
|
||||
stopBits: 'Stop bits',
|
||||
confirm: 'Ok'
|
||||
},
|
||||
wol: {
|
||||
|
||||
@@ -122,6 +122,16 @@ const pl = {
|
||||
serialPort: 'Port szeregowy',
|
||||
serialPortPlaceholder: 'Wprowadź port szeregowy',
|
||||
baudrate: 'Szybkość transmisji',
|
||||
parity: 'Kontrola parzystości',
|
||||
parityNone: 'Brak kontroli',
|
||||
parityEven: 'Parzystość',
|
||||
parityOdd: 'Nieparzystość',
|
||||
flowControl: 'Kontrola przepływu',
|
||||
flowControlNone: 'Brak kontroli',
|
||||
flowControlSoft: 'Miękka',
|
||||
flowControlHard: 'Twarda',
|
||||
dataBits: 'Bity danych',
|
||||
stopBits: 'Bity stopu',
|
||||
confirm: 'Ok'
|
||||
},
|
||||
wol: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChangeEvent, useState } from 'react';
|
||||
import { Button, Input, InputNumber, Modal, Radio, RadioChangeEvent } from 'antd';
|
||||
import { Button, Input, InputNumber, Modal, Radio, RadioChangeEvent, Select } from 'antd';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { SquareTerminalIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -13,6 +13,10 @@ export const SerialPort = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [port, setPort] = useState('');
|
||||
const [baudrate, setBaudrate] = useState(115200);
|
||||
const [parity, setParity] = useState<string>('none');
|
||||
const [flowControl, setFlowControl] = useState<string>('none');
|
||||
const [dataBits, setDataBits] = useState(8);
|
||||
const [stopBits, setStopBits] = useState(1);
|
||||
|
||||
function openModal() {
|
||||
setIsKeyboardEnable(false);
|
||||
@@ -45,7 +49,7 @@ export const SerialPort = () => {
|
||||
}
|
||||
|
||||
setIsModalOpen(false);
|
||||
window.open(`/#terminal?port=${port}&baud=${baudrate}`, '_blank');
|
||||
window.open(`/#terminal?port=${port}&baud=${baudrate}&parity=${parity}&flowControl=${flowControl}&dataBits=${dataBits}&stopBits=${stopBits}`, '_blank');
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -92,6 +96,71 @@ export const SerialPort = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-7 flex items-center space-x-[20px]">
|
||||
<div className="flex w-[80px] justify-end text-neutral-400">{t('terminal.parity')}</div>
|
||||
<div className="w-1/2">
|
||||
<Select
|
||||
defaultValue="none"
|
||||
value={parity}
|
||||
onChange={setParity}
|
||||
options={[
|
||||
{ label: t('terminal.parityNone'), value: 'none' },
|
||||
{ label: t('terminal.parityEven'), value: 'even' },
|
||||
{ label: t('terminal.parityOdd'), value: 'odd' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-7 flex items-center space-x-[20px]">
|
||||
<div className="flex w-[80px] justify-end text-neutral-400">{t('terminal.flowControl')}</div>
|
||||
<div className="w-1/2">
|
||||
<Select
|
||||
defaultValue="none"
|
||||
value={flowControl}
|
||||
onChange={setFlowControl}
|
||||
options={[
|
||||
{ label: t('terminal.flowControlNone'), value: 'none' },
|
||||
{ label: t('terminal.flowControlSoft'), value: 'soft' },
|
||||
{ label: t('terminal.flowControlHard'), value: 'hard' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="mt-7 flex items-center space-x-[20px]">
|
||||
<div className="flex w-[80px] justify-end text-neutral-400">{t('terminal.dataBits')}</div>
|
||||
<div className="w-1/2">
|
||||
<Select
|
||||
defaultValue={8}
|
||||
value={dataBits}
|
||||
onChange={setDataBits}
|
||||
options={[
|
||||
{ label: '5', value: 5 },
|
||||
{ label: '6', value: 6 },
|
||||
{ label: '7', value: 7 },
|
||||
{ label: '8', value: 8 }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-7 flex items-center space-x-[20px]">
|
||||
<div className="flex w-[80px] justify-end text-neutral-400">{t('terminal.stopBits')}</div>
|
||||
<div className="w-1/2">
|
||||
<Select
|
||||
defaultValue={1}
|
||||
value={stopBits}
|
||||
onChange={setStopBits}
|
||||
options={[
|
||||
{ label: '1', value: 1 },
|
||||
{ label: '2', value: 2 }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 mt-12 flex justify-center">
|
||||
<Button type="primary" onClick={submit}>
|
||||
{t('terminal.confirm')}
|
||||
@@ -100,4 +169,4 @@ export const SerialPort = () => {
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -48,9 +48,13 @@ export const Terminal = () => {
|
||||
const searchParams = new URLSearchParams(urls[1]);
|
||||
const port = searchParams.get('port');
|
||||
const baud = searchParams.get('baud');
|
||||
const parity = searchParams.get('parity');
|
||||
const flowControl = searchParams.get('flowControl');
|
||||
const dataBits = searchParams.get('dataBits');
|
||||
const stopBits = searchParams.get('stopBits');
|
||||
if (!port || !baud) return;
|
||||
|
||||
ws.send(`picocom ${port} -b ${baud}\r`);
|
||||
ws.send(`picocom ${port} --baud ${baud} --parity ${parity} --flow ${flowControl} --databits ${dataBits} --stopbits ${stopBits}\r`);
|
||||
};
|
||||
|
||||
const resizeScreen = () => {
|
||||
|
||||
Reference in New Issue
Block a user