From e6a7ab8152566d60a680323b11db39d75e5eefc5 Mon Sep 17 00:00:00 2001 From: g8bpq <john.wiseman@cantab.net> Date: Mon, 16 Oct 2023 18:03:48 +0100 Subject: [PATCH] 0.0.0.71 --- Config.cpp | 2 + ModemDialog.ui | 52 +++++++ QtSoundModem.cpp | 56 +++++-- QtSoundModem.vcxproj.user | 8 +- UZ7HOStuff.h | 15 +- ax25_agw.c | 49 ++++++- ax25_demod.c | 1 + debug/QtSoundModem.ini | 201 -------------------------- debug/moc_predefs-DESKTOP-MHE5LO8.h | 12 -- dw9600.c | 1 + il2p.c | 182 +++++++++++++++++++++-- kiss_mode.c | 1 - release/moc_predefs-DESKTOP-MHE5LO8.h | 11 -- 13 files changed, 330 insertions(+), 261 deletions(-) delete mode 100644 debug/QtSoundModem.ini delete mode 100644 debug/moc_predefs-DESKTOP-MHE5LO8.h delete mode 100644 release/moc_predefs-DESKTOP-MHE5LO8.h diff --git a/Config.cpp b/Config.cpp index d9dba2f..f660aaa 100644 --- a/Config.cpp +++ b/Config.cpp @@ -116,6 +116,7 @@ void GetPortSettings(int Chan) fx25_mode[Chan] = getAX25Param("FX25", FX25_MODE_RX).toInt(); il2p_mode[Chan] = getAX25Param("IL2P", IL2P_MODE_NONE).toInt(); + il2p_crc[Chan] = getAX25Param("IL2PCRC", 0).toInt(); RSID_UI[Chan] = getAX25Param("RSID_UI", 0).toInt(); RSID_SABM[Chan] = getAX25Param("RSID_SABM", 0).toInt(); RSID_SetModem[Chan] = getAX25Param("RSID_SetModem", 0).toInt(); @@ -350,6 +351,7 @@ void SavePortSettings(int Chan) saveAX25Param("MyDigiCall", MyDigiCall[Chan]); saveAX25Param("FX25", fx25_mode[Chan]); saveAX25Param("IL2P", il2p_mode[Chan]); + saveAX25Param("IL2PCRC", il2p_crc[Chan]); saveAX25Param("RSID_UI", RSID_UI[Chan]); saveAX25Param("RSID_SABM", RSID_SABM[Chan]); saveAX25Param("RSID_SetModem", RSID_SetModem[Chan]); diff --git a/ModemDialog.ui b/ModemDialog.ui index 00af6cd..9b5b856 100644 --- a/ModemDialog.ui +++ b/ModemDialog.ui @@ -737,6 +737,19 @@ <string>Retries</string> </property> </widget> + <widget class="QCheckBox" name="CRC_A"> + <property name="geometry"> + <rect> + <x>200</x> + <y>280</y> + <width>53</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>CRC</string> + </property> + </widget> </widget> </widget> </widget> @@ -1445,6 +1458,19 @@ </property> </item> </widget> + <widget class="QCheckBox" name="CRC_B"> + <property name="geometry"> + <rect> + <x>200</x> + <y>280</y> + <width>53</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>CRC</string> + </property> + </widget> </widget> <widget class="QLabel" name="label_88"> <property name="geometry"> @@ -2202,6 +2228,19 @@ </rect> </property> </widget> + <widget class="QCheckBox" name="CRC_C"> + <property name="geometry"> + <rect> + <x>200</x> + <y>280</y> + <width>53</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>CRC</string> + </property> + </widget> </widget> <widget class="QComboBox" name="IL2PModeC"> <property name="geometry"> @@ -2956,6 +2995,19 @@ </rect> </property> </widget> + <widget class="QCheckBox" name="CRC_D"> + <property name="geometry"> + <rect> + <x>200</x> + <y>280</y> + <width>53</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>CRC</string> + </property> + </widget> </widget> <widget class="QComboBox" name="IL2PModeD"> <property name="geometry"> diff --git a/QtSoundModem.cpp b/QtSoundModem.cpp index 9c0eb7b..976ca95 100644 --- a/QtSoundModem.cpp +++ b/QtSoundModem.cpp @@ -160,6 +160,7 @@ int WaterfallMax = 6000; int Configuring = 0; bool lockWaterfall = false; +bool inWaterfall = false; extern "C" int NeedWaterfallHeaders; extern "C" float BinSize; @@ -498,7 +499,7 @@ void DoPSKWindows() constellationDialog->resize(NextX, 140); } - +QTimer *wftimer; QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) { @@ -763,7 +764,7 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); timer->start(100); - QTimer *wftimer = new QTimer(this); + wftimer = new QTimer(this); connect(wftimer, SIGNAL(timeout()), this, SLOT(doRestartWF())); wftimer->start(1000 * 300); @@ -884,9 +885,12 @@ void QtSoundModem::MyTimerSlot() { NeedWaterfallHeaders = 0; - Waterfall->fill(black); - DrawModemFreqRange(); - DrawFreqTicks(); + if (Waterfall) + { + Waterfall->fill(black); + DrawModemFreqRange(); + DrawFreqTicks(); + } } show_grid(); @@ -1443,6 +1447,11 @@ void QtSoundModem::doModems() Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); + Dlg->CRC_A->setChecked(il2p_crc[0]); + Dlg->CRC_B->setChecked(il2p_crc[1]); + Dlg->CRC_C->setChecked(il2p_crc[2]); + Dlg->CRC_D->setChecked(il2p_crc[3]); + Dlg->CWIDCall->setText(CWIDCall); Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); Dlg->CWIDMark->setText(CWIDMark); @@ -1532,6 +1541,12 @@ extern "C" void get_exclude_list(char * line, TStringList * list); void QtSoundModem::modemaccept() { modemSave(); + + AGW_Report_Modem_Change(0); + AGW_Report_Modem_Change(1); + AGW_Report_Modem_Change(2); + AGW_Report_Modem_Change(3); + delete(Dlg); saveSettings(); @@ -1661,6 +1676,11 @@ void QtSoundModem::modemSave() il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); + il2p_crc[0] = Dlg->CRC_A->isChecked(); + il2p_crc[1] = Dlg->CRC_B->isChecked(); + il2p_crc[2] = Dlg->CRC_C->isChecked(); + il2p_crc[3] = Dlg->CRC_D->isChecked(); + recovery[0] = Dlg->recoverBitA->currentIndex(); recovery[1] = Dlg->recoverBitB->currentIndex(); recovery[2] = Dlg->recoverBitC->currentIndex(); @@ -1712,7 +1732,6 @@ void QtSoundModem::modemSave() for (i = 0; i < 4; i++) { initTStringList(&list_digi_callsigns[i]); - get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); } @@ -1729,6 +1748,7 @@ void QtSoundModem::modemSave() Q = Dlg->LPFWidthD->text(); lpf[3] = Q.toInt(); */ + } void QtSoundModem::modemreject() @@ -2401,6 +2421,14 @@ void QtSoundModem::handleButton(int Port, int Type) void QtSoundModem::doRestartWF() { + if (inWaterfall) + { + // in waterfall update thread + + wftimer->start(5000); + return; + } + lockWaterfall = true; if (Firstwaterfall | Secondwaterfall) @@ -2849,6 +2877,11 @@ void doWaterfallThread(void * param) if (lockWaterfall) return; + if (Configuring) + return; + + inWaterfall = true; // don't allow restart waterfall + if (snd_ch == 1 && UsingLeft == 0) // Only using right snd_ch = 0; // Samples are in first buffer @@ -2865,8 +2898,6 @@ void doWaterfallThread(void * param) float RealOut[8192] = { 0 }; float ImagOut[8192]; - if (Configuring) - return; RefreshLevel(CurrentLevel); // Signal Level @@ -2954,10 +2985,15 @@ void doWaterfallThread(void * param) // we always do fft so we can get centre freq and do busy detect. But only upodate waterfall if on display if (bm == 0) + { + inWaterfall = false; return; - + } if ((Firstwaterfall == 0 && snd_ch == 0) || (Secondwaterfall == 0 && snd_ch == 1)) + { + inWaterfall = false; return; + } p = Line; lineLen = 4096; @@ -3005,6 +3041,8 @@ void doWaterfallThread(void * param) if (TopLine > 79) TopLine = 0; } + + inWaterfall = false; } diff --git a/QtSoundModem.vcxproj.user b/QtSoundModem.vcxproj.user index 198fa38..8b8926c 100644 --- a/QtSoundModem.vcxproj.user +++ b/QtSoundModem.vcxproj.user @@ -20,15 +20,15 @@ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> </PropertyGroup> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <QtLastBackgroundBuild>2023-10-13T13:21:39.9400374Z</QtLastBackgroundBuild> + <QtLastBackgroundBuild>2023-10-15T11:35:54.9027336Z</QtLastBackgroundBuild> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings"> - <QtLastBackgroundBuild>2023-10-13T13:21:40.0558471Z</QtLastBackgroundBuild> + <QtLastBackgroundBuild>2023-10-15T11:35:55.0741785Z</QtLastBackgroundBuild> </PropertyGroup> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <QtLastBackgroundBuild>2023-10-13T13:21:40.2121547Z</QtLastBackgroundBuild> + <QtLastBackgroundBuild>2023-10-15T11:35:55.2661628Z</QtLastBackgroundBuild> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings"> - <QtLastBackgroundBuild>2023-10-13T13:21:40.4722944Z</QtLastBackgroundBuild> + <QtLastBackgroundBuild>2023-10-15T11:35:55.4659021Z</QtLastBackgroundBuild> </PropertyGroup> </Project> \ No newline at end of file diff --git a/UZ7HOStuff.h b/UZ7HOStuff.h index 00aa2f3..4a68356 100644 --- a/UZ7HOStuff.h +++ b/UZ7HOStuff.h @@ -4,8 +4,8 @@ // My port of UZ7HO's Soundmodem // -#define VersionString "0.0.0.70" -#define VersionBytes {0, 0, 0, 70} +#define VersionString "0.0.0.71" +#define VersionBytes {0, 0, 0, 71} // Added FX25. 4x100 FEC and V27 not Working and disabled @@ -174,6 +174,11 @@ // .70 Restructure Waterfall area to be a single image +// .71 Add IL2P CRC Mode +// Improve reliability of waterfall update +// Report and set fx.25 and il2p flags to/from BPQ + + #include <string.h> @@ -1004,6 +1009,7 @@ extern TAX25Port AX25Port[4][port_num]; extern int fx25_mode[4]; extern int il2p_mode[4]; +extern int il2p_crc[4]; extern int tx_fx25_size[4]; extern int tx_fx25_size_cnt[4]; @@ -1105,7 +1111,7 @@ int Add(TStringList * Q, string * Entry); struct il2p_context_s { - enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_DECODE } state; + enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_CRC, IL2P_DECODE } state; unsigned int acc; // Accumulate most recent 24 bits for sync word matching. // Lower 8 bits are also used for accumulating bytes for @@ -1129,6 +1135,9 @@ struct il2p_context_s { int pc; // Number of bytes placed in above. int corrected; // Number of symbols corrected by RS FEC. + + int crccount; // fec chars collected + unsigned char crc[4]; // the 4 fec chars }; extern int NeedWaterfallHeaders; diff --git a/ax25_agw.c b/ax25_agw.c index 5432195..ec73b2b 100644 --- a/ax25_agw.c +++ b/ax25_agw.c @@ -515,13 +515,15 @@ void on_AGW_Gs_frame(AGWUser * AGW, struct AGWHeader * Frame, Byte * Data) { // QTSM with a data field is used by QtSM to set/read Modem Params - Byte info[44] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature + Byte info[48] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature int Len = 12; if (Frame->DataLength == 32) { // BPQ to QTSM private Format. + // First 4 Freq, 4 to 24 Modem, rest was spare. Use 27-31 for modem control flags (fx.25 il2p etc) + int Freq; Byte versionBytes[4] = VersionBytes; @@ -542,7 +544,7 @@ void on_AGW_Gs_frame(AGWUser * AGW, struct AGWHeader * Frame, Byte * Data) // New Modem Name. Need to convert to index unless numeric int n; - + if (strlen(&Data[4]) < 3) { n = atoi(&Data[4]); @@ -569,6 +571,13 @@ void on_AGW_Gs_frame(AGWUser * AGW, struct AGWHeader * Frame, Byte * Data) } } + if (Data[27] == 2) + { + fx25_mode[Frame->Port] = Data[28]; + il2p_mode[Frame->Port] = Data[29]; + il2p_crc[Frame->Port] = Data[30]; + } + // Return Freq and Modem memcpy(&info[12], &rx_freq[Frame->Port], 2); @@ -577,6 +586,22 @@ void on_AGW_Gs_frame(AGWUser * AGW, struct AGWHeader * Frame, Byte * Data) memcpy(&info[38], versionBytes, 4); Len = 44; + + if (Data[27]) + { + // BPQ understands fx25 and il2p fields + + AGW->reportFreqAndModem = 2; // Can report frequency Modem and flags + + + Len = 48; + + info[44] = 1; // Show includes Modem Flags + info[45] = fx25_mode[Frame->Port]; + info[46] = il2p_mode[Frame->Port]; + info[47] = il2p_crc[Frame->Port]; + } + AGW_send_to_app(AGW->socket, AGW_Gs_Frame(Frame->Port, info, Len)); return; } @@ -1337,6 +1362,9 @@ void AGW_Report_Modem_Change(int port) AGWUser * AGW; string * pkt; + if (soundChannel[port] == 0) // Not in use + return; + // I think we send to all AGW sockets for (i = 0; i < AGWConCount; i++) @@ -1345,16 +1373,27 @@ void AGW_Report_Modem_Change(int port) if (AGW->reportFreqAndModem) { - // QTSM 's' Message with a data field is used by QtSM to set/read Modem Params + // QTSM 'g' Message with a data field is used by QtSM to set/read Modem Params - Byte info[44] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature + Byte info[48] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature + int Len = 44; // Return Freq and Modem memcpy(&info[12], &rx_freq[port], 2); memcpy(&info[16], modes_name[speed[port]], 20); info[37] = speed[port]; // Index - AGW_send_to_app(AGW->socket, AGW_Gs_Frame(port, info, 44)); + + if (AGW->reportFreqAndModem == 2) + { + Len = 48; + + info[44] = 1; // Show includes Modem Flags + info[45] = fx25_mode[port]; + info[46] = il2p_mode[port]; + info[47] = il2p_crc[port]; + } + AGW_send_to_app(AGW->socket, AGW_Gs_Frame(port, info, Len)); } } } diff --git a/ax25_demod.c b/ax25_demod.c index 3e1b5bb..f1b0b36 100644 --- a/ax25_demod.c +++ b/ax25_demod.c @@ -142,6 +142,7 @@ short active_rx_freq[5] = { 1700, 1700,1700,1700,1700 }; int fx25_mode[4] = { 0, 0, 0, 0 }; int il2p_mode[4] = { 0, 0, 0, 0 }; +int il2p_crc[4] = { 0, 0, 0, 0 }; int pnt_change[5] = { 0 }; float src_buf[5][2048]; diff --git a/debug/QtSoundModem.ini b/debug/QtSoundModem.ini deleted file mode 100644 index 0aefa4a..0000000 --- a/debug/QtSoundModem.ini +++ /dev/null @@ -1,201 +0,0 @@ -[General] -geometry="@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0z\0\0\0\t\0\0\x4=\0\0\x2\xf9\0\0\0{\0\0\0(\0\0\x4<\0\0\x2\xf8\0\0\0\0\0\0\0\0\x5\0\0\0\0{\0\0\0(\0\0\x4<\0\0\x2\xf8)" -windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\xc2\0\0\x2\xb9\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\0) -PSKWindow=@Rect(46 499 366 140) -FontFamily=Courier New -PointSize=12 -Weight=50 - -[AX25_A] -Retries=15 -HiToneRaise=0 -Maxframe=3 -FrackTime=5 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -NonAX25Frm=0 -MEMRecovery=200 -IPOLL=80 -MyDigiCall= -FX25=1 -IL2P=2 -RSID_UI=0 -RSID_SABM=0 -RSID_SetModem=0 - -[Init] -SoundMode=0 -UDPClientPort=8888 -UDPServerPort=8884 -TXPort=8884 -UDPServer=0 -UDPHost=192.168.1.255 -TXSampleRate=12000 -RXSampleRate=12000 -SndRXDeviceName="CABLE-B OUTPUT (VB-AUDIO CABLE " -SndTXDeviceName=CABLE-B INPUT (VB-AUDIO CABLE B -SCO=0 -DualPTT=1 -TXRotate=0 -DispMode=1 -PTT= -PTTBAUD=19200 -PTTMode=1 -PTTOffString= -PTTOnString= -pttGPIOPin=17 -pttGPIOPinR=17 -CM108Addr=0xD8C:0x08 -HamLibPort=4532 -HamLibHost=127.0.0.1 -MinimizetoTray=1 -multiCore=1 -Wisdom=(fftw-3.3.5 fftwf_wisdom #x9e7d4dee #xdb14fed1 #x34bf76a4 #xeb6e8fdf\n (fftwf_codelet_n2fv_12_avx 0 #x10048 #x10048 #x0 #xb0767e46 #x8d41dd22 #x439264a0 #x18435a99)\n (fftwf_rdft_rank0_register 0 #x11048 #x11048 #x0 #xff75c762 #x3a0ee093 #x5b78d592 #x6b6be60e)\n (fftwf_codelet_t2fv_2_avx 0 #x11048 #x11048 #x0 #x34057a74 #x664db78f #xa9524ebc #x606afd88)\n (fftwf_dft_nop_register 0 #x11048 #x11048 #x0 #x4a593e24 #xb5f06ddf #xf11fe7f2 #xc010b545)\n (fftwf_dft_bluestein_register 0 #x11048 #x11048 #x0 #x5e17c068 #x1682c5d6 #x89dd79be #x9b951c0f)\n (fftwf_dft_vrank_geq1_register 0 #x10048 #x10048 #x0 #x2fce15e1 #x178d4f4d #x1e956a41 #xf3fd6b80)\n (fftwf_codelet_t1fuv_4_sse2 0 #x11048 #x11048 #x0 #x2fb84bc5 #x2792028e #x8ec66ed5 #x47b5f7dc)\n (fftwf_dft_buffered_register 0 #x11048 #x11048 #x0 #x4f8e87b4 #xec4f2fa0 #x79fe76a1 #xa16e32a5)\n (fftwf_dft_vrank_geq1_register 0 #x11048 #x11048 #x0 #x8a9c355b #xb6dbadad #xbac1daac #xa866ceb3)\n (fftwf_dft_r2hc_register 0 #x11048 #x11048 #x0 #x576d5db6 #xa6a15f8a #x875d87d5 #x7561a866)\n (fftwf_codelet_t1fv_6_avx 0 #x10048 #x10048 #x0 #xd9db29d8 #x3302fcf3 #x19ce6e5d #x869fc341)\n (fftwf_dft_vrank_geq1_register 0 #x11048 #x11048 #x0 #xf7abab03 #x5f0e79b1 #x1b8367ad #xe5028f2c)\n (fftwf_codelet_t1fv_12_avx 0 #x10048 #x10048 #x0 #x0b0d3933 #x08267d12 #x45613873 #xde496efe)\n)\n -WaterfallMin=0 -WaterfallMax=3300 - -[AX25_B] -Retries=15 -HiToneRaise=0 -Maxframe=3 -FrackTime=5 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -NonAX25Frm=0 -MEMRecovery=200 -IPOLL=80 -MyDigiCall= -FX25=1 -IL2P=2 -RSID_UI=0 -RSID_SABM=0 -RSID_SetModem=0 - -[Modem] -NRRcvrPairs1=2 -NRRcvrPairs2=2 -NRRcvrPairs3=0 -NRRcvrPairs4=2 -RcvrShift1=50 -RcvrShift2=30 -RcvrShift3=30 -RcvrShift4=30 -ModemType1=4 -ModemType2=14 -ModemType3=0 -ModemType4=14 -soundChannel1=1 -soundChannel2=1 -soundChannel3=0 -soundChannel4=0 -DCDThreshold=40 -rxOffset=-100 -PreEmphasisAll1=0 -PreEmphasisAll2=0 -PreEmphasisAll3=0 -PreEmphasisAll4=0 -PreEmphasisDB1=0 -PreEmphasisDB2=0 -PreEmphasisDB3=0 -PreEmphasisDB4=0 -TxDelay1=250 -TxDelay2=250 -TxDelay3=250 -TxDelay4=250 -TxTail1=50 -TxTail2=50 -TxTail3=50 -TxTail4=50 -CWIDCall= -CWIDInterval=0 -CWIDLeft=0 -CWIDRight=0 -CWIDType=1 -RXFreq1=1700 -RXFreq2=1700 -RXFreq3=500 -RXFreq4=1700 -CWIDMark= -afterTraffic=false - -[AGWHost] -Server=1 -Port=8000 - -[KISS] -Server=0 -Port=8105 - -[AX25_C] -Retries=15 -HiToneRaise=0 -Maxframe=3 -FrackTime=5 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -NonAX25Frm=0 -MEMRecovery=200 -IPOLL=80 -MyDigiCall= -FX25=1 -IL2P=0 -RSID_UI=0 -RSID_SABM=0 -RSID_SetModem=0 - -[Window] -Waterfall1=1 -Waterfall2=1 - -[AX25_D] -Retries=15 -HiToneRaise=0 -Maxframe=3 -FrackTime=5 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -NonAX25Frm=0 -MEMRecovery=200 -IPOLL=80 -MyDigiCall= -FX25=1 -IL2P=0 -RSID_UI=0 -RSID_SABM=0 -RSID_SetModem=0 diff --git a/debug/moc_predefs-DESKTOP-MHE5LO8.h b/debug/moc_predefs-DESKTOP-MHE5LO8.h deleted file mode 100644 index 2c1557b..0000000 --- a/debug/moc_predefs-DESKTOP-MHE5LO8.h +++ /dev/null @@ -1,12 +0,0 @@ -#define _MSC_EXTENSIONS -#define _INTEGRAL_MAX_BITS 64 -#define _MSC_VER 1916 -#define _MSC_FULL_VER 191627050 -#define _MSC_BUILD 0 -#define _WIN32 -#define _M_IX86 600 -#define _M_IX86_FP 2 -#define _CPPRTTI -#define _DEBUG -#define _MT -#define _DLL diff --git a/dw9600.c b/dw9600.c index 8307342..407feb1 100644 --- a/dw9600.c +++ b/dw9600.c @@ -25,6 +25,7 @@ typedef struct TStringList_T extern int fx25_mode[4]; extern int il2p_mode[4]; +extern int il2p_crc[4]; extern short rx_baudrate[5]; #define FX25_MODE_NONE 0 diff --git a/il2p.c b/il2p.c index e51264c..6a284f2 100644 --- a/il2p.c +++ b/il2p.c @@ -42,11 +42,44 @@ along with QtSoundModem. If not, see http://www.gnu.org/licenses // IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders - - - #include "UZ7HOStuff.h" +#include <stdint.h> // for uint64_t + + // Oct 2023 Nino has added an optional crc + +// Hamming(7,4) Encoding Table +// Enter this table with the 4-bit value to be encoded. +// Returns 7-bit encoded value, with high bit zero'd. + +uint8_t Hamming74EncodeTable[16] = { 0x0, 0x71, 0x62, 0x13, 0x54, 0x25, 0x36, 0x47, 0x38, 0x49, 0x5a, 0x2b, 0x6c, 0x1d, 0xe, 0x7f }; + +// Hamming(7,4) Decoding Table +// Enter this table with 7-bit encoded value, high bit masked. +// Returns 4-bit decoded value. + +uint16_t Hamming74DecodeTable[128] = { \ + 0x0, 0x0, 0x0, 0x3, 0x0, 0x5, 0xe, 0x7, \ + 0x0, 0x9, 0xe, 0xb, 0xe, 0xd, 0xe, 0xe, \ + 0x0, 0x3, 0x3, 0x3, 0x4, 0xd, 0x6, 0x3, \ + 0x8, 0xd, 0xa, 0x3, 0xd, 0xd, 0xe, 0xd, \ + 0x0, 0x5, 0x2, 0xb, 0x5, 0x5, 0x6, 0x5, \ + 0x8, 0xb, 0xb, 0xb, 0xc, 0x5, 0xe, 0xb, \ + 0x8, 0x1, 0x6, 0x3, 0x6, 0x5, 0x6, 0x6, \ + 0x8, 0x8, 0x8, 0xb, 0x8, 0xd, 0x6, 0xf, \ + 0x0, 0x9, 0x2, 0x7, 0x4, 0x7, 0x7, 0x7, \ + 0x9, 0x9, 0xa, 0x9, 0xc, 0x9, 0xe, 0x7, \ + 0x4, 0x1, 0xa, 0x3, 0x4, 0x4, 0x4, 0x7, \ + 0xa, 0x9, 0xa, 0xa, 0x4, 0xd, 0xa, 0xf, \ + 0x2, 0x1, 0x2, 0x2, 0xc, 0x5, 0x2, 0x7, \ + 0xc, 0x9, 0x2, 0xb, 0xc, 0xc, 0xc, 0xf, \ + 0x1, 0x1, 0x2, 0x1, 0x4, 0x1, 0x6, 0xf, \ + 0x8, 0x1, 0xa, 0xf, 0xc, 0xf, 0xf, 0xf }; + + + + + void Debugprintf(const char * format, ...); int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count); @@ -109,7 +142,6 @@ int MaxMagIndex = 0; #ifndef FX25_H #define FX25_H -#include <stdint.h> // for uint64_t extern unsigned int pskStates[4]; @@ -343,6 +375,7 @@ struct packet_s { unsigned char frame_data[AX25_MAX_PACKET_LEN + 1]; /* Raw frame contents, without the CRC. */ + unsigned char crc[4]; // received crc int magic2; /* Will get stomped on if above overflows. */ }; @@ -1015,6 +1048,39 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t sprintf(Mode, "IL2P %d", centreFreq); + // check crc if enabled + + if (il2p_crc[snd_ch]) + { + unsigned short CRCMSG; + unsigned short CRCCALC; + uint8_t crc[4]; + + // check crc if enabled + + // The four encoded CRC bytes are arranged : + // | CRC3 | CRC2 | CRC1 | CRC0 | but we store as received, so F->crc[0] is CRC3 + // CRC3 encoded from high nibble of 16 - bit CRC value (from crc2) + // CRC0 encoded from low nibble of 16 - bit CRC value (from crc1) + + crc[0] = Hamming74DecodeTable[(pp->crc[0] & 0x7f)]; + crc[1] = Hamming74DecodeTable[(pp->crc[1] & 0x7f)]; + crc[2] = Hamming74DecodeTable[(pp->crc[2] & 0x7f)]; + crc[3] = Hamming74DecodeTable[(pp->crc[3] & 0x7f)]; + + CRCMSG = crc[0] << 12 | crc[1] << 8 | crc[2] << 4 | crc[3]; + + CRCCALC = get_fcs(pp->frame_data, pp->frame_len); + + if (CRCCALC != CRCMSG) + { + Debugprintf("CRC Error Decoder %d Received %x Sent %x", subchan, CRCCALC, CRCMSG); + // freeString(data); + // ax25_delete(pp); + // return; + } + } + stringAdd(data, pp->frame_data, pp->frame_len + 2); // QTSM assumes a CRC ax25_delete(pp); @@ -3151,6 +3217,13 @@ int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr) ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr); int src_ssid = ax25_get_ssid(pp, AX25_SOURCE); + if ((pp->frame_data[6] & 0x80) == (pp->frame_data[13] & 0x80)) + { + // Both C bits are the same (ax.25 v1) so can't be sent as type 1 as will be changed + + return -1; + } + unsigned char *a = (unsigned char *)dst_addr; for (int i = 0; *a != '\0'; i++, a++) { if (*a < ' ' || *a > '_') { @@ -3919,7 +3992,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) //assert(slice >= 0 && slice < MAX_SLICERS); F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s)); //assert(F != NULL); - memset(F, 0, sizeof(struct il2p_context_s)); +memset(F, 0, sizeof(struct il2p_context_s)); } // Accumulate most recent 24 bits received. Most recent is LSB. @@ -3942,7 +4015,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) nPhases[chan][subchan][slice] = 0; // Determine Centre Freq - + centreFreq[chan] = GuessCentreFreq(chan); } else if (__builtin_popcount((~F->acc & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) { @@ -3956,7 +4029,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) centreFreq[chan] = GuessCentreFreq(chan); nPhases[chan][subchan][slice] = 0; } - + break; case IL2P_HEADER: // Gathering the header. @@ -3990,7 +4063,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) F->eplen = il2p_payload_compute(&plprop, len, max_fec); if (il2p_get_debug() >= 1) - { + { Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec); Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len); Debugprintf("%d small blocks of %d and %d large blocks of %d. %d parity symbols per block", @@ -4008,9 +4081,21 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) F->pc = 0; F->state = IL2P_PAYLOAD; } - else if (F->eplen == 0) { // No payload. + else if (F->eplen == 0) + { + // No payload. + F->pc = 0; - F->state = IL2P_DECODE; + + if (il2p_crc[chan]) + { + // enter collect crc state + + F->crccount = 0; + F->state = IL2P_CRC; + } + else + F->state = IL2P_DECODE; } else { // Error. @@ -4039,16 +4124,47 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) else { F->spayload[F->pc++] = (~F->acc) & 0xff; } - if (F->pc == F->eplen) { + if (F->pc == F->eplen) + { + // got frame. See if need crc - // TODO?: for symmetry it seems like we should clarify the payload before combining. + if (il2p_crc[chan]) + { + // enter collect crc state - F->state = IL2P_DECODE; + F->crccount = 0; + F->state = IL2P_CRC; + } + else + F->state = IL2P_DECODE; } } break; + case IL2P_CRC: + + F->bc++; + if (F->bc == 8) + { + // full byte has been collected. + F->bc = 0; + if (!F->polarity) + F->crc[F->crccount++] = F->acc & 0xff; + else + F->crc[F->crccount++] = (~F->acc) & 0xff; + + if (F->crccount == 4) + { + // have all crc bytes. enter DECODE + + F->state = IL2P_DECODE; + } + } + + break; + case IL2P_DECODE: + // We get here after a good header and any payload has been collected. // Processing is delayed by one bit but I think it makes the logic cleaner. // During unit testing be sure to send an extra bit to flush it out at the end. @@ -4077,6 +4193,18 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit) // TODO: Could we put last 3 arguments in packet object rather than passing around separately? + // if using crc pass received crc to packet object + + if (il2p_crc[chan]) + { + //copy crc bytes to packet object + + pp->crc[0] = F->crc[0]; + pp->crc[1] = F->crc[1]; + pp->crc[2] = F->crc[2]; + pp->crc[3] = F->crc[3]; + } + multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]); } } // end block for local variables. @@ -4269,13 +4397,19 @@ static void send_bit(int chan, int b, int polarity); * *--------------------------------------------------------------*/ + string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity) { - unsigned char encoded[IL2P_MAX_PACKET_SIZE]; + unsigned char encoded[IL2P_MAX_PACKET_SIZE] = ""; string * packet = newString(); int preamblecount; unsigned char preamble[1024]; + // The data includes the 2 byte crc but length doesn't + + uint8_t crc1 = pp->frame_data[pp->frame_len]; // Low 8 bits + uint8_t crc2 = pp->frame_data[pp->frame_len + 1]; // High 8 bits + encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff; encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff; encoded[2] = (IL2P_SYNC_WORD) & 0xff; @@ -4289,6 +4423,24 @@ string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity) elen += IL2P_SYNC_WORD_SIZE; + // if we are using crc add it now. elen should point to end of data + // crc should be at pp->frame_data[pp->frame_len] + + if (il2p_crc[chan]) + { + // The four encoded CRC bytes are arranged : + // | CRC3 | CRC2 | CRC1 | CRC0 | + + // CRC3 encoded from high nibble of 16 - bit CRC value (from crc2) + // CRC0 encoded from low nibble of 16 - bit CRC value (from crc1) + + encoded[elen++] = Hamming74EncodeTable[crc2 >> 4]; + encoded[elen++] = Hamming74EncodeTable[crc2 & 0xf]; + encoded[elen++] = Hamming74EncodeTable[crc1 >> 4]; + encoded[elen++] = Hamming74EncodeTable[crc1 &0xf]; + } + + number_of_bits_sent[chan] = 0; if (il2p_get_debug() >= 1) { @@ -4366,7 +4518,7 @@ string * fill_il2p_data(int snd_ch, string * data) // Call il2p_send_frame to build the bit stream pp->frame_len = data->Length - 2; // Included CRC - memcpy(pp->frame_data, data->Data, data->Length); + memcpy(pp->frame_data, data->Data, data->Length); // Copy the crc in case we are going to send it result = il2p_send_frame(snd_ch, pp, 1, 0); diff --git a/kiss_mode.c b/kiss_mode.c index 5adba5d..72688a7 100644 --- a/kiss_mode.c +++ b/kiss_mode.c @@ -245,7 +245,6 @@ void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) Add(&KISS.buffer[Chan], TXMSG); } - return; case KISS_DATA: diff --git a/release/moc_predefs-DESKTOP-MHE5LO8.h b/release/moc_predefs-DESKTOP-MHE5LO8.h deleted file mode 100644 index 4c9c0c7..0000000 --- a/release/moc_predefs-DESKTOP-MHE5LO8.h +++ /dev/null @@ -1,11 +0,0 @@ -#define _MSC_EXTENSIONS -#define _INTEGRAL_MAX_BITS 64 -#define _MSC_VER 1916 -#define _MSC_FULL_VER 191627043 -#define _MSC_BUILD 0 -#define _WIN32 -#define _M_IX86 600 -#define _M_IX86_FP 2 -#define _CPPRTTI -#define _MT -#define _DLL