feat: 串口连接参数存储
This commit is contained in:
29
src/lib/stores/serial.options.ts
Normal file
29
src/lib/stores/serial.options.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { derived, get } from 'svelte/store';
|
||||
import { baudRate, dataBits, stopBits, parity, flowControl } from './serial';
|
||||
|
||||
export function getSerialOptions(): SerialOptions {
|
||||
return {
|
||||
baudRate: get(baudRate),
|
||||
dataBits: get(dataBits) as 7 | 8,
|
||||
stopBits: get(stopBits) as 1 | 2,
|
||||
parity: get(parity),
|
||||
flowControl: get(flowControl),
|
||||
};
|
||||
}
|
||||
|
||||
export const serialOptions = derived(
|
||||
[baudRate, dataBits, stopBits, parity, flowControl],
|
||||
([
|
||||
$baudRate,
|
||||
$dataBits,
|
||||
$stopBits,
|
||||
$parity,
|
||||
$flowControl,
|
||||
]): SerialOptions => ({
|
||||
baudRate: $baudRate,
|
||||
dataBits: $dataBits as 7 | 8,
|
||||
stopBits: $stopBits as 1 | 2,
|
||||
parity: $parity,
|
||||
flowControl: $flowControl,
|
||||
})
|
||||
);
|
||||
47
src/lib/stores/serial.ts
Normal file
47
src/lib/stores/serial.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { derived, writable, get } from 'svelte/store';
|
||||
import { useLocalStorage } from './utils/useLocalStorage';
|
||||
|
||||
export type ReadType = 'hex' | 'ascii' | 'dec';
|
||||
|
||||
const defaultBaudRatesList = [9600, 19200, 38400, 57600, 115200];
|
||||
|
||||
/* ---------------- 派生状态 ---------------- */
|
||||
export const baudRate = useLocalStorage<number>('baudRate', 9600);
|
||||
export const baudRateList = useLocalStorage<number[]>(
|
||||
'baudRateList',
|
||||
defaultBaudRatesList
|
||||
);
|
||||
|
||||
export const dataBits = writable<number>(8);
|
||||
export const stopBits = writable<number>(1);
|
||||
export const parity = writable<ParityType>('none');
|
||||
export const flowControl = writable<FlowControlType>('none');
|
||||
|
||||
export const readType = useLocalStorage<ReadType>('readType', 'hex');
|
||||
export const sendType = useLocalStorage<ReadType>('sendType', 'hex');
|
||||
|
||||
export const hasDecTypes = useLocalStorage<boolean>('hasDecTypes', false);
|
||||
|
||||
/* ---------------- 派生状态 ---------------- */
|
||||
export const recordTypes = derived(hasDecTypes, ($hasDecTypes) =>
|
||||
$hasDecTypes
|
||||
? (['hex', 'ascii', 'dec'] satisfies ReadType[])
|
||||
: (['hex', 'ascii'] satisfies ReadType[])
|
||||
);
|
||||
|
||||
/* ---------------- Actions ---------------- */
|
||||
export function nextReadType() {
|
||||
const types = get(recordTypes);
|
||||
const current = get(readType);
|
||||
|
||||
const index = types.indexOf(current);
|
||||
readType.set(types[(index + 1) % types.length]);
|
||||
}
|
||||
|
||||
export function nextSendType() {
|
||||
const types = get(recordTypes);
|
||||
const current = get(sendType);
|
||||
|
||||
const index = types.indexOf(current);
|
||||
sendType.set(types[(index + 1) % types.length]);
|
||||
}
|
||||
60
src/lib/stores/serial.ui.ts
Normal file
60
src/lib/stores/serial.ui.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { derived } from 'svelte/store';
|
||||
import { baudRate, baudRateList, dataBits, parity, stopBits } from './serial';
|
||||
import { createUIBridge } from './utils/uiBridge';
|
||||
import { isOneOf } from './utils/typeGuard';
|
||||
|
||||
export const baudRateItems = derived(baudRateList, ($list) =>
|
||||
$list.map((rate) => ({
|
||||
value: String(rate),
|
||||
label: `${rate}`,
|
||||
}))
|
||||
);
|
||||
|
||||
const baudRateBridge = createUIBridge(
|
||||
baudRate,
|
||||
(v) => String(v),
|
||||
(v) => {
|
||||
const n = Number(v);
|
||||
return Number.isFinite(n) ? n : undefined;
|
||||
}
|
||||
);
|
||||
|
||||
export const baudRateValue = baudRateBridge.store;
|
||||
|
||||
const dataBitsBridge = createUIBridge(
|
||||
dataBits,
|
||||
(v) => String(v),
|
||||
(v) => {
|
||||
const n = Number(v);
|
||||
return n;
|
||||
}
|
||||
);
|
||||
|
||||
export const dataBitsValue = dataBitsBridge.store;
|
||||
|
||||
const parityBridge = createUIBridge(
|
||||
parity,
|
||||
(v) => String(v),
|
||||
(v) => {
|
||||
const PARITY_VALUES = ['none', 'odd', 'even'] as const;
|
||||
if (!isOneOf(v, PARITY_VALUES)) {
|
||||
console.warn(`Invalid parity value: ${v}`);
|
||||
return undefined;
|
||||
}
|
||||
const n = v;
|
||||
return n;
|
||||
}
|
||||
);
|
||||
|
||||
export const parityValue = parityBridge.store;
|
||||
|
||||
const stopBitsBridge = createUIBridge(
|
||||
stopBits,
|
||||
(v) => String(v),
|
||||
(v) => {
|
||||
const n = Number(v);
|
||||
return n;
|
||||
}
|
||||
);
|
||||
|
||||
export const stopBitsValue = stopBitsBridge.store;
|
||||
6
src/lib/stores/utils/typeGuard.ts
Normal file
6
src/lib/stores/utils/typeGuard.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export function isOneOf<T extends readonly unknown[]>(
|
||||
value: unknown,
|
||||
allowed: T
|
||||
): value is T[number] {
|
||||
return allowed.includes(value as T[number]);
|
||||
}
|
||||
36
src/lib/stores/utils/uiBridge.ts
Normal file
36
src/lib/stores/utils/uiBridge.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { get, writable, type Writable } from 'svelte/store';
|
||||
|
||||
export function createUIBridge<T, U>(
|
||||
source: Writable<T>,
|
||||
toUI: (value: T) => U,
|
||||
fromUI: (value: U) => T | undefined
|
||||
) {
|
||||
const ui = writable<U>(toUI(get(source)));
|
||||
|
||||
let syncing = false;
|
||||
|
||||
const unsubSource = source.subscribe((v) => {
|
||||
if (syncing) return;
|
||||
syncing = true;
|
||||
ui.set(toUI(v));
|
||||
syncing = false;
|
||||
});
|
||||
|
||||
const unsubUI = ui.subscribe((v) => {
|
||||
if (syncing) return;
|
||||
const next = fromUI(v);
|
||||
if (next === undefined) return;
|
||||
|
||||
syncing = true;
|
||||
source.set(next);
|
||||
syncing = false;
|
||||
});
|
||||
|
||||
return {
|
||||
store: ui,
|
||||
destroy() {
|
||||
unsubSource();
|
||||
unsubUI();
|
||||
},
|
||||
};
|
||||
}
|
||||
22
src/lib/stores/utils/useLocalStorage.ts
Normal file
22
src/lib/stores/utils/useLocalStorage.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
|
||||
export function useLocalStorage<T>(key: string, initialValue: T): Writable<T> {
|
||||
let startValue = initialValue;
|
||||
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const stored = localStorage.getItem(key);
|
||||
if (stored !== null) {
|
||||
startValue = JSON.parse(stored);
|
||||
}
|
||||
}
|
||||
|
||||
const store = writable<T>(startValue);
|
||||
|
||||
store.subscribe((value) => {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem(key, JSON.stringify(value));
|
||||
}
|
||||
});
|
||||
|
||||
return store;
|
||||
}
|
||||
Reference in New Issue
Block a user