This commit is contained in:
BuGu
2025-03-20 18:02:57 +08:00
6 changed files with 126 additions and 36 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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>
</>
);
};
};

View File

@@ -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 = () => {