/* Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO This file is part of QtSoundModem QtSoundModem is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. QtSoundModem is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QtSoundModem. If not, see http://www.gnu.org/licenses */ // UZ7HO Soundmodem Port by John Wiseman G8BPQ #include "UZ7HOStuff.h" int add_raw_frames(int snd_ch, string * frame, TStringList * buf); // I think I need a struct for each connection, but a simple array of entries should be fine // My normal ** and count system // Each needs an input buffer of max size kiss frame and length (or maybe string is a good idea) TKISSMode ** KissConnections = NULL; int KISSConCount = 0; #define FEND 0xc0 #define FESC 0xDB #define TFEND 0xDC #define TFESC 0xDD #define KISS_ACKMODE 0x0C #define KISS_DATA 0 #define QTSMKISSCMD 7 struct TKISSMode_t KISS; int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON); void KISS_init() { int i; KISS.data_in = newString(); // initTStringList(KISS.socket); for (i = 0; i < 4; i++) { initTStringList(&KISS.buffer[i]); } } /* procedure KISS_free; var i: byte; begin KISS.data_in.Free; KISS.socket.Free; for i:=1 to 4 do begin KISS.buffer[i].Free; KISS.request[i].Free; KISS.acked[i].Free; KISS.irequest[i].Free; KISS.iacked[i].Free; end; end; */ void KISS_add_stream(void * Socket) { // Add a new connection. Called when QT accepts an incoming call} TKISSMode * KISS; KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *)); KISS = KissConnections[KISSConCount++] = malloc(sizeof(*KISS)); memset(KISS, 0, sizeof(*KISS)); KISS->Socket = Socket; KISS->data_in = newString(); } void KISS_del_socket(void * socket) { int i; TKISSMode * KISS = NULL; if (KISSConCount == 0) return; for (i = 0; i < KISSConCount; i++) { if (KissConnections[i]->Socket == socket) { KISS = KissConnections[i]; break; } } if (KISS == NULL) return; // Need to remove entry and move others down KISSConCount--; while (i < KISSConCount) { KissConnections[i] = KissConnections[i + 1]; i++; } } void KISS_on_data_out(int port, string * frame, int TX) { int Len; UCHAR * KISSFrame = (UCHAR *)malloc(512); // cant pass local data via signal/slot Len = KISS_encode(KISSFrame, port, frame, TX); KISSSendtoServer(NULL, KISSFrame, Len); // Send to all open sockets } void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) { int n = Len; UCHAR c; int ESCFLAG = 0; UCHAR * ptr1, *ptr2; int Chan; int Opcode; string * TXMSG; unsigned short CRC; UCHAR CRCString[2]; ptr1 = ptr2 = Msg; while (n--) { c = *(ptr1++); if (ESCFLAG) { // // FESC received - next should be TFESC or TFEND ESCFLAG = 0; if (c == TFESC) c = FESC; if (c == TFEND) c = FEND; } else { switch (c) { case FEND: // // Either start of message or message complete // // npKISSINFO->MSGREADY = TRUE; return; case FESC: ESCFLAG = 1; continue; } } // // Ok, a normal char // *(ptr2++) = c; } Len = ptr2 - Msg; Chan = (Msg[0] >> 4); Opcode = Msg[0] & 0x0f; if (Chan > 3) return; switch (Opcode) { case KISS_ACKMODE: // How best to do ACKMODE?? I think pass whole frame including CMD and ack bytes to all_frame_buf // But ack should only be sent to client that sent the message - needs more thought! TXMSG = newString(); stringAdd(TXMSG, &Msg[0], Len); // include Control CRC = get_fcs(&Msg[3], Len - 3); // exclude control and ack bytes CRCString[0] = CRC & 0xff; CRCString[1] = CRC >> 8; stringAdd(TXMSG, CRCString, 2); // Ackmode needs to know where to send ack back to, so save socket on end of data stringAdd(TXMSG, (unsigned char * )&socket, sizeof(socket)); // if KISS Optimise see if frame is really needed if (!KISS_opt[Chan]) Add(&KISS.buffer[Chan], TXMSG); else { if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) Add(&KISS.buffer[Chan], TXMSG); } return; case KISS_DATA: TXMSG = newString(); stringAdd(TXMSG, &Msg[0], Len); // include Control CRC = get_fcs(&Msg[1], Len - 1); CRCString[0] = CRC & 0xff; CRCString[1] = CRC >> 8; stringAdd(TXMSG, CRCString, 2); // if KISS Optimise see if frame is really needed if (!KISS_opt[Chan]) Add(&KISS.buffer[Chan], TXMSG); else { if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) Add(&KISS.buffer[Chan], TXMSG); } return; } // Still need to process kiss control frames } void KISSDataReceived(void * socket, UCHAR * data, int length) { int i; UCHAR * ptr1, * ptr2; int Length; TKISSMode * KISS = NULL; if (KISSConCount == 0) return; for (i = 0; i < KISSConCount; i++) { if (KissConnections[i]->Socket == socket) { KISS = KissConnections[i]; break; } } if (KISS == NULL) return; stringAdd(KISS->data_in, data, length); if (KISS->data_in->Length > 10000) // Probably AGW Data on KISS Port { KISS->data_in->Length = 0; return; } ptr1 = KISS->data_in->Data; Length = KISS->data_in->Length; while ((ptr2 = memchr(ptr1, FEND, Length))) { int Len = (ptr2 - ptr1); if (Len == 0) { // Start of frame mydelete(KISS->data_in, 0, 1); ptr1 = KISS->data_in->Data; Length = KISS->data_in->Length; continue; } // Process Frame if (Len < 350) // Drop obviously corrupt frames ProcessKISSFrame(socket, ptr1, Len); mydelete(KISS->data_in, 0, Len + 1); ptr1 = KISS->data_in->Data; Length = KISS->data_in->Length; } /* if (length(KISS.data_in.Strings[idx]) > 65535) if Form1.ServerSocket2.Socket.ActiveConnections > 0) for i:=0 to Form1.ServerSocket2.Socket.ActiveConnections-1 do if Form1.ServerSocket2.Socket.Connections[i].SocketHandle=socket then try Form1.ServerSocket2.Socket.Connections[i].Close; except end; */ } int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON) { // Encode frame UCHAR * ptr1 = frame->Data; UCHAR TXCCC = 0; int Len = frame->Length - 2; // frame includes CRC UCHAR * ptr2 = &KISSBuffer[2]; UCHAR c; if (TXMON) { // TX Frame has control byte on front ptr1++; Len--; } KISSBuffer[0] = FEND; KISSBuffer[1] = port << 4; TXCCC ^= KISSBuffer[1]; while (Len--) { c = *(ptr1++); TXCCC ^= c; switch (c) { case FEND: (*ptr2++) = FESC; (*ptr2++) = TFEND; break; case FESC: (*ptr2++) = FESC; (*ptr2++) = TFESC; break; // Drop through default: (*ptr2++) = c; } } // If using checksum, send it /* if (KISSFLAGS & CHECKSUM) { c = (UCHAR)KISS->TXCCC; // On TNC-X based boards, it is difficult to cope with an encoded CRC, so if // CRC is FEND, send it as 0xc1. This means we have to accept 00 or 01 as valid. // which is a slight loss in robustness if (c == FEND && (PORT->KISSFLAGS & TNCX)) { (*ptr2++) = FEND + 1; } else { switch (c) { case FEND: (*ptr2++) = FESC; (*ptr2++) = TFEND; break; case FESC: (*ptr2++) = FESC; (*ptr2++) = TFESC; break; default: (*ptr2++) = c; } } } */ (*ptr2++) = FEND; return (int)(ptr2 - KISSBuffer); } void sendAckModeAcks(int snd_ch) { // format and send any outstanding acks string * temp; UCHAR * Msg; void * socket; while (KISS_acked[snd_ch].Count) { UCHAR * ACK = (UCHAR *)malloc(15); UCHAR * ackptr = ACK; temp = Strings(&KISS_acked[snd_ch], 0); // get first Msg = temp->Data; *ackptr++ = FEND; *ackptr++ = Msg[0]; // opcode and channel *ackptr++ = Msg[1]; *ackptr++ = Msg[2]; // ACK Bytes *ackptr++ = FEND; // Socket to reply to is on end Msg += (temp->Length - sizeof(void *)); memcpy(&socket, Msg, sizeof(void *)); KISSSendtoServer(socket, ACK, 5); Delete(&KISS_acked[snd_ch], 0); // This will invalidate temp } }