@tx5dr/contracts 1.7.12 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.js +27 -0
- package/dist/schema/__tests__/android-operator-audio.schema.test.js.map +1 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.js +114 -0
- package/dist/schema/__tests__/assisted-queue.schema.test.js.map +1 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.js +42 -0
- package/dist/schema/__tests__/audio-sidecar.schema.test.js.map +1 -0
- package/dist/schema/__tests__/audio.schema.test.js +92 -1
- package/dist/schema/__tests__/audio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/diagnostics.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/diagnostics.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/diagnostics.schema.test.js +31 -0
- package/dist/schema/__tests__/diagnostics.schema.test.js.map +1 -0
- package/dist/schema/__tests__/logbook-health.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/logbook-health.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/logbook-health.schema.test.js +104 -0
- package/dist/schema/__tests__/logbook-health.schema.test.js.map +1 -0
- package/dist/schema/__tests__/meter.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/meter.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/meter.schema.test.js +27 -0
- package/dist/schema/__tests__/meter.schema.test.js.map +1 -0
- package/dist/schema/__tests__/observability.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/observability.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/observability.schema.test.js +12 -0
- package/dist/schema/__tests__/observability.schema.test.js.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js +70 -0
- package/dist/schema/__tests__/operator-context-report.schema.test.js.map +1 -0
- package/dist/schema/__tests__/operator.schema.test.js +9 -3
- package/dist/schema/__tests__/operator.schema.test.js.map +1 -1
- package/dist/schema/__tests__/plugin-market.schema.test.js +149 -3
- package/dist/schema/__tests__/plugin-market.schema.test.js.map +1 -1
- package/dist/schema/__tests__/qso.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/qso.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/qso.schema.test.js +70 -0
- package/dist/schema/__tests__/qso.schema.test.js.map +1 -0
- package/dist/schema/__tests__/radio-power-support.test.js +15 -0
- package/dist/schema/__tests__/radio-power-support.test.js.map +1 -1
- package/dist/schema/__tests__/radio-profile.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/radio-profile.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/radio-profile.schema.test.js +36 -0
- package/dist/schema/__tests__/radio-profile.schema.test.js.map +1 -0
- package/dist/schema/__tests__/radio.schema.test.js +92 -1
- package/dist/schema/__tests__/radio.schema.test.js.map +1 -1
- package/dist/schema/__tests__/realtime-settings.schema.test.js +2 -1
- package/dist/schema/__tests__/realtime-settings.schema.test.js.map +1 -1
- package/dist/schema/__tests__/remote-access.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/remote-access.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/remote-access.schema.test.js +18 -0
- package/dist/schema/__tests__/remote-access.schema.test.js.map +1 -0
- package/dist/schema/__tests__/spectrum.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/spectrum.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/spectrum.schema.test.js +107 -0
- package/dist/schema/__tests__/spectrum.schema.test.js.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts +2 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.d.ts.map +1 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js +95 -0
- package/dist/schema/__tests__/strategy-transmission.schema.test.js.map +1 -0
- package/dist/schema/android-operator-audio.schema.d.ts +174 -0
- package/dist/schema/android-operator-audio.schema.d.ts.map +1 -0
- package/dist/schema/android-operator-audio.schema.js +38 -0
- package/dist/schema/android-operator-audio.schema.js.map +1 -0
- package/dist/schema/api-response.schema.d.ts +503 -44
- package/dist/schema/api-response.schema.d.ts.map +1 -1
- package/dist/schema/api-response.schema.js +9 -0
- package/dist/schema/api-response.schema.js.map +1 -1
- package/dist/schema/audio-sidecar.schema.d.ts +75 -0
- package/dist/schema/audio-sidecar.schema.d.ts.map +1 -1
- package/dist/schema/audio-sidecar.schema.js +32 -0
- package/dist/schema/audio-sidecar.schema.js.map +1 -1
- package/dist/schema/audio.schema.d.ts +4749 -3
- package/dist/schema/audio.schema.d.ts.map +1 -1
- package/dist/schema/audio.schema.js +101 -2
- package/dist/schema/audio.schema.js.map +1 -1
- package/dist/schema/auth.schema.d.ts +173 -14
- package/dist/schema/auth.schema.d.ts.map +1 -1
- package/dist/schema/auth.schema.js +65 -1
- package/dist/schema/auth.schema.js.map +1 -1
- package/dist/schema/cpu-profile.schema.d.ts +2 -2
- package/dist/schema/cw-decoder.schema.d.ts +74 -74
- package/dist/schema/cw-keyer.schema.d.ts +20 -14
- package/dist/schema/cw-keyer.schema.d.ts.map +1 -1
- package/dist/schema/cw-keyer.schema.js +3 -0
- package/dist/schema/cw-keyer.schema.js.map +1 -1
- package/dist/schema/desktop-https.schema.d.ts +6 -6
- package/dist/schema/device-ui.schema.d.ts +16 -16
- package/dist/schema/diagnostics.schema.d.ts +163 -0
- package/dist/schema/diagnostics.schema.d.ts.map +1 -0
- package/dist/schema/diagnostics.schema.js +46 -0
- package/dist/schema/diagnostics.schema.js.map +1 -0
- package/dist/schema/ft8.schema.d.ts +12 -2
- package/dist/schema/ft8.schema.d.ts.map +1 -1
- package/dist/schema/ft8.schema.js +8 -0
- package/dist/schema/ft8.schema.js.map +1 -1
- package/dist/schema/image-radio.schema.d.ts +2597 -0
- package/dist/schema/image-radio.schema.d.ts.map +1 -0
- package/dist/schema/image-radio.schema.js +283 -0
- package/dist/schema/image-radio.schema.js.map +1 -0
- package/dist/schema/logbook.schema.d.ts +2128 -18
- package/dist/schema/logbook.schema.d.ts.map +1 -1
- package/dist/schema/logbook.schema.js +159 -1
- package/dist/schema/logbook.schema.js.map +1 -1
- package/dist/schema/mode.schema.d.ts +4 -6
- package/dist/schema/mode.schema.d.ts.map +1 -1
- package/dist/schema/mode.schema.js +18 -6
- package/dist/schema/mode.schema.js.map +1 -1
- package/dist/schema/observability.schema.d.ts +66 -0
- package/dist/schema/observability.schema.d.ts.map +1 -0
- package/dist/schema/observability.schema.js +20 -0
- package/dist/schema/observability.schema.js.map +1 -0
- package/dist/schema/openwebrx.schema.d.ts +2 -2
- package/dist/schema/operator.schema.d.ts +2682 -6
- package/dist/schema/operator.schema.d.ts.map +1 -1
- package/dist/schema/operator.schema.js +10 -20
- package/dist/schema/operator.schema.js.map +1 -1
- package/dist/schema/plugin.schema.d.ts +1977 -492
- package/dist/schema/plugin.schema.d.ts.map +1 -1
- package/dist/schema/plugin.schema.js +165 -14
- package/dist/schema/plugin.schema.js.map +1 -1
- package/dist/schema/process-monitor.schema.d.ts +132 -132
- package/dist/schema/pskreporter.schema.d.ts +1 -3
- package/dist/schema/pskreporter.schema.d.ts.map +1 -1
- package/dist/schema/pskreporter.schema.js +1 -3
- package/dist/schema/pskreporter.schema.js.map +1 -1
- package/dist/schema/qso.schema.d.ts +246 -1
- package/dist/schema/qso.schema.d.ts.map +1 -1
- package/dist/schema/qso.schema.js +68 -0
- package/dist/schema/qso.schema.js.map +1 -1
- package/dist/schema/radio-capability.schema.d.ts +31 -40
- package/dist/schema/radio-capability.schema.d.ts.map +1 -1
- package/dist/schema/radio-capability.schema.js +8 -15
- package/dist/schema/radio-capability.schema.js.map +1 -1
- package/dist/schema/radio-power-support.d.ts.map +1 -1
- package/dist/schema/radio-power-support.js +3 -0
- package/dist/schema/radio-power-support.js.map +1 -1
- package/dist/schema/radio-power.schema.d.ts +102 -13
- package/dist/schema/radio-power.schema.d.ts.map +1 -1
- package/dist/schema/radio-power.schema.js +15 -8
- package/dist/schema/radio-power.schema.js.map +1 -1
- package/dist/schema/radio-profile.schema.d.ts +1491 -97
- package/dist/schema/radio-profile.schema.d.ts.map +1 -1
- package/dist/schema/radio-profile.schema.js +7 -0
- package/dist/schema/radio-profile.schema.js.map +1 -1
- package/dist/schema/radio.schema.d.ts +442 -48
- package/dist/schema/radio.schema.d.ts.map +1 -1
- package/dist/schema/radio.schema.js +75 -7
- package/dist/schema/radio.schema.js.map +1 -1
- package/dist/schema/realtime.schema.d.ts +60 -52
- package/dist/schema/realtime.schema.d.ts.map +1 -1
- package/dist/schema/realtime.schema.js +9 -1
- package/dist/schema/realtime.schema.js.map +1 -1
- package/dist/schema/rigctld.schema.d.ts +6 -6
- package/dist/schema/slot-info.schema.d.ts +28 -9
- package/dist/schema/slot-info.schema.d.ts.map +1 -1
- package/dist/schema/slot-info.schema.js +17 -10
- package/dist/schema/slot-info.schema.js.map +1 -1
- package/dist/schema/spectrum-config.schema.d.ts +638 -0
- package/dist/schema/spectrum-config.schema.d.ts.map +1 -0
- package/dist/schema/spectrum-config.schema.js +129 -0
- package/dist/schema/spectrum-config.schema.js.map +1 -0
- package/dist/schema/spectrum.schema.d.ts +1323 -30
- package/dist/schema/spectrum.schema.d.ts.map +1 -1
- package/dist/schema/spectrum.schema.js +72 -0
- package/dist/schema/spectrum.schema.js.map +1 -1
- package/dist/schema/station-info.schema.d.ts +5 -0
- package/dist/schema/station-info.schema.d.ts.map +1 -1
- package/dist/schema/station-info.schema.js +5 -0
- package/dist/schema/station-info.schema.js.map +1 -1
- package/dist/schema/system.schema.d.ts +56 -6
- package/dist/schema/system.schema.d.ts.map +1 -1
- package/dist/schema/system.schema.js +22 -0
- package/dist/schema/system.schema.js.map +1 -1
- package/dist/schema/transmission.schema.d.ts +8 -7
- package/dist/schema/transmission.schema.d.ts.map +1 -1
- package/dist/schema/transmission.schema.js +2 -7
- package/dist/schema/transmission.schema.js.map +1 -1
- package/dist/schema/tx-audio-input.schema.d.ts +8 -0
- package/dist/schema/tx-audio-input.schema.d.ts.map +1 -0
- package/dist/schema/tx-audio-input.schema.js +19 -0
- package/dist/schema/tx-audio-input.schema.js.map +1 -0
- package/dist/schema/voice-keyer.schema.d.ts +16 -16
- package/dist/schema/voice.schema.d.ts +1 -1
- package/dist/schema/voice.schema.d.ts.map +1 -1
- package/dist/schema/voice.schema.js +1 -1
- package/dist/schema/voice.schema.js.map +1 -1
- package/dist/schema/websocket.schema.d.ts +35811 -7829
- package/dist/schema/websocket.schema.d.ts.map +1 -1
- package/dist/schema/websocket.schema.js +453 -9
- package/dist/schema/websocket.schema.js.map +1 -1
- package/package.json +6 -1
- package/src/index.ts +7 -0
- package/src/schema/__tests__/android-operator-audio.schema.test.ts +31 -0
- package/src/schema/__tests__/assisted-queue.schema.test.ts +122 -0
- package/src/schema/__tests__/audio-sidecar.schema.test.ts +48 -0
- package/src/schema/__tests__/audio.schema.test.ts +102 -0
- package/src/schema/__tests__/diagnostics.schema.test.ts +32 -0
- package/src/schema/__tests__/logbook-health.schema.test.ts +117 -0
- package/src/schema/__tests__/meter.schema.test.ts +28 -0
- package/src/schema/__tests__/observability.schema.test.ts +15 -0
- package/src/schema/__tests__/operator-context-report.schema.test.ts +77 -0
- package/src/schema/__tests__/operator.schema.test.ts +11 -3
- package/src/schema/__tests__/plugin-market.schema.test.ts +165 -2
- package/src/schema/__tests__/qso.schema.test.ts +91 -0
- package/src/schema/__tests__/radio-power-support.test.ts +17 -0
- package/src/schema/__tests__/radio-profile.schema.test.ts +44 -0
- package/src/schema/__tests__/radio.schema.test.ts +108 -1
- package/src/schema/__tests__/realtime-settings.schema.test.ts +2 -1
- package/src/schema/__tests__/remote-access.schema.test.ts +22 -0
- package/src/schema/__tests__/spectrum.schema.test.ts +119 -0
- package/src/schema/__tests__/strategy-transmission.schema.test.ts +106 -0
- package/src/schema/android-operator-audio.schema.ts +49 -0
- package/src/schema/api-response.schema.ts +11 -0
- package/src/schema/audio-sidecar.schema.ts +35 -0
- package/src/schema/audio.schema.ts +115 -2
- package/src/schema/auth.schema.ts +79 -1
- package/src/schema/cw-keyer.schema.ts +5 -0
- package/src/schema/diagnostics.schema.ts +55 -0
- package/src/schema/ft8.schema.ts +8 -0
- package/src/schema/image-radio.schema.ts +342 -0
- package/src/schema/logbook.schema.ts +205 -1
- package/src/schema/mode.schema.ts +18 -6
- package/src/schema/observability.schema.ts +26 -0
- package/src/schema/operator.schema.ts +11 -20
- package/src/schema/plugin.schema.ts +186 -15
- package/src/schema/pskreporter.schema.ts +1 -3
- package/src/schema/qso.schema.ts +78 -0
- package/src/schema/radio-capability.schema.ts +8 -15
- package/src/schema/radio-power-support.ts +3 -0
- package/src/schema/radio-power.schema.ts +15 -8
- package/src/schema/radio-profile.schema.ts +7 -0
- package/src/schema/radio.schema.ts +90 -7
- package/src/schema/realtime.schema.ts +9 -1
- package/src/schema/slot-info.schema.ts +18 -11
- package/src/schema/spectrum-config.schema.ts +156 -0
- package/src/schema/spectrum.schema.ts +89 -0
- package/src/schema/station-info.schema.ts +5 -0
- package/src/schema/system.schema.ts +29 -0
- package/src/schema/transmission.schema.ts +2 -7
- package/src/schema/tx-audio-input.schema.ts +22 -0
- package/src/schema/voice.schema.ts +1 -1
- package/src/schema/websocket.schema.ts +601 -13
- package/test/image-radio-schema.test.ts +107 -0
- package/test/plugin-slot-schema.test.ts +31 -0
- package/test/radio-capability-schema.test.ts +44 -0
- package/CLAUDE.md +0 -41
|
@@ -37,7 +37,9 @@ export const RadioPowerStageSchema = z.enum([
|
|
|
37
37
|
export type RadioPowerStage = z.infer<typeof RadioPowerStageSchema>;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Last known power transition state exposed through WebSocket events and
|
|
41
|
+
* `ctx.radioPower.getState()`. `state` is the controller's high-level state;
|
|
42
|
+
* `stage` is finer progress; errors use a localized key plus diagnostic detail.
|
|
41
43
|
*/
|
|
42
44
|
export const RadioPowerStateEventSchema = z.object({
|
|
43
45
|
profileId: z.string().optional(),
|
|
@@ -51,12 +53,17 @@ export const RadioPowerStateEventSchema = z.object({
|
|
|
51
53
|
export type RadioPowerStateEvent = z.infer<typeof RadioPowerStateEventSchema>;
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
|
-
*
|
|
56
|
+
* Power targets accepted by Host commands. `on`/`off` control physical power;
|
|
57
|
+
* `standby`/`operate` switch a responding radio between controller states.
|
|
55
58
|
*/
|
|
56
|
-
/** Allowed physical radio target states for a power request. */
|
|
57
59
|
export const RadioPowerTargetSchema = z.enum(['on', 'off', 'standby', 'operate']);
|
|
58
60
|
export type RadioPowerTarget = z.infer<typeof RadioPowerTargetSchema>;
|
|
59
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Request to transition one radio profile to a physical/controller power state.
|
|
64
|
+
* `profileId` selects the profile, `state` is the requested target, and
|
|
65
|
+
* `autoEngine` controls whether TX-5DR starts after a successful power-on.
|
|
66
|
+
*/
|
|
60
67
|
export const RadioPowerRequestSchema = z.object({
|
|
61
68
|
profileId: z.string().min(1),
|
|
62
69
|
/** Physical radio power target. This is not the TX-5DR software engine state. */
|
|
@@ -66,9 +73,7 @@ export const RadioPowerRequestSchema = z.object({
|
|
|
66
73
|
});
|
|
67
74
|
export type RadioPowerRequest = z.infer<typeof RadioPowerRequestSchema>;
|
|
68
75
|
|
|
69
|
-
/**
|
|
70
|
-
* REST response: POST /api/radio/power
|
|
71
|
-
*/
|
|
76
|
+
/** Result returned by the REST endpoint and `ctx.radioPowerCommands.submit()`. */
|
|
72
77
|
export const RadioPowerResponseSchema = z.object({
|
|
73
78
|
success: z.boolean(),
|
|
74
79
|
target: RadioPowerTargetSchema,
|
|
@@ -77,8 +82,10 @@ export const RadioPowerResponseSchema = z.object({
|
|
|
77
82
|
export type RadioPowerResponse = z.infer<typeof RadioPowerResponseSchema>;
|
|
78
83
|
|
|
79
84
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
85
|
+
* Power operations supported by one radio profile, returned by REST and
|
|
86
|
+
* `ctx.radioPower.getSupport()`. `reason` explains why wake is unavailable;
|
|
87
|
+
* `supportedStates` lists connected-state transitions the Host may accept.
|
|
88
|
+
* The Host resolves manufacturer/model names through Hamlib.
|
|
82
89
|
*/
|
|
83
90
|
export const RadioPowerSupportInfoSchema = z.object({
|
|
84
91
|
profileId: z.string(),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { HamlibConfigSchema } from './radio.schema.js';
|
|
3
3
|
import { AudioDeviceSettingsSchema } from './audio.schema.js';
|
|
4
|
+
import { TxAudioInputSourcePolicySchema } from './tx-audio-input.schema.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Radio Profile Schema
|
|
@@ -14,9 +15,13 @@ export const RadioProfileSchema = z.object({
|
|
|
14
15
|
radio: HamlibConfigSchema, // 电台连接配置
|
|
15
16
|
audio: AudioDeviceSettingsSchema, // 音频设备配置
|
|
16
17
|
audioLockedToRadio: z.boolean(), // ICOM WLAN = true,音频由电台决定
|
|
18
|
+
/** Optional policy for the radio's physical TX audio input selector. */
|
|
19
|
+
txAudioInputSource: TxAudioInputSourcePolicySchema.optional(),
|
|
17
20
|
createdAt: z.number(),
|
|
18
21
|
updatedAt: z.number(),
|
|
19
22
|
description: z.string().optional(),
|
|
23
|
+
isVirtual: z.boolean().optional(),
|
|
24
|
+
readOnly: z.boolean().optional(),
|
|
20
25
|
});
|
|
21
26
|
|
|
22
27
|
export type RadioProfile = z.infer<typeof RadioProfileSchema>;
|
|
@@ -41,6 +46,7 @@ export const UpdateProfileRequestSchema = z.object({
|
|
|
41
46
|
radio: HamlibConfigSchema.optional(),
|
|
42
47
|
audio: AudioDeviceSettingsSchema.optional(),
|
|
43
48
|
audioLockedToRadio: z.boolean().optional(),
|
|
49
|
+
txAudioInputSource: TxAudioInputSourcePolicySchema.optional(),
|
|
44
50
|
description: z.string().optional(),
|
|
45
51
|
});
|
|
46
52
|
|
|
@@ -52,6 +58,7 @@ export type UpdateProfileRequest = z.infer<typeof UpdateProfileRequestSchema>;
|
|
|
52
58
|
export const ProfileListResponseSchema = z.object({
|
|
53
59
|
profiles: z.array(RadioProfileSchema),
|
|
54
60
|
activeProfileId: z.string().nullable(),
|
|
61
|
+
hasConfiguredProfiles: z.boolean().optional().default(false),
|
|
55
62
|
});
|
|
56
63
|
|
|
57
64
|
export type ProfileListResponse = z.infer<typeof ProfileListResponseSchema>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { CWKeyActiveLevelSchema } from './cw-keyer.schema.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 中继差频方向
|
|
@@ -10,20 +11,24 @@ export const RepeaterShiftSchema = z.enum(['none', 'minus', 'plus']);
|
|
|
10
11
|
*/
|
|
11
12
|
export const ToneSquelchModeSchema = z.enum(['none', 'ctcss', 'dcs']);
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* 预设频率Schema
|
|
15
|
-
*/
|
|
14
|
+
/** Saved dial-frequency preset with band, digital mode and radio modulation. */
|
|
16
15
|
export const PresetFrequencySchema = z.object({
|
|
17
16
|
band: z.string(),
|
|
18
|
-
mode: z.string(), // 协议模式,如 FT8
|
|
17
|
+
mode: z.string(), // 协议模式,如 FT8、FT4、VOICE、SSTV、FAX
|
|
19
18
|
radioMode: z.string().optional(), // 电台调制模式,如 USB, LSB, AM, FM
|
|
20
|
-
frequency: z.number(),
|
|
19
|
+
frequency: z.number().int().positive().max(1_000_000_000), // 拨盘频率,单位 Hz(MHz 输入最多 6 位小数)
|
|
21
20
|
description: z.string().optional(),
|
|
22
21
|
repeaterShift: RepeaterShiftSchema.optional(), // 中继差频方向,默认 none
|
|
23
22
|
repeaterOffsetHz: z.number().int().positive().optional(), // 中继偏移,单位 Hz
|
|
24
23
|
toneMode: ToneSquelchModeSchema.optional(), // 哑音类型,默认 none
|
|
25
24
|
ctcssToneTenthsHz: z.number().int().positive().optional(), // CTCSS,单位 0.1Hz
|
|
26
25
|
dcsCode: z.number().int().positive().optional(), // DCS 码
|
|
26
|
+
region: z.enum(['global', 'iaru1', 'iaru2', 'iaru3']).optional(),
|
|
27
|
+
imagePurpose: z.enum(['activity', 'iss', 'weatherfax']).optional(),
|
|
28
|
+
audioCenterHz: z.number().int().positive().optional(),
|
|
29
|
+
assignedFrequency: z.number().int().positive().max(1_000_000_000).optional(),
|
|
30
|
+
faxEmission: z.enum(['J3C', 'F3C', 'F1C']).optional(),
|
|
31
|
+
carrierFrequency: z.number().positive().optional(), // Legacy field; use assignedFrequency for published WEFAX channels.
|
|
27
32
|
}).superRefine((preset, ctx) => {
|
|
28
33
|
const isVoiceFmPreset = preset.mode === 'VOICE' && preset.radioMode?.toUpperCase() === 'FM';
|
|
29
34
|
const hasRepeaterDuplex = preset.repeaterShift === 'minus' || preset.repeaterShift === 'plus';
|
|
@@ -192,11 +197,44 @@ export const IcomWlanConfigSchema = z.object({
|
|
|
192
197
|
dataMode: z.boolean().optional().default(true),
|
|
193
198
|
});
|
|
194
199
|
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* TCI / SunSDR 连接配置Schema
|
|
203
|
+
*/
|
|
204
|
+
const TciWebSocketUrlSchema = z.string().url()
|
|
205
|
+
.refine((value) => /^wss?:\/\//i.test(value), 'TCI URL must use ws:// or wss://')
|
|
206
|
+
.refine((value) => {
|
|
207
|
+
const parsed = new URL(value);
|
|
208
|
+
return !parsed.username && !parsed.password;
|
|
209
|
+
}, 'TCI URL must not contain credentials');
|
|
210
|
+
|
|
211
|
+
export const TciConfigSchema = z.object({
|
|
212
|
+
host: z.string().default('127.0.0.1'),
|
|
213
|
+
port: z.number().int().min(1).max(65535).default(40001),
|
|
214
|
+
url: TciWebSocketUrlSchema.optional(),
|
|
215
|
+
dialect: z.enum([
|
|
216
|
+
'auto',
|
|
217
|
+
'expertsdr-1.4',
|
|
218
|
+
'expertsdr-1.5-1.8',
|
|
219
|
+
'expertsdr-1.9-2.0',
|
|
220
|
+
'aethersdr-1.5',
|
|
221
|
+
'thetis-2.0',
|
|
222
|
+
'generic-observed',
|
|
223
|
+
]).default('auto'),
|
|
224
|
+
autoDiscoverPorts: z.boolean().default(true),
|
|
225
|
+
receiver: z.number().int().min(0).default(0),
|
|
226
|
+
trx: z.number().int().min(0).default(0),
|
|
227
|
+
vfo: z.number().int().min(0).default(0),
|
|
228
|
+
audioEnabled: z.boolean().optional().default(true),
|
|
229
|
+
audioSampleRate: z.number().int().min(8000).max(48000).optional().default(12000),
|
|
230
|
+
});
|
|
231
|
+
|
|
195
232
|
/**
|
|
196
233
|
* 串口连接配置Schema
|
|
197
234
|
*/
|
|
198
235
|
export const SerialConnectionConfigSchema = z.object({
|
|
199
236
|
path: z.string(),
|
|
237
|
+
serialNumber: z.string().optional(),
|
|
200
238
|
rigModel: z.number().int(),
|
|
201
239
|
serialConfig: SerialConfigSchema.optional(),
|
|
202
240
|
backendConfig: HamlibBackendConfigSchema.optional(),
|
|
@@ -206,6 +244,15 @@ export const HamlibSpectrumConfigSchema = z.object({
|
|
|
206
244
|
speed: z.number().int().min(0).max(255).optional(),
|
|
207
245
|
});
|
|
208
246
|
|
|
247
|
+
/**
|
|
248
|
+
* FT8/FT4 数字模式切换频率时的电台 CAT 模式偏好。
|
|
249
|
+
*
|
|
250
|
+
* - none: 只切换频率,不主动设置电台模式
|
|
251
|
+
* - usb: 设置普通 USB
|
|
252
|
+
* - usb-data: 设置 USB-DATA / PKTUSB 类数据模式
|
|
253
|
+
*/
|
|
254
|
+
export const DigitalModeRadioModePreferenceSchema = z.enum(['none', 'usb', 'usb-data']);
|
|
255
|
+
|
|
209
256
|
/**
|
|
210
257
|
* PTT (Push-to-Talk) 方法Schema
|
|
211
258
|
*
|
|
@@ -216,6 +263,15 @@ export const HamlibSpectrumConfigSchema = z.object({
|
|
|
216
263
|
*/
|
|
217
264
|
export const PttMethodSchema = z.enum(['cat', 'vox', 'dtr', 'rts']);
|
|
218
265
|
|
|
266
|
+
/**
|
|
267
|
+
* 虚拟频差(Virtual Frequency Offset / "Fake It" Split)配置Schema
|
|
268
|
+
* 目标音频频率与滞回区间目前由服务端常量控制(~1500Hz),此处仅暴露开关,预留扩展位。
|
|
269
|
+
*/
|
|
270
|
+
export const FakeFrequencyConfigSchema = z.object({
|
|
271
|
+
enabled: z.boolean(),
|
|
272
|
+
});
|
|
273
|
+
export type FakeFrequencyConfig = z.infer<typeof FakeFrequencyConfigSchema>;
|
|
274
|
+
|
|
219
275
|
/**
|
|
220
276
|
* Hamlib配置Schema - 嵌套对象结构
|
|
221
277
|
*
|
|
@@ -226,7 +282,7 @@ export const PttMethodSchema = z.enum(['cat', 'vox', 'dtr', 'rts']);
|
|
|
226
282
|
* - 根据 type 字段读取对应的配置对象
|
|
227
283
|
*/
|
|
228
284
|
export const HamlibConfigSchema = z.object({
|
|
229
|
-
type: z.enum(['none', 'network', 'serial', 'icom-wlan']),
|
|
285
|
+
type: z.enum(['none', 'network', 'serial', 'icom-wlan', 'tci']),
|
|
230
286
|
|
|
231
287
|
// 网络模式配置
|
|
232
288
|
network: NetworkConfigSchema.optional(),
|
|
@@ -234,17 +290,29 @@ export const HamlibConfigSchema = z.object({
|
|
|
234
290
|
// ICOM WLAN 模式配置
|
|
235
291
|
icomWlan: IcomWlanConfigSchema.optional(),
|
|
236
292
|
|
|
293
|
+
// TCI / SunSDR 模式配置
|
|
294
|
+
tci: TciConfigSchema.optional(),
|
|
295
|
+
|
|
237
296
|
// 串口模式配置
|
|
238
297
|
serial: SerialConnectionConfigSchema.optional(),
|
|
239
298
|
|
|
240
299
|
// Hamlib 频谱配置(当前仅用于官方频谱流 speed)
|
|
241
300
|
spectrum: HamlibSpectrumConfigSchema.optional(),
|
|
242
301
|
|
|
302
|
+
// FT8/FT4 切换频率时是否主动设置电台 CAT 模式;未设置时按 none 处理
|
|
303
|
+
digitalModeRadioMode: DigitalModeRadioModePreferenceSchema.optional(),
|
|
304
|
+
|
|
243
305
|
// 发射时序补偿(毫秒)- 用于补偿电台和网络的处理延迟
|
|
244
306
|
// 正值表示提前发射,负值表示延后发射
|
|
245
307
|
// 范围限制:-1000~1000ms,适用于各种网络和设备延迟场景
|
|
246
308
|
transmitCompensationMs: z.number().int().min(-1000).max(1000).optional(),
|
|
247
309
|
|
|
310
|
+
// 虚拟频差(Virtual Frequency Offset / WSJT-X "Fake It" Split)
|
|
311
|
+
// 启用后,发射时临时反向平移电台 dial 频率,使送进电台的音频载波保持在甜区(~1500Hz),
|
|
312
|
+
// 而打到空中的实际 RF 位置与用户设定的发射频点完全一致。
|
|
313
|
+
// 用于规避部分电台在音频频率过高/过低时发射功率衰减的问题;对用户透明(接收 dial、TX 标记不变)。
|
|
314
|
+
fakeFrequency: FakeFrequencyConfigSchema.optional(),
|
|
315
|
+
|
|
248
316
|
// PTT 方法(默认 'cat',即 Hamlib RIG 类型)
|
|
249
317
|
// 仅对 network 和 serial 连接类型有效,icom-wlan 固定使用 CI-V PTT
|
|
250
318
|
pttMethod: PttMethodSchema.optional(),
|
|
@@ -258,6 +326,9 @@ export const HamlibConfigSchema = z.object({
|
|
|
258
326
|
|
|
259
327
|
// CW 键控引脚类型(dtr 或 rts)
|
|
260
328
|
cwKeyMethod: z.enum(['dtr', 'rts']).optional(),
|
|
329
|
+
|
|
330
|
+
// CW 键控有效电平(默认 high,即高电平按下;部分接口为低电平按下)
|
|
331
|
+
cwKeyActiveLevel: CWKeyActiveLevelSchema.optional(),
|
|
261
332
|
});
|
|
262
333
|
|
|
263
334
|
/**
|
|
@@ -303,7 +374,7 @@ export const RadioInfoSchema = z.object({
|
|
|
303
374
|
/** Hamlib 电台型号 ID (serial/network 模式使用,icom-wlan 模式可选) */
|
|
304
375
|
rigModel: z.number().optional(),
|
|
305
376
|
/** 连接类型 */
|
|
306
|
-
connectionType: z.enum(['serial', 'network', 'icom-wlan']),
|
|
377
|
+
connectionType: z.enum(['serial', 'network', 'icom-wlan', 'tci']),
|
|
307
378
|
/** 固件版本 (如果可获取) */
|
|
308
379
|
firmwareVersion: z.string().optional(),
|
|
309
380
|
/** 序列号 (如果可获取) */
|
|
@@ -315,6 +386,7 @@ export const RadioInfoSchema = z.object({
|
|
|
315
386
|
*/
|
|
316
387
|
export const SerialPortSchema = z.object({
|
|
317
388
|
path: z.string(),
|
|
389
|
+
friendlyName: z.string().optional(),
|
|
318
390
|
manufacturer: z.string().optional(),
|
|
319
391
|
serialNumber: z.string().optional(),
|
|
320
392
|
pnpId: z.string().optional(),
|
|
@@ -336,6 +408,7 @@ export const SerialPortsResponseSchema = z.object({
|
|
|
336
408
|
export const TestResponseSchema = z.object({
|
|
337
409
|
success: z.boolean(),
|
|
338
410
|
message: z.string().optional(),
|
|
411
|
+
details: z.record(z.unknown()).optional(),
|
|
339
412
|
});
|
|
340
413
|
|
|
341
414
|
/**
|
|
@@ -449,6 +522,14 @@ export const CustomFrequencyPresetsSchema = z.object({
|
|
|
449
522
|
presets: z.array(PresetFrequencySchema).min(1),
|
|
450
523
|
});
|
|
451
524
|
|
|
525
|
+
/** TCI receiver DDS/IQ center-frequency control request. */
|
|
526
|
+
export const DdsFrequencyRequestSchema = z.object({
|
|
527
|
+
frequency: z.number().finite().nonnegative(),
|
|
528
|
+
receiver: z.number().int().nonnegative().optional(),
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
export type DdsFrequencyRequest = z.infer<typeof DdsFrequencyRequestSchema>;
|
|
532
|
+
|
|
452
533
|
// 导出类型
|
|
453
534
|
export type CustomFrequencyPresets = z.infer<typeof CustomFrequencyPresetsSchema>;
|
|
454
535
|
export type PresetFrequency = z.infer<typeof PresetFrequencySchema>;
|
|
@@ -461,8 +542,10 @@ export type HamlibConfigFieldType = z.infer<typeof HamlibConfigFieldTypeSchema>;
|
|
|
461
542
|
export type HamlibConfigField = z.infer<typeof HamlibConfigFieldSchema>;
|
|
462
543
|
export type NetworkConfig = z.infer<typeof NetworkConfigSchema>;
|
|
463
544
|
export type IcomWlanConfig = z.infer<typeof IcomWlanConfigSchema>;
|
|
545
|
+
export type TciConfig = z.infer<typeof TciConfigSchema>;
|
|
464
546
|
export type SerialConnectionConfig = z.infer<typeof SerialConnectionConfigSchema>;
|
|
465
547
|
export type HamlibSpectrumConfig = z.infer<typeof HamlibSpectrumConfigSchema>;
|
|
548
|
+
export type DigitalModeRadioModePreference = z.infer<typeof DigitalModeRadioModePreferenceSchema>;
|
|
466
549
|
export type PttMethod = z.infer<typeof PttMethodSchema>;
|
|
467
550
|
export type HamlibConfig = z.infer<typeof HamlibConfigSchema>;
|
|
468
551
|
export type RadioConfigResponse = z.infer<typeof RadioConfigResponseSchema>;
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
export const RealtimeScopeSchema = z.enum(['radio', 'openwebrx-preview']);
|
|
4
4
|
export type RealtimeScope = z.infer<typeof RealtimeScopeSchema>;
|
|
5
5
|
|
|
6
|
-
export const RealtimeTransportKindSchema = z.enum(['rtc-data-audio', 'ws-compat']);
|
|
6
|
+
export const RealtimeTransportKindSchema = z.enum(['rtc-data-audio', 'ws-compat', 'android-native']);
|
|
7
7
|
export type RealtimeTransportKind = z.infer<typeof RealtimeTransportKindSchema>;
|
|
8
8
|
|
|
9
9
|
export const RealtimeSessionDirectionSchema = z.enum(['recv', 'send']);
|
|
@@ -307,6 +307,13 @@ export const RealtimeSessionResponseSchema = z.object({
|
|
|
307
307
|
|
|
308
308
|
export type RealtimeSessionResponse = z.infer<typeof RealtimeSessionResponseSchema>;
|
|
309
309
|
|
|
310
|
+
/**
|
|
311
|
+
* Persisted realtime-audio transport preferences.
|
|
312
|
+
*
|
|
313
|
+
* `transportPolicy` selects automatic or explicit transport behavior. The
|
|
314
|
+
* optional public host/UDP port advertise an RTC data-audio endpoint to remote
|
|
315
|
+
* clients; null/omitted values disable that public candidate.
|
|
316
|
+
*/
|
|
310
317
|
export const RealtimeSettingsSchema = z.object({
|
|
311
318
|
transportPolicy: RealtimeTransportPolicySchema.optional(),
|
|
312
319
|
rtcDataAudioPublicHost: RtcDataAudioPublicHostSchema.optional(),
|
|
@@ -333,6 +340,7 @@ export const RealtimeSettingsRuntimeSchema = z.object({
|
|
|
333
340
|
|
|
334
341
|
export type RealtimeSettingsRuntime = z.infer<typeof RealtimeSettingsRuntimeSchema>;
|
|
335
342
|
|
|
343
|
+
/** Realtime settings plus the Host's current resolved runtime projection. */
|
|
336
344
|
export const RealtimeSettingsResponseDataSchema = RealtimeSettingsSchema.extend({
|
|
337
345
|
runtime: RealtimeSettingsRuntimeSchema.optional(),
|
|
338
346
|
});
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DxccStatusSchema, SubdivisionConfidenceSchema } from './qso.schema.js';
|
|
3
3
|
|
|
4
|
+
/** Number of non-empty slot packs retained for live FT8/FT4 message history. */
|
|
5
|
+
export const SLOT_PACK_HISTORY_LIMIT = 1000;
|
|
6
|
+
|
|
4
7
|
/**
|
|
5
8
|
* Frequency context captured when a slot pack is created.
|
|
6
9
|
* Fields are optional so older persisted slot packs remain valid.
|
|
@@ -16,11 +19,12 @@ export const SlotPackFrequencyContextSchema = z.object({
|
|
|
16
19
|
export type SlotPackFrequencyContext = z.infer<typeof SlotPackFrequencyContextSchema>;
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
22
|
+
* Timing and identity of one FT8/FT4 receive or transmit slot.
|
|
23
|
+
*
|
|
24
|
+
* `startMs` is the calibrated Unix epoch start in milliseconds; `phaseMs` is
|
|
25
|
+
* elapsed time inside the slot; `driftMs` is the clock correction; `cycleNumber`
|
|
26
|
+
* is the absolute slot index (use modulo two for even/odd); and `utcSeconds` is
|
|
27
|
+
* the integer epoch-second form used for display and logs.
|
|
24
28
|
*/
|
|
25
29
|
export const SlotInfoSchema = z.object({
|
|
26
30
|
/** 时隙唯一标识符 */
|
|
@@ -41,9 +45,7 @@ export const SlotInfoSchema = z.object({
|
|
|
41
45
|
|
|
42
46
|
export type SlotInfo = z.infer<typeof SlotInfoSchema>;
|
|
43
47
|
|
|
44
|
-
/**
|
|
45
|
-
* 基于日志本的消息分析结果
|
|
46
|
-
*/
|
|
48
|
+
/** Logbook-derived enrichment attached to a decoded message when available. */
|
|
47
49
|
export const LogbookAnalysisSchema = z.object({
|
|
48
50
|
/** 是否为新呼号(之前没有通联过) */
|
|
49
51
|
isNewCallsign: z.boolean().optional(),
|
|
@@ -76,7 +78,9 @@ export const LogbookAnalysisSchema = z.object({
|
|
|
76
78
|
export type LogbookAnalysis = z.infer<typeof LogbookAnalysisSchema>;
|
|
77
79
|
|
|
78
80
|
/**
|
|
79
|
-
*
|
|
81
|
+
* Original decoder frame with RF metrics and unparsed message text.
|
|
82
|
+
* `snr` is dB, `freq` is audio offset in hertz, `dt` is seconds, and
|
|
83
|
+
* `confidence` is normalized to 0..1.
|
|
80
84
|
*/
|
|
81
85
|
export const FrameMessageSchema = z.object({
|
|
82
86
|
/** 信号强度 (dB) */
|
|
@@ -92,7 +96,8 @@ export const FrameMessageSchema = z.object({
|
|
|
92
96
|
/** 基于日志本的分析结果(可选,仅在客户端定制化数据中提供) */
|
|
93
97
|
logbookAnalysis: LogbookAnalysisSchema.optional(),
|
|
94
98
|
/** 操作员ID(可选,仅 TX 帧使用,用于多操作员覆盖识别) */
|
|
95
|
-
operatorId: z.string().optional()
|
|
99
|
+
operatorId: z.string().optional(),
|
|
100
|
+
streamId: z.string().optional(),
|
|
96
101
|
});
|
|
97
102
|
|
|
98
103
|
export type FrameMessage = z.infer<typeof FrameMessageSchema>;
|
|
@@ -157,7 +162,9 @@ export const DecodeResultSchema = z.object({
|
|
|
157
162
|
export type DecodeResult = z.infer<typeof DecodeResultSchema>;
|
|
158
163
|
|
|
159
164
|
/**
|
|
160
|
-
*
|
|
165
|
+
* Deduplicated best-frame collection for one slot, including decode statistics,
|
|
166
|
+
* history and the dial-frequency context captured when the slot began.
|
|
167
|
+
* `startMs`, `endMs` and history timestamps use Unix epoch milliseconds.
|
|
161
168
|
*/
|
|
162
169
|
export const SlotPackSchema = z.object({
|
|
163
170
|
/** 时隙ID */
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const SpectrumPresetIdSchema = z.enum(['responsive', 'balanced', 'fine']);
|
|
4
|
+
export const SpectrumPresetSchema = z.enum(['responsive', 'balanced', 'fine', 'custom']);
|
|
5
|
+
export type SpectrumPreset = z.infer<typeof SpectrumPresetSchema>;
|
|
6
|
+
export type SpectrumPresetId = z.infer<typeof SpectrumPresetIdSchema>;
|
|
7
|
+
|
|
8
|
+
export const SpectrumWindowFunctionSchema = z.enum([
|
|
9
|
+
'hann',
|
|
10
|
+
'hamming',
|
|
11
|
+
'blackman',
|
|
12
|
+
'blackmanHarris',
|
|
13
|
+
'none',
|
|
14
|
+
]);
|
|
15
|
+
export type SpectrumWindowFunction = z.infer<typeof SpectrumWindowFunctionSchema>;
|
|
16
|
+
|
|
17
|
+
export const SpectrumFftSizeSchema = z.union([
|
|
18
|
+
z.literal(1024),
|
|
19
|
+
z.literal(2048),
|
|
20
|
+
z.literal(4096),
|
|
21
|
+
z.literal(8192),
|
|
22
|
+
z.literal(16384),
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export const SpectrumTargetSampleRateSchema = z.union([
|
|
26
|
+
z.literal(3000),
|
|
27
|
+
z.literal(4000),
|
|
28
|
+
z.literal(6000),
|
|
29
|
+
z.literal(8000),
|
|
30
|
+
z.literal(12000),
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export const SpectrumCustomSettingsSchema = z.object({
|
|
34
|
+
analysisIntervalMs: z.number().int().min(50).max(1000),
|
|
35
|
+
fftSize: SpectrumFftSizeSchema,
|
|
36
|
+
targetSampleRate: SpectrumTargetSampleRateSchema,
|
|
37
|
+
windowFunction: SpectrumWindowFunctionSchema,
|
|
38
|
+
haloReduce: z.boolean(),
|
|
39
|
+
});
|
|
40
|
+
export type SpectrumCustomSettings = z.infer<typeof SpectrumCustomSettingsSchema>;
|
|
41
|
+
|
|
42
|
+
export const SpectrumRenderFrequencyRangeSchema = z.object({
|
|
43
|
+
min: z.number().finite(),
|
|
44
|
+
max: z.number().finite(),
|
|
45
|
+
}).refine((range) => range.max > range.min, {
|
|
46
|
+
message: 'Spectrum frequency range maximum must be greater than minimum',
|
|
47
|
+
path: ['max'],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const SpectrumRenderConfigSchema = z.object({
|
|
51
|
+
preset: SpectrumPresetSchema,
|
|
52
|
+
revision: z.number().int().nonnegative(),
|
|
53
|
+
analysisIntervalMs: z.number().int().positive(),
|
|
54
|
+
frameRateHz: z.number().positive(),
|
|
55
|
+
fftSize: z.number().int().positive(),
|
|
56
|
+
targetSampleRate: z.number().int().positive(),
|
|
57
|
+
fftWindowDurationMs: z.number().positive(),
|
|
58
|
+
frequencyResolutionHz: z.number().positive(),
|
|
59
|
+
frequencyRange: SpectrumRenderFrequencyRangeSchema,
|
|
60
|
+
displayBinCount: z.number().int().positive(),
|
|
61
|
+
windowFunction: SpectrumWindowFunctionSchema,
|
|
62
|
+
haloReduce: z.boolean(),
|
|
63
|
+
customSettings: SpectrumCustomSettingsSchema.optional(),
|
|
64
|
+
});
|
|
65
|
+
export type SpectrumRenderConfig = z.infer<typeof SpectrumRenderConfigSchema>;
|
|
66
|
+
|
|
67
|
+
export const TciIqSampleRateSchema = z.number().int().positive();
|
|
68
|
+
export type TciIqSampleRate = z.infer<typeof TciIqSampleRateSchema>;
|
|
69
|
+
|
|
70
|
+
export const TciSpectrumSettingsSchema = z.object({
|
|
71
|
+
fftSize: z.union([
|
|
72
|
+
z.literal(4096), z.literal(8192), z.literal(16384), z.literal(32768), z.literal(65536),
|
|
73
|
+
]),
|
|
74
|
+
displayBinCount: z.number().int().min(1024).max(16384),
|
|
75
|
+
analysisIntervalMs: z.number().int().min(20).max(1000),
|
|
76
|
+
});
|
|
77
|
+
export type TciSpectrumSettings = z.infer<typeof TciSpectrumSettingsSchema>;
|
|
78
|
+
|
|
79
|
+
export const TciSpectrumSettingsResponseSchema = z.object({
|
|
80
|
+
success: z.boolean(),
|
|
81
|
+
settings: TciSpectrumSettingsSchema,
|
|
82
|
+
});
|
|
83
|
+
export type TciSpectrumSettingsResponse = z.infer<typeof TciSpectrumSettingsResponseSchema>;
|
|
84
|
+
|
|
85
|
+
export const TciIqSpectrumSettingsResponseSchema = z.object({
|
|
86
|
+
success: z.boolean(),
|
|
87
|
+
configuredSampleRate: TciIqSampleRateSchema.nullable(),
|
|
88
|
+
appliedSampleRate: TciIqSampleRateSchema.nullable(),
|
|
89
|
+
supportedSampleRates: z.array(TciIqSampleRateSchema),
|
|
90
|
+
});
|
|
91
|
+
export type TciIqSpectrumSettingsResponse = z.infer<typeof TciIqSpectrumSettingsResponseSchema>;
|
|
92
|
+
|
|
93
|
+
export const SpectrumPresetDefinitionSchema = SpectrumRenderConfigSchema.omit({
|
|
94
|
+
revision: true,
|
|
95
|
+
});
|
|
96
|
+
export type SpectrumPresetDefinition = z.infer<typeof SpectrumPresetDefinitionSchema>;
|
|
97
|
+
|
|
98
|
+
export const SPECTRUM_PRESET_DEFINITIONS: Record<SpectrumPresetId, SpectrumPresetDefinition> = {
|
|
99
|
+
responsive: {
|
|
100
|
+
preset: 'responsive',
|
|
101
|
+
analysisIntervalMs: 100,
|
|
102
|
+
frameRateHz: 10,
|
|
103
|
+
fftSize: 2048,
|
|
104
|
+
targetSampleRate: 6000,
|
|
105
|
+
fftWindowDurationMs: (2048 / 6000) * 1000,
|
|
106
|
+
frequencyResolutionHz: 6000 / 2048,
|
|
107
|
+
frequencyRange: { min: 0, max: 3000 },
|
|
108
|
+
displayBinCount: 1025,
|
|
109
|
+
windowFunction: 'blackmanHarris',
|
|
110
|
+
haloReduce: false,
|
|
111
|
+
},
|
|
112
|
+
balanced: {
|
|
113
|
+
preset: 'balanced',
|
|
114
|
+
analysisIntervalMs: 150,
|
|
115
|
+
frameRateHz: 1000 / 150,
|
|
116
|
+
fftSize: 8192,
|
|
117
|
+
targetSampleRate: 6000,
|
|
118
|
+
fftWindowDurationMs: (8192 / 6000) * 1000,
|
|
119
|
+
frequencyResolutionHz: 6000 / 8192,
|
|
120
|
+
frequencyRange: { min: 0, max: 3000 },
|
|
121
|
+
displayBinCount: 4097,
|
|
122
|
+
windowFunction: 'blackmanHarris',
|
|
123
|
+
haloReduce: false,
|
|
124
|
+
},
|
|
125
|
+
fine: {
|
|
126
|
+
preset: 'fine',
|
|
127
|
+
analysisIntervalMs: 200,
|
|
128
|
+
frameRateHz: 5,
|
|
129
|
+
fftSize: 16384,
|
|
130
|
+
targetSampleRate: 6000,
|
|
131
|
+
fftWindowDurationMs: (16384 / 6000) * 1000,
|
|
132
|
+
frequencyResolutionHz: 6000 / 16384,
|
|
133
|
+
frequencyRange: { min: 0, max: 3000 },
|
|
134
|
+
displayBinCount: 8193,
|
|
135
|
+
windowFunction: 'blackmanHarris',
|
|
136
|
+
haloReduce: false,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export function getSpectrumPresetDefinition(preset: SpectrumPresetId): SpectrumPresetDefinition {
|
|
141
|
+
return { ...SPECTRUM_PRESET_DEFINITIONS[preset] };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const SpectrumSettingsUpdateRequestSchema = z.discriminatedUnion('preset', [
|
|
145
|
+
z.object({ preset: SpectrumPresetIdSchema }),
|
|
146
|
+
z.object({ preset: z.literal('custom'), settings: SpectrumCustomSettingsSchema }),
|
|
147
|
+
]);
|
|
148
|
+
export type SpectrumSettingsUpdateRequest = z.infer<typeof SpectrumSettingsUpdateRequestSchema>;
|
|
149
|
+
|
|
150
|
+
export const SpectrumSettingsResponseSchema = z.object({
|
|
151
|
+
success: z.boolean(),
|
|
152
|
+
message: z.string().optional(),
|
|
153
|
+
currentSettings: SpectrumRenderConfigSchema,
|
|
154
|
+
presets: z.array(SpectrumPresetDefinitionSchema),
|
|
155
|
+
});
|
|
156
|
+
export type SpectrumSettingsResponse = z.infer<typeof SpectrumSettingsResponseSchema>;
|