import { z } from 'zod'; import { LogbookAnalysisSchema } from './slot-info.schema.js'; // FT8解码帧信息(基于wsjtx-lib的数据类型) export const FT8DecodeSchema = z.object({ // 时间戳 timestamp: z.number(), // 信噪比 snr: z.number(), // 时间偏移(秒) dt: z.number(), // 频率偏移(Hz) df: z.number(), // 解码的消息文本 message: z.string(), // 是否为低置信度解码 lowConfidence: z.boolean().optional(), // 解码周期(15秒周期内的序号) cycle: z.number(), }); // FT8编码请求 export const FT8EncodeRequestSchema = z.object({ message: z.string(), frequency: z.number().optional(), // 发射功率(dBm) power: z.number().optional(), }); // FT8编码响应 export const FT8EncodeResponseSchema = z.object({ success: z.boolean(), audioData: z.array(z.number()).optional(), duration: z.number().optional(), error: z.string().optional(), }); // FT8解码帧列表响应 export const FT8DecodesResponseSchema = z.object({ decodes: z.array(FT8DecodeSchema), cycle: z.number(), timestamp: z.number(), }); // FT8频谱数据 export const FT8SpectrumSchema = z.object({ // 时间戳 timestamp: z.number(), // 采样率 sampleRate: z.number(), // 频率范围 frequencyRange: z.object({ min: z.number(), max: z.number(), }), // 二进制频谱数据 binaryData: z.object({ // 二进制数据,使用base64编码 data: z.string(), // 数据格式描述 format: z.object({ type: z.literal('int16'), // 数据点数量 length: z.number(), // 缩放因子(可选) scale: z.number().optional(), // 偏移量(可选) offset: z.number().optional(), }), }), // 频谱数据摘要 summary: z.object({ // 峰值频率(Hz) peakFrequency: z.number(), // 峰值幅度(dB) peakMagnitude: z.number(), // 平均幅度(dB) averageMagnitude: z.number(), // 动态范围(dB) dynamicRange: z.number(), // 能量分布(可选) energyDistribution: z.array(z.number()).optional(), }).optional(), }); // FT8频谱响应 export const FT8SpectrumResponseSchema = z.object({ spectrum: FT8SpectrumSchema, }); // FT8发射控制请求 export const FT8TransmitRequestSchema = z.object({ message: z.string(), frequency: z.number(), // 是否立即发射 immediate: z.boolean().optional(), // 发射周期(如果不是立即发射) cycle: z.number().optional(), }); // FT8发射控制响应 export const FT8TransmitResponseSchema = z.object({ success: z.boolean(), message: z.string().optional(), scheduledCycle: z.number().optional(), }); /** * Canonical FT8 message kind identifiers used by the parser. * * These values describe the semantic role of a decoded message after TX-5DR has * normalized the raw free-text payload into structured FT8/QSO stages. */ export const FT8MessageType = { CQ: 'cq', // CQ呼叫 CALL: 'call', // 响应呼叫 SIGNAL_REPORT: 'signal_report',// 信号报告 ROGER_REPORT: 'roger_report', // 确认信号报告 RRR: 'rrr', // RRR确认 SEVENTY_THREE: '73', // 73告别 FOX_RR73: 'fox_rr73', // Fox/Hound DXpedition模式:Fox确认完成并邀请下一个Hound CUSTOM: 'custom', // 自定义消息 UNKNOWN: 'unknown', // 未知消息类型 } as const; /** * Zod schema for {@link FT8MessageType} values. */ export const FT8MessageTypeSchema = z.enum([ FT8MessageType.CQ, FT8MessageType.CALL, FT8MessageType.SIGNAL_REPORT, FT8MessageType.ROGER_REPORT, FT8MessageType.RRR, FT8MessageType.SEVENTY_THREE, FT8MessageType.FOX_RR73, FT8MessageType.CUSTOM, FT8MessageType.UNKNOWN, ]); /** * Base shape shared by every structured FT8 message. * * Use this when code only needs to discriminate on the message `type` without * caring about the rest of the payload. */ export const FT8MessageBaseSchema = z.object({ type: FT8MessageTypeSchema, }); /** * Structured representation of a CQ message. * * This is typically the main entry point for automation plugins that scan the * band for new targets to answer. */ export const FT8MessageCQSchema = FT8MessageBaseSchema.extend({ type: z.literal('cq'), senderCallsign: z.string(), // Reuses the legacy field name for compatibility. The value can be a // directed-CQ modifier such as DX/EU/JA or a callback token such as 290. flag: z.string().optional(), grid: z.string().optional(), }); /** * Structured representation of a directed call message. * * This covers "A B" style messages where one station calls or answers a * specific target station, optionally including grid information. */ export const FT8MessageCallSchema = FT8MessageBaseSchema.extend({ type: z.literal('call'), senderCallsign: z.string(), targetCallsign: z.string(), grid: z.string().optional(), }); /** * Structured representation of a signal report message. * * This usually corresponds to the report-exchange phase of a normal FT8 QSO. */ export const FT8MessageSignalReportSchema = FT8MessageBaseSchema.extend({ type: z.literal('signal_report'), senderCallsign: z.string(), targetCallsign: z.string(), report: z.number(), }); /** * Structured representation of an RR73-style "roger + report" message. * * In standard FT8 flow this acknowledges the received report while also * carrying the sender's report for the other station. */ export const FT8MessageRogerReportSchema = FT8MessageBaseSchema.extend({ type: z.literal('roger_report'), senderCallsign: z.string(), targetCallsign: z.string(), report: z.number(), }); /** * Structured representation of an `RRR` confirmation message. * * This indicates the sender considers the report exchange complete. */ export const FT8MessageRRRSchema = FT8MessageBaseSchema.extend({ type: z.literal('rrr'), senderCallsign: z.string(), targetCallsign: z.string(), }); /** * Structured representation of a final `73` closing message. * * This is typically the terminal stage of a completed FT8 QSO. */ export const FT8MessageSeventyThreeSchema = FT8MessageBaseSchema.extend({ type: z.literal('73'), senderCallsign: z.string(), targetCallsign: z.string(), }); /** * Structured representation of a Fox/Hound `RR73` completion message. * * This variant appears in DXpedition workflows where the Fox acknowledges one * completed Hound and may invite the next one in the same frame. */ export const FT8MessageFoxRR73Schema = FT8MessageBaseSchema.extend({ type: z.literal('fox_rr73'), senderCallsign: z.string().optional(), // 可解析时填入真实 Fox 呼号;仅短哈希时留空 completedCallsign: z.string(), // 已完成QSO的Hound呼号 nextCallsign: z.string(), // 下一个被邀请的Hound呼号 foxHash: z.string().optional(), // Fox的哈希码(去掉尖括号后的值) snrForNext: z.number().optional(), // Fox告知下一个Hound的信号强度(如+04→4) }); /** * Structured representation of a decoder-recognized message whose free-text * payload is intentionally left uninterpreted. */ export const FT8MessageCustomSchema = FT8MessageBaseSchema.extend({ type: z.literal('custom'), }); /** * Fallback structured representation for a decoded message that the parser * could not confidently classify. */ export const FT8MessageUnknownSchema = FT8MessageBaseSchema.extend({ type: z.literal('unknown'), }); /** * Discriminated union of every structured FT8 message variant understood by * TX-5DR. */ export const FT8MessageSchema = z.discriminatedUnion('type', [ FT8MessageCQSchema, FT8MessageCallSchema, FT8MessageSignalReportSchema, FT8MessageRogerReportSchema, FT8MessageRRRSchema, FT8MessageSeventyThreeSchema, FT8MessageFoxRR73Schema, FT8MessageCustomSchema, FT8MessageUnknownSchema, ]); /** * Fully parsed decode entry used by selection, filtering and automation logic. * * This is the main plugin-facing FT8 payload. It combines RF metrics from the * decoder (`snr`, `dt`, `df`), the original unparsed text (`rawMessage`), the * normalized semantic form (`message`) and optional logbook enrichment. */ export const ParsedFT8MessageSchema = z.object({ snr: z.number(), dt: z.number(), df: z.number(), rawMessage: z.string(), message: FT8MessageSchema, slotId: z.string(), timestamp: z.number(), logbookAnalysis: LogbookAnalysisSchema.optional(), }); export type FT8Decode = z.infer; export type FT8EncodeRequest = z.infer; export type FT8EncodeResponse = z.infer; export type FT8DecodesResponse = z.infer; export type FT8Spectrum = z.infer; export type FT8SpectrumResponse = z.infer; export type FT8TransmitRequest = z.infer; export type FT8TransmitResponse = z.infer; /** * Base FT8 message type containing only the discriminant field. */ export type FT8MessageBase = z.infer; /** * Structured CQ message with sender identity and optional grid/modifier metadata. */ export type FT8MessageCQ = z.infer; /** * Structured directed-call message between a sender and a target station. */ export type FT8MessageCall = z.infer; /** * Structured signal-report exchange message carrying a numeric report. */ export type FT8MessageSignalReport = z.infer; /** * Structured "roger + report" exchange message. */ export type FT8MessageRogerReport = z.infer; /** * Structured `RRR` completion/acknowledgement message. */ export type FT8MessageRRR = z.infer; /** * Structured final `73` closing message. */ export type FT8MessageSeventyThree = z.infer; /** * Structured Fox/Hound `RR73` completion-and-invite message. */ export type FT8MessageFoxRR73 = z.infer; /** * Structured custom FT8 message whose payload is intentionally not further * parsed by the core parser. */ export type FT8MessageCustom = z.infer; /** * Structured fallback FT8 message for unclassified decoder output. */ export type FT8MessageUnknown = z.infer; /** * Union of every structured FT8 message variant recognized by TX-5DR. */ export type FT8Message = z.infer; /** * Primary plugin-facing FT8 decode model. * * Prefer this type when filtering targets, scoring candidates or reacting to * decoded traffic in plugin hooks. */ export type ParsedFT8Message = z.infer;