diff --git a/KISSConfig.ui b/KISSConfig.ui
index 3f4509a..8c54dfe 100644
--- a/KISSConfig.ui
+++ b/KISSConfig.ui
@@ -468,6 +468,35 @@
TXDelay
+
+
+
+ 200
+ 80
+ 151
+ 30
+
+
+
+ Open MH Window
+
+
+
+
+
+ 390
+ 83
+ 20
+ 20
+
+
+
+ Qt::RightToLeft
+
+
+
+
+
diff --git a/QtTermTCP.cpp b/QtTermTCP.cpp
index 6f10b14..45fd43d 100644
--- a/QtTermTCP.cpp
+++ b/QtTermTCP.cpp
@@ -2,7 +2,7 @@
// Application icon design by Red PE1RRR
-#define VersionString "0.0.0.78"
+#define VersionString "0.0.0.79"
// .12 Save font weight
@@ -124,6 +124,10 @@
// Fix restoring monitor flags when connecting to current host
+// .79
+// Add KISS MHEARD Window (Feb 2025)
+
+
#define _CRT_SECURE_NO_WARNINGS
#define UNUSED(x) (void)(x)
@@ -328,6 +332,7 @@ extern "C" int KISSMonNodes;
extern "C" int KISSListen;
extern "C" int KISSChecksum;
extern "C" int KISSAckMode;
+extern "C" int KISSMH;
extern "C" short txtail[5];
extern "C" short txdelay[5];
@@ -559,6 +564,7 @@ void AGWMonWindowClosing(Ui_ListenSession *Sess);
void AGWWindowClosing(Ui_ListenSession *Sess);
extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length);
void closeSerialPort();
+int newMHWindow(QObject * parent, int Type, const char * Label);
extern void initUTF8();
int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
@@ -736,12 +742,39 @@ void DoTermResize(Ui_ListenSession * Sess)
}
}
+
+extern "C" Ui_ListenSession * MHWindow;
+
bool QtTermTCP::eventFilter(QObject* obj, QEvent *event)
{
// See if from a Listening Session
Ui_ListenSession * Sess;
+ if (obj == MHWindow)
+ {
+ if (event->type() == QEvent::Resize)
+ {
+ QRect r = MHWindow->rect();
+
+ int H, Width, Border = 3;
+
+ Width = r.width() - 6;
+ H = r.height() - 6;
+
+ MHWindow->monWindow->setGeometry(QRect(Border, Border, Width, H));
+ return true;
+ }
+ if (event->type() == QEvent::Close)
+ {
+ QSettings mysettings(GetConfPath(), QSettings::IniFormat);
+ mysettings.setValue("MHgeometry", MHWindow->saveGeometry());
+ SaveSettings();
+ MHWindow = 0;
+ }
+ }
+
+
for (int i = 0; i < _sessions.size(); ++i)
{
Sess = _sessions.at(i);
@@ -1336,6 +1369,12 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
updateWindowMenu();
+ if (KISSEnable && KISSMH)
+ {
+ newMHWindow(this, 0, "KISS MH");
+ MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray());
+ }
+
connectMenu = mymenuBar->addMenu(tr("&Connect"));
actHost[16] = new QAction("AGW Connect", this);
@@ -3604,6 +3643,7 @@ void GetSettings()
KISSListen = settings->value("KISSListen", 1).toInt();
KISSChecksum = settings->value("KISSChecksum", 0).toInt();
KISSAckMode = settings->value("KISSAckMode", 0).toInt();
+ KISSMH = settings->value("KISSMH", 1).toInt();
strcpy(KISSMYCALL, settings->value("MYCALL", "").toString().toUtf8());
strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8());
KISSPortNum = settings->value("KISSPort", 8100).toInt();
@@ -3837,6 +3877,7 @@ extern "C" void SaveSettings()
settings->setValue("KISSListen", KISSListen);
settings->setValue("KISSChecksum", KISSChecksum);
settings->setValue("KISSAckMode", KISSAckMode);
+ settings->setValue("KISSMH", KISSMH);
settings->setValue("MYCALL", KISSMYCALL);
settings->setValue("KISSHost", KISSHost);
settings->setValue("KISSMode", KISSMode);
@@ -3921,6 +3962,10 @@ void QtTermTCP::closeEvent(QCloseEvent *event)
#endif
if (process)
process->close();
+
+ if (MHWindow)
+ MHWindow->close();
+
}
}
@@ -3962,6 +4007,11 @@ QtTermTCP::~QtTermTCP()
mysettings.setValue("geometry", saveGeometry());
mysettings.setValue("windowState", saveState());
+ if (MHWindow)
+ {
+ mysettings.setValue("MHgeometry", MHWindow->saveGeometry());
+ MHWindow->close();
+ }
SaveSettings();
}
@@ -4117,6 +4167,7 @@ void QtTermTCP::KISSSlot()
KISS->KISSListen->setChecked(KISSListen);
KISS->KISSChecksum->setChecked(KISSChecksum);
KISS->KISSACKMODE->setChecked(KISSAckMode);
+ KISS->KISSMH->setChecked(KISSMH);
KISS->MYCALL->setText(KISSMYCALL);
KISS->TXDELAY->setText(QString::number(txdelay[0]));
@@ -4176,6 +4227,7 @@ void QtTermTCP::KISSaccept()
KISSListen = KISS->KISSListen->isChecked();
KISSChecksum = KISS->KISSChecksum->isChecked();
KISSAckMode = KISS->KISSACKMODE->isChecked();
+ KISSMH = KISS->KISSMH->isChecked();
actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line
strcpy(KISSMYCALL, KISS->MYCALL->text().toUtf8().toUpper());
@@ -4231,6 +4283,26 @@ void QtTermTCP::KISSaccept()
}
}
+ if (KISSEnable == 0 && MHWindow)
+ {
+ MHWindow->close();
+ MHWindow = 0;
+ }
+
+ if (KISSEnable && KISSMH && MHWindow == 0)
+ {
+ newMHWindow(this, 0, "KISS MH");
+ QSettings mysettings(GetConfPath(), QSettings::IniFormat);
+ MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray());
+ }
+
+ if (!KISSMH && MHWindow)
+ {
+ MHWindow->close();
+ MHWindow = 0;
+ }
+
+
delete(KISS);
SaveSettings();
deviceUI->accept();
@@ -7988,3 +8060,106 @@ void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg)
}
+// Create MH Window
+
+
+
+int newMHWindow(QObject * parent, int Type, const char * Label)
+{
+ Ui_ListenSession * Sess = new(Ui_ListenSession);
+
+ MHWindow = Sess;
+
+ // Need to explicity initialise on Qt4
+
+ Sess->termWindow = NULL;
+ Sess->monWindow = NULL;
+ Sess->inputWindow = NULL;
+
+ Sess->StackIndex = 0;
+ Sess->InputMode = 0;
+ Sess->SlowTimer = 0;
+ Sess->MonData = 0;
+ Sess->OutputSaveLen = 0;
+ Sess->MonSaveLen = 0;
+ Sess->PortMonString[0] = 0;
+ Sess->portmask = 0;
+ Sess->portmask = 1;
+ Sess->mtxparam = 1;
+ Sess->mlocaltime = 0;
+ Sess->mcomparam = 1;
+ Sess->monUI = 0;
+ Sess->MonitorNODES = 0;
+ Sess->MonitorColour = 1;
+ Sess->CurrentHost = 0;
+
+ Sess->SessionType = Type;
+ Sess->clientSocket = NULL;
+ Sess->AGWSession = NULL;
+ Sess->AGWMonSession = NULL;
+ Sess->KISSSession = NULL;
+ Sess->KISSMode = 0;
+ Sess->TTActive = 0;
+ Sess->TTFlashToggle = 0;
+ Sess->pageBuffer[0] = 0;
+ Sess->Tab = 0;
+
+ Sess->LogMonitor = false;
+ Sess->monSpan = (char *) "";
+ Sess->monLogfile = nullptr;
+ Sess->sessNo = sessNo++;
+
+ QSettings settings(GetConfPath(), QSettings::IniFormat);
+
+#ifdef ANDROID
+ QFont font = QFont(settings.value("FontFamily", "Driod Sans Mono").value(),
+ settings.value("PointSize", 12).toInt(),
+ settings.value("Weight", 50).toInt());
+#else
+ QFont font = QFont(settings.value("FontFamily", "Courier New").value(),
+ settings.value("PointSize", 10).toInt(),
+ settings.value("Weight", 50).toInt());
+#endif
+
+ Sess->monWindow = new QTextEdit(Sess);
+ Sess->monWindow->setReadOnly(1);
+ Sess->monWindow->document()->setMaximumBlockCount(10000);
+ Sess->monWindow->setFont(font);
+ Sess->monWindow->setStyleSheet(monStyleSheet);
+
+ Sess->setWindowTitle(Label);
+
+ Sess->installEventFilter(mythis);
+
+ Sess->show();
+
+
+
+ Sess->monWindow->setGeometry(QRect(2, 2, 400, 400));
+ Sess->setGeometry(QRect(400, 400, 400, 400));
+
+
+ QSize Size(800, 602); // Not actually used, but Event constructor needs it
+
+ QResizeEvent event(Size, Size);
+
+ QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window
+
+ return true;
+}
+
+extern "C" void WritetoMHWindow(char * Buffer)
+{
+ unsigned char Copy[8192];
+ unsigned char * ptr1, *ptr2;
+ unsigned char Line[8192];
+ unsigned char out[8192];
+ int outlen;
+
+ int num;
+
+ if (MHWindow == NULL || MHWindow->monWindow == NULL)
+ return;
+
+ MHWindow->monWindow->setText(Buffer);
+}
diff --git a/QtTermTCP.vcxproj.user b/QtTermTCP.vcxproj.user
index 43079b7..56666e6 100644
--- a/QtTermTCP.vcxproj.user
+++ b/QtTermTCP.vcxproj.user
@@ -3,11 +3,12 @@
C:\DevProgs\BPQ32\Release
WindowsLocalDebugger
- C:\Dev\Msdev2005\projects\QT\QtTermTCP\Win32\Debug\QtTermTCP.exe
+ C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe
C:\DevProgs\BPQ32\Release
WindowsLocalDebugger
+ C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe
2022-05-19T07:28:47.9186341Z
@@ -16,15 +17,15 @@
2022-05-19T07:28:58.9302359Z
- 2024-08-18T13:22:28.7149666Z
+ 2025-02-19T10:20:19.7224236Z
- 2024-08-18T13:22:29.0403359Z
+ 2025-02-19T10:20:19.9860750Z
- 2024-08-18T13:22:28.3840024Z
+ 2025-02-19T10:20:19.2704826Z
- 2024-08-18T13:22:28.6207028Z
+ 2025-02-19T10:20:19.4132585Z
\ No newline at end of file
diff --git a/ax25.c b/ax25.c
index 6e9f489..5858b5a 100644
--- a/ax25.c
+++ b/ax25.c
@@ -44,7 +44,7 @@ void decode_frame(Byte * frame, int len, Byte * path, string * data,
void SetSessLabel(void * Sess, char * label);
void setMenus(int State);
-
+void MHPROC(unsigned char * Packet, int Len);
/*
unit ax25;
@@ -2626,6 +2626,8 @@ void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len)
TXMSG = newString();
stringAdd(TXMSG, &Msg[1], Len - 1); // include Control
+ MHPROC(TXMSG->Data, TXMSG->Length);
+
analiz_frame(Chan, TXMSG, socket, 0);
free(TXMSG);
@@ -3019,6 +3021,221 @@ char * frame_monitor(string * frame, char * code, int tx_stat)
return FrameData;
}
+typedef struct _MHSTRUC
+{
+ UCHAR MHCALL[7];
+ UCHAR MHDIGIS[7][8];
+ time_t MHTIME;
+ int MHCOUNT;
+ unsigned char MHDIGI;
+ char MHFreq[12];
+ char MHLocator[6];
+} MHSTRUC, *PMHSTRUC;
+
+
+#define MHENTRIES 30
+
+MHSTRUC MHEARD[(MHENTRIES + 1) * sizeof(MHSTRUC)] = { 0 };
+
+int CompareCalls(UCHAR * c1, UCHAR * c2)
+{
+ // COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID
+
+ if (memcmp(c1, c2, 6))
+ return FALSE; // No Match
+
+ if ((c1[6] & 0x1e) == (c2[6] & 0x1e))
+ return TRUE;
+
+ return FALSE;
+}
+
+static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+void * MHWindow = 0;
+void WritetoMHWindow(char * Buffer);
+int KISSMH = 0;
+
+char * FormatMH(PMHSTRUC MH)
+{
+ struct tm * TM;
+ static char MHTime[50];
+ time_t szClock;
+ char LOC[7];
+
+ memcpy(LOC, MH->MHLocator, 6);
+ LOC[6] = 0;
+
+ szClock = MH->MHTIME;
+// else
+// szClock = time(NULL) - MH->MHTIME;
+
+ TM = gmtime(&szClock);
+
+ sprintf(MHTime, "%s %02d %.2d:%.2d:%.2d %s %s",
+ month[TM->tm_mon], TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC);
+
+ return MHTime;
+}
+
+
+
+
+void MHPROC(unsigned char * Packet, int Len)
+{
+ PMHSTRUC MH = &MHEARD[0];
+ PMHSTRUC MHBASE = MH;
+ int i;
+ int OldCount = 0;
+ char Freq[64] = "";
+ char DIGI = '*';
+
+ MESSAGE Frame;
+ MESSAGE * Buffer = &Frame;
+
+ memcpy(Buffer->DEST, Packet, Len);
+
+
+ // if port has a freq associated with it use it
+
+
+ // if (Buffer->ORIGIN[6] & 1)
+ DIGI = 0; // Don't think we want to do this
+
+// See if in list
+
+ for (i = 0; i < MHENTRIES; i++)
+ {
+ if ((MH->MHCALL[0] == 0) || (CompareCalls(Buffer->ORIGIN, MH->MHCALL) && MH->MHDIGI == DIGI)) // Spare or our entry
+ {
+ OldCount = MH->MHCOUNT;
+ goto DoMove;
+ }
+ MH++;
+ }
+
+ // TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP
+
+ i = MHENTRIES - 1;
+
+ // Move others down and add at front
+DoMove:
+ if (i != 0) // First
+ memmove(MHBASE + 1, MHBASE, i * sizeof(MHSTRUC));
+
+ memcpy(MHBASE->MHCALL, Buffer->ORIGIN, 7 * 9); // Save Digis
+ MHBASE->MHDIGI = DIGI;
+ MHBASE->MHTIME = time(NULL);
+ MHBASE->MHCOUNT = ++OldCount;
+ strcpy(MHBASE->MHFreq, Freq);
+ MHBASE->MHLocator[0] = 0;
+
+ if (MHWindow)
+ {
+ int count = MHENTRIES;
+ int n;
+ char Normcall[20];
+ char From[10];
+ char DigiList[100];
+ char * Output;
+ int len;
+ char Digi = 0;
+ char MHPage[MHENTRIES * 100];
+ char * Bufferptr = MHPage;
+ unsigned char * ptr;
+
+ MH = &MHEARD[0];
+
+ // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find
+ // how many digis there are
+
+ Bufferptr += sprintf(Bufferptr, "Callsign Last heard Pkts RX via Digi\r");
+ Bufferptr += sprintf(Bufferptr, "\r");
+
+ while (count--)
+ {
+ if (MH->MHCALL[0] == 0)
+ break;
+
+ Digi = 0;
+
+ len = ConvFromAX25(MH->MHCALL, Normcall);
+
+ Normcall[len++] = MH->MHDIGI;
+ Normcall[len++] = 0;
+
+ n = 8; // Max number of digi-peaters
+
+ ptr = &MH->MHCALL[6]; // End of Address bit
+
+ Output = &DigiList[0];
+
+ if ((*ptr & 1) == 0)
+ {
+ // at least one digi
+
+ strcpy(Output, "via ");
+ Output += 4;
+
+ while ((*ptr & 1) == 0)
+ {
+ // MORE TO COME
+
+ From[ConvFromAX25(ptr + 1, From)] = 0;
+ Output += sprintf((char *)Output, "%s", From);
+
+ ptr += 7;
+ n--;
+
+ if (n == 0)
+ break;
+
+ // See if digi actioned - put a * on last actioned
+
+ if (*ptr & 0x80)
+ {
+ if (*ptr & 1) // if last address, must need *
+ {
+ *(Output++) = '*';
+ Digi = '*';
+ }
+
+ else
+ if ((ptr[7] & 0x80) == 0) // Repeased by next?
+ {
+ *(Output++) = '*'; // No, so need *
+ Digi = '*';
+ }
+
+ }
+ *(Output++) = ',';
+ }
+ *(--Output) = 0; // remove last comma
+ }
+ else
+ *(Output) = 0;
+
+ // if we used a digi set * on call and display via string
+
+
+ if (Digi)
+ Normcall[len++] = Digi;
+ else
+ DigiList[0] = 0; // Dont show list if not used
+
+ Normcall[len++] = 0;
+
+ ptr = FormatMH(MH);
+
+ Bufferptr += sprintf(Bufferptr, "%-10s %-10s %-10d %-30s\r", Normcall, ptr, MH->MHCOUNT, DigiList);
+
+ MH++;
+ }
+
+ WritetoMHWindow(MHPage);
+ }
+ return;
+}
diff --git a/debug/moc_predefs.h b/debug/moc_predefs.h
index 8247e15..b90fa38 100644
--- a/debug/moc_predefs.h
+++ b/debug/moc_predefs.h
@@ -1,7 +1,7 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
-#define _MSC_FULL_VER 191627043
+#define _MSC_FULL_VER 191627051
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600
diff --git a/release/moc_predefs.h b/release/moc_predefs.h
index b1c49a8..24cfab5 100644
--- a/release/moc_predefs.h
+++ b/release/moc_predefs.h
@@ -1,7 +1,7 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
-#define _MSC_FULL_VER 191627045
+#define _MSC_FULL_VER 191627051
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600