mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
- Remove manual "Mic Source" (Radio/SoundCard) setting from UI and storage; source is now determined automatically in ApplyMOX: HW PTT → txmsRadio, MOX button/CAT → txmsSoundCard if audio device configured, else txmsRadio - Replace "Line in" checkbox with "Mic jack" combo (Mic In / Line In); when Line In is selected, Mic Boost is hidden and Line In Gain (-34.5..+12 dB, step 1.5 dB) is shown and sent as DUC Specific byte 51 - Add Tip/Ring connector selector (Orion/OrionMkII boards 4/5 only, byte 50 bit 3); control is hidden for other board types - Fix byte 50 bit 1 (Mic Boost) suppressed when Line In is active - Fix byte 51 comment polarity (was reversed: 0=+12dB; correct: 0=-34.5dB) - New JSON fields: mic_line_in, mic_tip_ring, line_in_gain_db; mic_source removed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
493 lines
20 KiB
ObjectPascal
493 lines
20 KiB
ObjectPascal
unit HPSDRProtocol;
|
|
|
|
{
|
|
openHPSDR Ethernet Protocol V4.3 constants and packet structures.
|
|
Big-Endian (Network Byte Order) unless otherwise noted.
|
|
}
|
|
|
|
{$IFDEF FPC}
|
|
{$MODE Delphi}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// UDP Ports (defaults)
|
|
// ---------------------------------------------------------------------------
|
|
const
|
|
PORT_COMMAND = 1024; // Discovery, Erase, Program, Set IP
|
|
PORT_DDC_SPECIFIC = 1025; // DDC Specific packet (PC -> HW)
|
|
PORT_DUC_SPECIFIC = 1026; // DUC/TXA Specific packet (PC -> HW)
|
|
PORT_HP_FROM_PC = 1027; // High Priority from PC
|
|
PORT_HP_TO_PC = 1025; // High Priority Status from HW
|
|
PORT_DDC_AUDIO = 1028; // DDC Audio (PC -> HW)
|
|
PORT_DUC_IQ = 1029; // DUC I&Q data (PC -> HW)
|
|
PORT_MIC_DATA = 1026; // Microphone data (HW -> PC)
|
|
PORT_WIDEBAND_ADC0 = 1027; // Wideband data (HW -> PC)
|
|
PORT_DDC0_IQ = 1035; // DDC0 I&Q (HW -> PC), DDC1=1036 etc.
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Command bytes (Byte 4 of packet)
|
|
// ---------------------------------------------------------------------------
|
|
CMD_GENERAL = $00;
|
|
CMD_DISCOVERY = $02;
|
|
CMD_SET_IP = $03;
|
|
CMD_ERASE = $04;
|
|
CMD_PROGRAM = $05;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Discovery Reply Byte 4
|
|
// ---------------------------------------------------------------------------
|
|
REPLY_DISCOVERY_FREE = $02; // Hardware available
|
|
REPLY_DISCOVERY_INUSE = $03; // Hardware in use by another host
|
|
REPLY_XML_DESC = $FE; // XML hardware description follows
|
|
REPLY_FULL_DESC = $FF; // Full hardware description follows
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Board types (Discovery Reply Byte 11)
|
|
// ---------------------------------------------------------------------------
|
|
BOARD_ATLAS = 0;
|
|
BOARD_HERMES = 1; // ANAN-10, 100
|
|
BOARD_HERMES_10E = 2; // ANAN-10E, 100B
|
|
BOARD_ANGELA = 3; // ANAN-100D
|
|
BOARD_ORION = 4; // ANAN-200D
|
|
BOARD_ORION_MK2 = 5; // ANAN-7/8000DLE
|
|
BOARD_HERMES_LITE = 6;
|
|
BOARD_SATURN = 10; // ANAN-G2
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Packet sizes
|
|
// ---------------------------------------------------------------------------
|
|
DISCOVERY_PACKET_SIZE = 60;
|
|
GENERAL_PACKET_SIZE = 60;
|
|
DDC_SPECIFIC_SIZE = 1444;
|
|
DUC_SPECIFIC_SIZE = 60;
|
|
HP_DATA_PC_SIZE = 1444;
|
|
HP_STATUS_HW_SIZE = 60;
|
|
DDC_AUDIO_SIZE = 260; // 4 hdr + 64*2*2
|
|
DUC_IQ_SIZE = 1444; // 4 hdr + 240*6
|
|
MIC_DATA_SIZE = 132; // 4 hdr + 64*2
|
|
DDC_IQ_SIZE = 1444; // 4 hdr + 12 info + 238*6
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DDC sample rates (ksps)
|
|
// ---------------------------------------------------------------------------
|
|
DDC_RATE_48 = 48;
|
|
DDC_RATE_96 = 96;
|
|
DDC_RATE_192 = 192;
|
|
DDC_RATE_384 = 384;
|
|
DDC_RATE_768 = 768;
|
|
DDC_RATE_1536 = 1536;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DSP clock (Hz)
|
|
// ---------------------------------------------------------------------------
|
|
DSP_CLOCK_HZ: Double = 122880000.0;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Maximum DDCs / ADCs
|
|
// ---------------------------------------------------------------------------
|
|
MAX_DDCS = 80;
|
|
MAX_ADCS = 8;
|
|
MAX_DUCS = 4;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// High Priority Byte 4 bits (PC -> HW)
|
|
// ---------------------------------------------------------------------------
|
|
HP_RUN = $01;
|
|
HP_PTT0 = $02;
|
|
HP_PTT1 = $04;
|
|
HP_PTT2 = $08;
|
|
HP_PTT3 = $10;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// High Priority Status Byte 4 bits (HW -> PC)
|
|
// ---------------------------------------------------------------------------
|
|
HPS_PTT = $01;
|
|
HPS_DOT = $02;
|
|
HPS_DASH = $04;
|
|
HPS_PLL_LOCKED = $10;
|
|
HPS_FIFO_EMPTY = $20;
|
|
HPS_FIFO_FULL = $40;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DUC Specific Byte 5 bits (CW options)
|
|
// ---------------------------------------------------------------------------
|
|
CW_EER = $01;
|
|
CW_MODE = $02;
|
|
CW_REVERSE_KEYS = $04;
|
|
CW_IAMBIC = $08;
|
|
CW_SIDETONE = $10;
|
|
CW_MODE_B = $20;
|
|
CW_STRICT_SPACING = $40;
|
|
CW_BREAK_IN = $80;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Packet record types
|
|
// ---------------------------------------------------------------------------
|
|
|
|
type
|
|
// Raw byte array for a generic 60-byte command packet
|
|
TRawPacket60 = array[0..59] of Byte;
|
|
TRawPacket1444 = array[0..1443] of Byte;
|
|
PRawPacket1444 = ^TRawPacket1444;
|
|
PRawPacket60 = ^TRawPacket60;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Discovery packet (PC -> HW)
|
|
// -------------------------------------------------------------------------
|
|
TDiscoveryPacket = packed record
|
|
SeqHi, SeqMidHi, SeqMidLo, SeqLo: Byte; // Bytes 0-3: always 0
|
|
Command: Byte; // Byte 4: CMD_DISCOVERY=$02
|
|
Zeros: array[5..59] of Byte; // Bytes 5-59: zero
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Discovery Reply (HW -> PC)
|
|
// -------------------------------------------------------------------------
|
|
TDiscoveryReply = packed record
|
|
SeqHi, SeqMidHi, SeqMidLo, SeqLo: Byte; // 0-3
|
|
Status: Byte; // 4: $02 free/$03 in use
|
|
MAC: array[0..5] of Byte; // 5-10
|
|
BoardType: Byte; // 11
|
|
ProtocolVersion: Byte; // 12
|
|
FirmwareVersion: Byte; // 13
|
|
Mercury0: Byte; // 14
|
|
Mercury1: Byte; // 15
|
|
Mercury2: Byte; // 16
|
|
Mercury3: Byte; // 17
|
|
PennyVersion: Byte; // 18
|
|
MetisVersion: Byte; // 19
|
|
NumDDCs: Byte; // 20
|
|
FreqOrPhase: Byte; // 21: 0=freq, 1=phase
|
|
EndianModes: Byte; // 22
|
|
BetaVersion: Byte; // 23
|
|
Reserved: array[24..59] of Byte;
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// General Packet (PC -> HW, port 1024)
|
|
// -------------------------------------------------------------------------
|
|
TGeneralPacket = packed record
|
|
Seq: array[0..3] of Byte; // 0-3
|
|
Command: Byte; // 4: CMD_GENERAL=$00
|
|
DDCSpecPort: array[0..1] of Byte; // 5-6: default 1025
|
|
DUCSpecPort: array[0..1] of Byte; // 7-8: default 1026
|
|
HPFromPCPort: array[0..1] of Byte; // 9-10: default 1027
|
|
HPToPCPort: array[0..1] of Byte; // 11-12: default 1025
|
|
DDCAudioPort: array[0..1] of Byte; // 13-14: default 1028
|
|
DUCIQPort: array[0..1] of Byte; // 15-16: default 1029
|
|
DDC0Port: array[0..1] of Byte; // 17-18: default 1035
|
|
MicPort: array[0..1] of Byte; // 19-20: default 1026
|
|
WBPort: array[0..1] of Byte; // 21-22: default 1027
|
|
WBEnable: Byte; // 23
|
|
WBSamplesPerPkt: array[0..1] of Byte; // 24-25: default 512
|
|
WBSampleSize: Byte; // 26: default 16
|
|
WBUpdateRate: Byte; // 27: 0-255ms
|
|
WBPacketsPerFrame: Byte; // 28: default 32
|
|
MemMapFromPCPort: array[0..1] of Byte; // 29-30
|
|
MemMapToPCPort: array[0..1] of Byte; // 31-32
|
|
EnvPWMMin: array[0..1] of Byte; // 33-34
|
|
EnvPWMMax: array[0..1] of Byte; // 35-36
|
|
Flags37: Byte; // 37: timestamp/VITA/VNA/phase
|
|
Flags38: Byte; // 38: HW timer enable
|
|
DataFormat: Byte; // 39: endian/format
|
|
Reserved40: array[40..55] of Byte;
|
|
AtlasBusConfig: Byte; // 56: Atlas config [2:0]
|
|
Ref10MHz: Byte; // 57: 10MHz source [1:0]
|
|
PAConfig: Byte; // 58: PA/Apollo/Mercury/clock
|
|
AlexEnable: Byte; // 59: Alex[0..7] enable
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DDC Specific Packet (PC -> HW)
|
|
// -------------------------------------------------------------------------
|
|
TDDCSpecificPacket = packed record
|
|
Seq: array[0..3] of Byte; // 0-3
|
|
NumADCs: Byte; // 4: number of ADCs
|
|
DitherADC: Byte; // 5: dither enable bits
|
|
RandomADC: Byte; // 6: random enable bits
|
|
DDCEnable: array[0..9] of Byte; // 7-16: enable bits DDC0..79
|
|
// DDC config: 6 bytes each for DDC0..79
|
|
// Byte 17+n*6: ADC selection
|
|
// Byte 18+n*6: SampleRate [15:8]
|
|
// Byte 19+n*6: SampleRate [7:0]
|
|
// Byte 20+n*6: CIC1 (future)
|
|
// Byte 21+n*6: CIC2 (future)
|
|
// Byte 22+n*6: SampleSize (default 24)
|
|
DDCConfig: array[0..479] of Byte; // 17-496
|
|
Filler: array[497..1362] of Byte;
|
|
SyncDDC: array[0..79] of Byte; // 1363-1442
|
|
Unused: Byte; // 1443
|
|
end;
|
|
|
|
// Per-DDC config helper (maps into DDCConfig array above)
|
|
TDDCConfig = packed record
|
|
ADCSource: Byte; // which ADC (0..NumADCs-1) or NumADCs for DAC
|
|
SampleRateHi, SampleRateLo: Byte;
|
|
CIC1, CIC2: Byte;
|
|
SampleSize: Byte; // default 24
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DUC (Transmitter) Specific Packet (PC -> HW)
|
|
// -------------------------------------------------------------------------
|
|
TDUCSpecificPacket = packed record
|
|
Seq: array[0..3] of Byte;
|
|
NumDACs: Byte; // 4
|
|
CWOptions: Byte; // 5: CW_* flags
|
|
SidetoneLevel: Byte; // 6: 0..127
|
|
SidetoneFreqHi: Byte; // 7
|
|
SidetoneFreqLo: Byte; // 8
|
|
KeyerSpeed: Byte; // 9: 0..60 WPM
|
|
KeyerWeight: Byte; // 10: 33..66
|
|
HangDelayHi: Byte; // 11
|
|
HangDelayLo: Byte; // 12
|
|
RFDelay: Byte; // 13
|
|
DUC0RateHi: Byte; // 14
|
|
DUC0RateLo: Byte; // 15
|
|
DUC0Bits: Byte; // 16: default 24
|
|
CWRampPeriod: Byte; // 17: ms, 0=default
|
|
Reserved18: array[18..49] of Byte;
|
|
MicLineSelect: Byte; // 50
|
|
LineInGain: Byte; // 51: 0=-34.5dB .. 31=+12dB (шаг 1.5 dB)
|
|
Reserved52: array[52..56] of Byte;
|
|
StepAtten2: Byte; // 57: ADC2 atten during TX (0-31dB)
|
|
StepAtten1: Byte; // 58: ADC1 atten during TX
|
|
StepAtten0: Byte; // 59: ADC0 atten during TX
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// High Priority Packet (PC -> HW, port 1027)
|
|
// Full packet is 1444 bytes but we define the key fields
|
|
// -------------------------------------------------------------------------
|
|
THighPriorityPacket = packed record
|
|
Seq: array[0..3] of Byte;
|
|
RunPTT: Byte; // 4: HP_RUN | HP_PTTn
|
|
CWX0: Byte; // 5: [0]=CWX [1]=Dot [2]=Dash
|
|
CWX1: Byte; // 6: reserved
|
|
CWX2: Byte; // 7: reserved
|
|
CWX3: Byte; // 8: reserved
|
|
// Bytes 9-12: DDC0 frequency/phase word (Big-Endian)
|
|
// Bytes 13-16: DDC1 ...
|
|
// Bytes 17-328: DDC2..DDC79
|
|
// Bytes 329-332: DUC0
|
|
// Byte 345: DUC0 drive level (0-255)
|
|
// Bytes 1398-1399: CAT over TCP port
|
|
// Byte 1400: Transverter/audio enable
|
|
// Byte 1401: Open Collector outputs
|
|
// Bytes 1432-1435: Alex0 filter config
|
|
// Byte 1443: Step Attenuator 0
|
|
Data: array[9..1443] of Byte;
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// High Priority Status Packet (HW -> PC, port 1025)
|
|
// -------------------------------------------------------------------------
|
|
THighPriorityStatus = packed record
|
|
Seq: array[0..3] of Byte;
|
|
StatusBits: Byte; // 4: HPS_PTT/DOT/DASH/PLL_LOCKED
|
|
ADCOverload: Byte; // 5: [0..7] = ADC0..7 overload
|
|
ExciterPwr0Hi: Byte; // 6
|
|
ExciterPwr0Lo: Byte; // 7
|
|
ExciterPwr1: array[0..1] of Byte; // 8-9 (reserved)
|
|
ExciterPwr2: array[0..1] of Byte; // 10-11 (reserved)
|
|
ExciterPwr3: array[0..1] of Byte; // 12-13 (reserved)
|
|
FwdPwrAlex0Hi: Byte; // 14
|
|
FwdPwrAlex0Lo: Byte; // 15
|
|
FwdPwrAlex1: array[0..1] of Byte; // 16-17 (reserved)
|
|
FwdPwrAlex2: array[0..1] of Byte; // 18-19 (reserved)
|
|
FwdPwrAlex3: array[0..1] of Byte; // 20-21 (reserved)
|
|
RevPwrAlex0Hi: Byte; // 22
|
|
RevPwrAlex0Lo: Byte; // 23
|
|
RevPwrAlex1: array[0..1] of Byte; // 24-25 (reserved)
|
|
RevPwrAlex2: array[0..1] of Byte; // 26-27 (reserved)
|
|
RevPwrAlex3: array[0..1] of Byte; // 28-29 (reserved)
|
|
FIFOOverflow: Byte; // 30: [3:0] overflow bits
|
|
DDCFIFODepthHi: Byte; // 31
|
|
DDCFIFODepthLo: Byte; // 32
|
|
MicFIFODepthHi: Byte; // 33
|
|
MicFIFODepthLo: Byte; // 34
|
|
DUCFIFODepthHi: Byte; // 35
|
|
DUCFIFODepthLo: Byte; // 36
|
|
SpkFIFODepthHi: Byte; // 37
|
|
SpkFIFODepthLo: Byte; // 38
|
|
Unused39: array[39..48] of Byte;
|
|
SupplyVoltsHi: Byte; // 49
|
|
SupplyVoltsLo: Byte; // 50
|
|
UserADC3Hi: Byte; // 51
|
|
UserADC3Lo: Byte; // 52
|
|
UserADC2Hi: Byte; // 53
|
|
UserADC2Lo: Byte; // 54
|
|
UserADC1Hi: Byte; // 55
|
|
UserADC1Lo: Byte; // 56
|
|
UserADC0Hi: Byte; // 57
|
|
UserADC0Lo: Byte; // 58
|
|
UserInputBits: Byte; // 59: IO4/IO5/IO6/IO8/IO2 etc.
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Microphone Data Packet (HW -> PC, default port 1026)
|
|
// -------------------------------------------------------------------------
|
|
TMicDataPacket = packed record
|
|
Seq: array[0..3] of Byte;
|
|
Samples: array[0..63] of SmallInt; // 64 x 16-bit signed, big-endian
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DDC I&Q Packet (HW -> PC, DDC0 default port 1035)
|
|
// -------------------------------------------------------------------------
|
|
TDDCIQPacket = packed record
|
|
Seq: array[0..3] of Byte; // 0-3
|
|
TimeStamp: array[0..7] of Byte; // 4-11: 64-bit VITA-49 timestamp
|
|
BitsPerSample: array[0..1] of Byte; // 12-13
|
|
SamplesPerFrame: array[0..1] of Byte;// 14-15
|
|
// From byte 16: interleaved I/Q samples
|
|
// For 24-bit: 3 bytes I, 3 bytes Q repeated
|
|
// Max 238 IQ pairs for 24-bit = 1428 bytes, total packet = 1444
|
|
IQData: array[0..1427] of Byte; // 16-1443
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DDC Audio Packet (PC -> HW, default port 1028)
|
|
// 64 Left + 64 Right 16-bit samples at 48ksps
|
|
// -------------------------------------------------------------------------
|
|
TDDCAudioPacket = packed record
|
|
Seq: array[0..3] of Byte;
|
|
// Interleaved Left/Right 16-bit samples (big-endian)
|
|
// [L0_hi, L0_lo, R0_hi, R0_lo, L1_hi, L1_lo, R1_hi, R1_lo, ...]
|
|
AudioData: array[0..255] of Byte; // 64 * 4 bytes
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// DUC I&Q Data Packet (PC -> HW, default port 1029)
|
|
// 240 IQ pairs at 192ksps, 24-bit
|
|
// -------------------------------------------------------------------------
|
|
TDUCIQPacket = packed record
|
|
Seq: array[0..3] of Byte;
|
|
// 240 * 6 bytes = 1440 bytes
|
|
IQData: array[0..1439] of Byte;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helper functions for Big-Endian packing/unpacking
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Pack a 32-bit word into 4 bytes (Big-Endian)
|
|
procedure PackU32BE(Value: LongWord; out B: array of Byte; Offset: Integer = 0);
|
|
// Unpack 4 bytes to a 32-bit word (Big-Endian)
|
|
function UnpackU32BE(const B: array of Byte; Offset: Integer = 0): LongWord;
|
|
// Pack a 16-bit word into 2 bytes (Big-Endian)
|
|
procedure PackU16BE(Value: Word; out B: array of Byte; Offset: Integer = 0);
|
|
// Unpack 2 bytes to a 16-bit word (Big-Endian)
|
|
function UnpackU16BE(const B: array of Byte; Offset: Integer = 0): Word;
|
|
|
|
// Convert frequency in Hz to phase word for HPSDR hardware
|
|
function FreqToPhaseWord(FreqHz: Double): LongWord;
|
|
|
|
// Convert phase word back to frequency
|
|
function PhaseWordToFreq(PhaseWord: LongWord): Double;
|
|
|
|
// Convert raw ADC value to supply voltage.
|
|
// Returns -1.0 if the board has no supply voltage measurement.
|
|
function ADCToSupplyVolts(RawADC: Word; BoardType: Integer): Double;
|
|
|
|
// Convert raw ADC value to supply current in Amps (Board 5 / Orion MkII only)
|
|
// Uses UserADC1 (bytes 55-56). Returns -1 for unsupported boards.
|
|
function ADCToSupplyCurrent(RawADC: Word; BoardType: Integer): Double;
|
|
|
|
// Convert raw ADC value to RF power in Watts (ANAN-100)
|
|
function ADCToWatts100(RawADC: Word): Double;
|
|
|
|
// Convert raw ADC value to RF power in Watts (ANAN-10)
|
|
function ADCToWatts10(RawADC: Word): Double;
|
|
|
|
implementation
|
|
|
|
procedure PackU32BE(Value: LongWord; out B: array of Byte; Offset: Integer);
|
|
begin
|
|
B[Offset + 0] := (Value shr 24) and $FF;
|
|
B[Offset + 1] := (Value shr 16) and $FF;
|
|
B[Offset + 2] := (Value shr 8) and $FF;
|
|
B[Offset + 3] := Value and $FF;
|
|
end;
|
|
|
|
function UnpackU32BE(const B: array of Byte; Offset: Integer): LongWord;
|
|
begin
|
|
Result := (LongWord(B[Offset]) shl 24)
|
|
or (LongWord(B[Offset+1]) shl 16)
|
|
or (LongWord(B[Offset+2]) shl 8)
|
|
or LongWord(B[Offset+3]);
|
|
end;
|
|
|
|
procedure PackU16BE(Value: Word; out B: array of Byte; Offset: Integer);
|
|
begin
|
|
B[Offset + 0] := (Value shr 8) and $FF;
|
|
B[Offset + 1] := Value and $FF;
|
|
end;
|
|
|
|
function UnpackU16BE(const B: array of Byte; Offset: Integer): Word;
|
|
begin
|
|
Result := (Word(B[Offset]) shl 8) or Word(B[Offset+1]);
|
|
end;
|
|
|
|
function FreqToPhaseWord(FreqHz: Double): LongWord;
|
|
begin
|
|
// phase_word = 2^32 * freq / DSP_CLOCK
|
|
Result := Round(4294967296.0 * FreqHz / DSP_CLOCK_HZ);
|
|
end;
|
|
|
|
function PhaseWordToFreq(PhaseWord: LongWord): Double;
|
|
begin
|
|
Result := PhaseWord * DSP_CLOCK_HZ / 4294967296.0;
|
|
end;
|
|
|
|
function ADCToSupplyVolts(RawADC: Word; BoardType: Integer): Double;
|
|
begin
|
|
// Protocol Appendix A gives the ADC reference voltage only.
|
|
// The PCB voltage divider (from Thetis source) must also be applied.
|
|
// Board 0 (Atlas): no supply voltage measurement.
|
|
// Boards 1,2,3 (Hermes/Angelia): Vref=3.3V, PCB divider R1=4.7kΩ/R2=0.82kΩ.
|
|
// Board 5 (Orion MkII): Vref=5.0V, PCB divider R1=22kΩ/R2=1.1kΩ.
|
|
// NOTE: for board 5 caller must pass UserADC0, not supply_volts bytes.
|
|
// Board 4 (Orion) and others: not available (return -1).
|
|
case BoardType of
|
|
1, 2, 3: Result := (RawADC / 4095.0) * 3.3 * ((4.7 + 0.82) / 0.82);
|
|
5: Result := (RawADC / 4095.0) * 5.0 * ((22.0 + 1.0) / 1.1);
|
|
else Result := -1.0;
|
|
end;
|
|
end;
|
|
|
|
function ADCToSupplyCurrent(RawADC: Word; BoardType: Integer): Double;
|
|
begin
|
|
// Board 5 (Orion MkII): UserADC1, Vref=5V → mV = adc/4095*5000.
|
|
// Current sensor: Voff=360mV, Sens=120mV/A (Thetis defaults, ACS712-style).
|
|
// Formula: amps = (mV - Voff) / Sens.
|
|
if BoardType = 5 then
|
|
begin
|
|
Result := ((RawADC / 4095.0) * 5000.0 - 360.0) / 120.0;
|
|
if Result < 0.0 then Result := 0.0;
|
|
end else
|
|
Result := -1.0;
|
|
end;
|
|
|
|
function ADCToWatts100(RawADC: Word): Double;
|
|
var
|
|
V: Double;
|
|
begin
|
|
// W = (ADC/4095 * 3.3)^2 / 0.095 (ANAN-100, 0-150W range)
|
|
V := (RawADC / 4095.0) * 3.3;
|
|
Result := (V * V) / 0.095;
|
|
end;
|
|
|
|
function ADCToWatts10(RawADC: Word): Double;
|
|
var
|
|
V: Double;
|
|
begin
|
|
// W = (ADC/4095 * 3.3)^2 / 0.09 (ANAN-10, 0-20W range)
|
|
V := (RawADC / 4095.0) * 3.3;
|
|
Result := (V * V) / 0.09;
|
|
end;
|
|
|
|
end.
|