Packet resending implemented. Not very tested.
This commit is contained in:
parent
a07a61b5dd
commit
10f5da9595
15 changed files with 361 additions and 552 deletions
|
@ -16,8 +16,6 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
#CONFIG *= testing
|
|
||||||
|
|
||||||
# NOTE: You'll occasionally find a file with a capital "C" extension.
|
# NOTE: You'll occasionally find a file with a capital "C" extension.
|
||||||
# These are C files that we want ignored by the DOS compiler.
|
# These are C files that we want ignored by the DOS compiler.
|
||||||
|
|
||||||
|
@ -115,7 +113,6 @@ SOURCES = \
|
||||||
src/system/surface.c \
|
src/system/surface.c \
|
||||||
src/system/taglist.c \
|
src/system/taglist.c \
|
||||||
$$SHARED/util.c \
|
$$SHARED/util.c \
|
||||||
src/test.c \
|
|
||||||
$$SHARED/array.c \
|
$$SHARED/array.c \
|
||||||
$$SHARED/log.c \
|
$$SHARED/log.c \
|
||||||
src/system/timer.c \
|
src/system/timer.c \
|
||||||
|
@ -151,10 +148,4 @@ OTHER_FILES = \
|
||||||
../test.conf \
|
../test.conf \
|
||||||
postBuild.sh
|
postBuild.sh
|
||||||
|
|
||||||
testing {
|
|
||||||
DEFINES *= TESTING
|
|
||||||
HEADERS += src/test.h
|
|
||||||
SOURCES += src/test.c
|
|
||||||
}
|
|
||||||
|
|
||||||
QMAKE_POST_LINK = $$PWD/postBuild.sh "$$PWD" "$$DESTDIR"
|
QMAKE_POST_LINK = $$PWD/postBuild.sh "$$PWD" "$$DESTDIR"
|
||||||
|
|
|
@ -49,25 +49,118 @@
|
||||||
|
|
||||||
#include "welcome.h"
|
#include "welcome.h"
|
||||||
|
|
||||||
#ifdef TESTING
|
|
||||||
#include "test.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
|
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
|
||||||
|
|
||||||
|
|
||||||
|
static void taskComDebugLoop(void *data);
|
||||||
static void taskGuiEventLoop(void *data);
|
static void taskGuiEventLoop(void *data);
|
||||||
|
|
||||||
|
|
||||||
|
#include "comport.h"
|
||||||
|
static void taskComDebugLoop(void *data) {
|
||||||
|
int32_t r;
|
||||||
|
int32_t x;
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
// Open COM port.
|
||||||
|
logWrite("Opening COM\n");
|
||||||
|
r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
|
||||||
|
if (r != SER_SUCCESS) {
|
||||||
|
logWrite("Unable to open COM port! Please check settings.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Send a CR to clear anything in the modem.
|
||||||
|
logWrite("Clearing modem buffer\n");
|
||||||
|
snprintf(buffer, 1023, "%c", 13);
|
||||||
|
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||||
|
// Wait roughly a second for anything.
|
||||||
|
comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "weExpectNothing");
|
||||||
|
// Send actual init
|
||||||
|
logWrite("Init modem\n");
|
||||||
|
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
|
||||||
|
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||||
|
// Wait roughly a second for "OK".
|
||||||
|
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "\rOK\r");
|
||||||
|
if (r <= 0) {
|
||||||
|
comClose(__configData.serialCom - 1);
|
||||||
|
logWrite("Modem does not support ENET! Please check settings.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logWrite("Modem OK\n");
|
||||||
|
// Flush COM port.
|
||||||
|
timerQuarterSecondsWait(4);
|
||||||
|
comReceiveBufferFlush(__configData.serialCom - 1);
|
||||||
|
|
||||||
|
// Show dialing, dial service.
|
||||||
|
logWrite("Dialing\n");
|
||||||
|
snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
|
||||||
|
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||||
|
// Wait 7 seconds for welcome banner.
|
||||||
|
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4 * 7, "KPMPGSMKII\r");
|
||||||
|
if (r <= 0) {
|
||||||
|
comClose(__configData.serialCom - 1);
|
||||||
|
logWrite("Unable to connect to server! Please check settings or try later.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connected! Show icon and negotiate session.
|
||||||
|
logWrite("Connected\n");
|
||||||
|
|
||||||
|
PacketEncodeDataT encoded = { 0 };
|
||||||
|
PacketDecodeDataT decoded = { 0 };
|
||||||
|
|
||||||
|
// Send it 10 times, waiting for a PONG between each.
|
||||||
|
for (x=0; x<10; x++) {
|
||||||
|
// Send PING.
|
||||||
|
logWrite("Sending PING %d\n", x);
|
||||||
|
encoded.control = PACKET_CONTROL_DAT;
|
||||||
|
encoded.packetType = PACKET_TYPE_PING;
|
||||||
|
encoded.channel = 1;
|
||||||
|
encoded.encrypt = 0;
|
||||||
|
packetEncode(__packetThreadData, &encoded, NULL, 0); // Must encode each packet - no reusing encoded data.
|
||||||
|
packetSend(__packetThreadData, &encoded);
|
||||||
|
// Wait for PONG.
|
||||||
|
while (1) {
|
||||||
|
r = comRead(__configData.serialCom - 1, buffer, 1);
|
||||||
|
if (r == 1) {
|
||||||
|
if (packetDecode(__packetThreadData, &decoded, buffer, 1)) {
|
||||||
|
if (decoded.packetType == PACKET_TYPE_PONG) {
|
||||||
|
logWrite("Received PONG\n");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logWrite("Unexpected packet type received %d\n", decoded.packetType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskYield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send CLIENT_SHUTDOWN.
|
||||||
|
logWrite("Sending CLIENT_SHUTDOWN\n");
|
||||||
|
encoded.control = PACKET_CONTROL_DAT;
|
||||||
|
encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
|
||||||
|
encoded.channel = 1;
|
||||||
|
encoded.encrypt = 0;
|
||||||
|
packetEncode(__packetThreadData, &encoded, NULL, 0);
|
||||||
|
packetSend(__packetThreadData, &encoded);
|
||||||
|
|
||||||
|
logWrite("Sleeping\n");
|
||||||
|
timerQuarterSecondsWait(8);
|
||||||
|
|
||||||
|
logWrite("COM closed\n");
|
||||||
|
comClose(__configData.serialCom - 1);
|
||||||
|
guiStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void taskGuiEventLoop(void *data) {
|
static void taskGuiEventLoop(void *data) {
|
||||||
MouseT *mouse = NULL;
|
MouseT *mouse = NULL;
|
||||||
ImageT *pointer = NULL;
|
ImageT *pointer = NULL;
|
||||||
ColorT alpha;
|
ColorT alpha;
|
||||||
#ifdef TESTING
|
|
||||||
int8_t debugState = 0;
|
|
||||||
int8_t key = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
||||||
|
@ -78,34 +171,16 @@ static void taskGuiEventLoop(void *data) {
|
||||||
timerUpdate();
|
timerUpdate();
|
||||||
mouse = mouseRead();
|
mouse = mouseRead();
|
||||||
if (keyHit()) {
|
if (keyHit()) {
|
||||||
#ifdef TESTING
|
|
||||||
lastKey = keyASCIIGet(); //***DEBUG***
|
|
||||||
#endif
|
|
||||||
guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet());
|
guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet());
|
||||||
//logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
|
//logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
|
||||||
}
|
}
|
||||||
guiMouseProcess(mouse);
|
guiMouseProcess(mouse);
|
||||||
guiComposite();
|
guiComposite();
|
||||||
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
|
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
|
||||||
|
|
||||||
#ifdef TESTING
|
|
||||||
if (key == '=') guiDebugWidgetTreeDump(guiRootGet(), 0);
|
|
||||||
if (key == '+') {
|
|
||||||
debugState++;
|
|
||||||
if (debugState > 2) debugState = 0;
|
|
||||||
}
|
|
||||||
if (debugState > 0) widgetDebugDraw(guiRootGet(), debugState - 1);
|
|
||||||
//if (timerHalfSecondOn) guiDrawRectangle(0, 0, vbeSurfaceWidthGet() - 1, vbeSurfaceHeightGet() - 1, vbeMakeColor(255, 255, 255));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vbeVBlankWait();
|
vbeVBlankWait();
|
||||||
vbePresent();
|
vbePresent();
|
||||||
taskYield();
|
taskYield();
|
||||||
#ifdef TESTING
|
|
||||||
} while (key != 27); // Exit on ESC.
|
|
||||||
#else
|
|
||||||
} while (!guiHasStopped());
|
} while (!guiHasStopped());
|
||||||
#endif
|
|
||||||
|
|
||||||
imageUnload(&pointer);
|
imageUnload(&pointer);
|
||||||
}
|
}
|
||||||
|
@ -152,31 +227,15 @@ int main(int argc, char *argv[]) {
|
||||||
guiStartup();
|
guiStartup();
|
||||||
taskStartup();
|
taskStartup();
|
||||||
|
|
||||||
__packetThreadData = packetThreadDataCreate();
|
__packetThreadData = packetThreadDataCreate(NULL);
|
||||||
|
packetSenderRegister(comPacketSender);
|
||||||
|
|
||||||
#ifdef TESTING
|
taskCreate(taskComDebugLoop, NULL);
|
||||||
taskCreate(comPortScanTest, NULL);
|
//taskCreate(taskWelcome, NULL);
|
||||||
#else
|
|
||||||
taskCreate(taskWelcome, NULL);
|
|
||||||
taskCreate(taskGuiEventLoop, NULL);
|
taskCreate(taskGuiEventLoop, NULL);
|
||||||
#endif
|
|
||||||
|
|
||||||
taskRun();
|
taskRun();
|
||||||
|
|
||||||
/*
|
|
||||||
char *testPacket = "Hello Server!";
|
|
||||||
PacketEncodeDataT encoded;
|
|
||||||
encoded.control = PACKET_CONTROL_DAT;
|
|
||||||
encoded.packetType = PACKET_TYPE_TEST;
|
|
||||||
encoded.channel = 1;
|
|
||||||
encoded.encrypt = 0;
|
|
||||||
packetEncode(__packetThreadData, &encoded, testPacket, strlen(testPacket));
|
|
||||||
logWrite("Encoded %d bytes (raw length %d)\n", encoded.length, strlen(testPacket));
|
|
||||||
PacketDecodeDataT decoded;
|
|
||||||
packetDecode(__packetThreadData, &decoded, encoded.dataPointer, encoded.length);
|
|
||||||
logWrite("Decoded %d bytes (raw length %d)\n", decoded.length, encoded.length);
|
|
||||||
*/
|
|
||||||
|
|
||||||
packetThreadDataDestroy(&__packetThreadData);
|
packetThreadDataDestroy(&__packetThreadData);
|
||||||
|
|
||||||
taskShutdown();
|
taskShutdown();
|
||||||
|
|
|
@ -21,6 +21,14 @@
|
||||||
#include "comport.h"
|
#include "comport.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
void comPacketSender(char *data, uint32_t length, void *userData) {
|
||||||
|
(void)userData;
|
||||||
|
|
||||||
|
comWrite(__configData.serialCom - 1, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int comReceiveBufferFlush(int com) {
|
int comReceiveBufferFlush(int com) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -52,8 +53,9 @@ int comWrite(int com, const char *data, int len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int comReceiveBufferFlush(int com);
|
void comPacketSender(char *data, uint32_t length, void *userData);
|
||||||
int comWaitWithTimeout(int com, char *buffer, int len, int quarterSeconds, char *expecting);
|
int comReceiveBufferFlush(int com);
|
||||||
|
int comWaitWithTimeout(int com, char *buffer, int len, int quarterSeconds, char *expecting);
|
||||||
|
|
||||||
|
|
||||||
#endif // COMPORT_H
|
#endif // COMPORT_H
|
||||||
|
|
|
@ -1,370 +0,0 @@
|
||||||
/*
|
|
||||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
|
||||||
* Copyright (C) 2020-2021 Scott Duensing
|
|
||||||
*
|
|
||||||
* This program 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.
|
|
||||||
*
|
|
||||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
#include "task.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "widget.h"
|
|
||||||
#include "desktop.h"
|
|
||||||
#include "window.h"
|
|
||||||
#include "button.h"
|
|
||||||
#include "label.h"
|
|
||||||
#include "checkbox.h"
|
|
||||||
#include "radio.h"
|
|
||||||
#include "picture.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "textbox.h"
|
|
||||||
#include "updown.h"
|
|
||||||
#include "listbox.h"
|
|
||||||
#include "terminal.h"
|
|
||||||
|
|
||||||
#include "taglist.h"
|
|
||||||
#include "comport.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t _lastKey = 0;
|
|
||||||
|
|
||||||
static TerminalT *_t1 = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static void buttonClick(WidgetT *widget);
|
|
||||||
//static void test(void *data);
|
|
||||||
static void testTerminal(void *data);
|
|
||||||
|
|
||||||
|
|
||||||
static void buttonClick(WidgetT *widget) {
|
|
||||||
logWrite("'%s' was clicked.\n", ((ButtonT *)widget)->title);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void comPortScanTest(void *data) {
|
|
||||||
int rc;
|
|
||||||
int len;
|
|
||||||
char buffer[1024];
|
|
||||||
|
|
||||||
(void)data;
|
|
||||||
|
|
||||||
for (int x=0; x<4; x++) {
|
|
||||||
rc = comOpen(x, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
|
|
||||||
if (rc == SER_SUCCESS) {
|
|
||||||
logWrite("COM%d exists!\n", x + 1);
|
|
||||||
snprintf(buffer, 1024, "%s%c", "AT+SOCK1", 13);
|
|
||||||
comWrite(x, buffer, strlen(buffer));
|
|
||||||
sleep(1);
|
|
||||||
len = comRead(x, buffer, 1024);
|
|
||||||
buffer[len] = 0;
|
|
||||||
if (strstr(buffer, "OK")) {
|
|
||||||
logWrite("ENET SoftModem found!\n");
|
|
||||||
} else {
|
|
||||||
logWrite("Result: [%s]\n", buffer);
|
|
||||||
}
|
|
||||||
comClose(x);
|
|
||||||
} else {
|
|
||||||
logWrite("No COM%d.\n", x + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guiStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
static void test(void *data) {
|
|
||||||
DesktopT *desktop = (DesktopT *)guiRootGet();
|
|
||||||
WindowT *w1 = NULL;
|
|
||||||
WindowT *w2 = NULL;
|
|
||||||
WindowT *w3 = NULL;
|
|
||||||
WindowT *w4 = NULL;
|
|
||||||
ButtonT *b1 = NULL;
|
|
||||||
LabelT *l1 = NULL;
|
|
||||||
CheckboxT *c1 = NULL;
|
|
||||||
RadioT *r1a = NULL;
|
|
||||||
RadioT *r2a = NULL;
|
|
||||||
RadioT *r3a = NULL;
|
|
||||||
RadioT *r1b = NULL;
|
|
||||||
RadioT *r2b = NULL;
|
|
||||||
RadioT *r3b = NULL;
|
|
||||||
PictureT *p1 = NULL;
|
|
||||||
FrameT *f1 = NULL;
|
|
||||||
TextboxT *tb1 = NULL;
|
|
||||||
TextboxT *tb2 = NULL;
|
|
||||||
UpdownT *u1 = NULL;
|
|
||||||
ListboxT *lb1 = NULL;
|
|
||||||
|
|
||||||
(void)data;
|
|
||||||
|
|
||||||
// Windows
|
|
||||||
w1 = windowNew(300, 25, 300, 200, "Window 1");
|
|
||||||
guiAttach(W(desktop), W(w1));
|
|
||||||
w2 = windowNew(150, 150, 300, 200, "Window 2");
|
|
||||||
guiAttach(W(desktop), W(w2));
|
|
||||||
w3 = windowNew(300, 300, 300, 200, "Window 3");
|
|
||||||
guiAttach(W(desktop), W(w3));
|
|
||||||
w4 = windowNew(10, 10, 7 + 8 + (80 * 8), 26 + 8 + (24 * 14), "Terminal");
|
|
||||||
guiAttach(W(desktop), W(w4));
|
|
||||||
|
|
||||||
// Window 1
|
|
||||||
p1 = pictureNew(0, 0, "data/kanga.png");
|
|
||||||
guiAttach(W(w1), W(p1));
|
|
||||||
lb1 = listboxNew(155, 10, 120, 140, "List Box");
|
|
||||||
listboxItemAdd(lb1, "One");
|
|
||||||
listboxItemAdd(lb1, "Two");
|
|
||||||
listboxItemAdd(lb1, "Three");
|
|
||||||
listboxItemAdd(lb1, "Four");
|
|
||||||
listboxItemAdd(lb1, "Five");
|
|
||||||
listboxItemAdd(lb1, "Six");
|
|
||||||
listboxItemAdd(lb1, "Seven");
|
|
||||||
listboxItemAdd(lb1, "Eight");
|
|
||||||
listboxItemAdd(lb1, "Nine");
|
|
||||||
listboxItemAdd(lb1, "Ten");
|
|
||||||
listboxStepSet(lb1, 3);
|
|
||||||
guiAttach(W(w1), W(lb1));
|
|
||||||
|
|
||||||
// Window 2
|
|
||||||
r1a = radioNew(10, 10, "Radio 1a", 1);
|
|
||||||
guiAttach(W(w2), W(r1a));
|
|
||||||
r2a = radioNew(20 + widgetWidthGet(W(r1a)), 10, "Radio 2a", 1);
|
|
||||||
guiAttach(W(w2), W(r2a));
|
|
||||||
r3a = radioNew(30 + widgetWidthGet(W(r1a)) + widgetWidthGet(W(r2a)), 10, "Radio 3a", 1);
|
|
||||||
guiAttach(W(w2), W(r3a));
|
|
||||||
r1b = radioNew(10, 35, "Radio 1b", 2);
|
|
||||||
guiAttach(W(w2), W(r1b));
|
|
||||||
r2b = radioNew(20 + widgetWidthGet(W(r1b)), 35, "Radio 2b", 2);
|
|
||||||
guiAttach(W(w2), W(r2b));
|
|
||||||
r3b = radioNew(30 + widgetWidthGet(W(r1b)) + widgetWidthGet(W(r2b)), 35, "Radio 3b", 2);
|
|
||||||
guiAttach(W(w2), W(r3b));
|
|
||||||
radioSelectedSet(r1a);
|
|
||||||
radioSelectedSet(r2b);
|
|
||||||
tb1 = textboxNew(10, 60, 265, "Test Textbox");
|
|
||||||
textboxValueSet(tb1, "Really long text string to edit!");
|
|
||||||
guiAttach(W(w2), W(tb1));
|
|
||||||
tb2 = textboxNew(10, 85, 265, "Test Textbox");
|
|
||||||
textboxValueSet(tb2, "Short string.");
|
|
||||||
guiAttach(W(w2), W(tb2));
|
|
||||||
u1 = updownNew(10, 110, 0, 1024, 5, "UpDown");
|
|
||||||
guiAttach(W(w2), W(u1));
|
|
||||||
|
|
||||||
// Window 3
|
|
||||||
f1 = frameNew(10, 5, 175, 125, "Test Frame");
|
|
||||||
guiAttach(W(w3), W(f1));
|
|
||||||
b1 = buttonNew(0, 0, "Test Button", buttonClick);
|
|
||||||
guiAttach(W(f1), W(b1));
|
|
||||||
l1 = labelNew(10, 40, "Test Label");
|
|
||||||
guiAttach(W(f1), W(l1));
|
|
||||||
c1 = checkboxNew(10, 65, "Test Checkbox");
|
|
||||||
guiAttach(W(f1), W(c1));
|
|
||||||
|
|
||||||
// Window 4 - Terminal
|
|
||||||
t1 = terminalNew(0, 0, 80, 24);
|
|
||||||
guiAttach(W(w4), W(t1));
|
|
||||||
|
|
||||||
taskCreate(testTerminal, "terminalTest");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void taskTestTagList(void *data) {
|
|
||||||
WindowT *w1 = NULL;
|
|
||||||
WindowT *w2 = NULL;
|
|
||||||
WindowT *w3 = NULL;
|
|
||||||
WindowT *w4 = NULL;
|
|
||||||
ButtonT *b1 = NULL;
|
|
||||||
LabelT *l1 = NULL;
|
|
||||||
CheckboxT *c1 = NULL;
|
|
||||||
RadioT *r1a = NULL;
|
|
||||||
RadioT *r2a = NULL;
|
|
||||||
RadioT *r3a = NULL;
|
|
||||||
RadioT *r1b = NULL;
|
|
||||||
RadioT *r2b = NULL;
|
|
||||||
RadioT *r3b = NULL;
|
|
||||||
PictureT *p1 = NULL;
|
|
||||||
FrameT *f1 = NULL;
|
|
||||||
TextboxT *tb1 = NULL;
|
|
||||||
TextboxT *tb2 = NULL;
|
|
||||||
UpdownT *u1 = NULL;
|
|
||||||
ListboxT *lb1 = NULL;
|
|
||||||
|
|
||||||
(void)data;
|
|
||||||
|
|
||||||
TagItemT ui[] = {
|
|
||||||
T_START,
|
|
||||||
|
|
||||||
T_WINDOW, O(w1),
|
|
||||||
T_TITLE, P("Window 1"),
|
|
||||||
T_X, 300, T_Y, 25, T_WIDTH, 300, T_HEIGHT, 200,
|
|
||||||
T_PICTURE, O(p1),
|
|
||||||
T_X, 0, T_Y, 0,
|
|
||||||
T_FILENAME, P("data/kanga.png"),
|
|
||||||
T_PICTURE, T_DONE,
|
|
||||||
T_LISTBOX, O(lb1),
|
|
||||||
T_TITLE, P("Listbox"),
|
|
||||||
T_X, 155, T_Y, 10, T_WIDTH, 120, T_HEIGHT, 140,
|
|
||||||
T_ITEM, P("One"),
|
|
||||||
T_ITEM, P("Two"),
|
|
||||||
T_ITEM, P("Three"),
|
|
||||||
T_ITEM, P("Four"),
|
|
||||||
T_ITEM, P("Five"),
|
|
||||||
T_ITEM, P("Six"),
|
|
||||||
T_ITEM, P("Seven"),
|
|
||||||
T_ITEM, P("Eight"),
|
|
||||||
T_ITEM, P("Nine"),
|
|
||||||
T_ITEM, P("Ten"),
|
|
||||||
T_STEP, 3,
|
|
||||||
T_LISTBOX, T_DONE,
|
|
||||||
T_WINDOW, T_DONE,
|
|
||||||
|
|
||||||
T_WINDOW, O(w2),
|
|
||||||
T_TITLE, P("Window 2"),
|
|
||||||
T_X, 150, T_Y, 150, T_WIDTH, 300, T_HEIGHT, 200,
|
|
||||||
T_RADIOBUTTON, O(r1a),
|
|
||||||
T_TITLE, P("Radio 1a"),
|
|
||||||
T_X, 10, T_Y, 10,
|
|
||||||
T_GROUP, 1,
|
|
||||||
T_SELECTED, 1,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_RADIOBUTTON, O(r2a),
|
|
||||||
T_TITLE, P("Radio 2a"),
|
|
||||||
T_X, 20 + 80, T_Y, 10,
|
|
||||||
T_GROUP, 1,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_RADIOBUTTON, O(r3a),
|
|
||||||
T_TITLE, P("Radio 3a"),
|
|
||||||
T_X, 30 + 80 * 2, T_Y, 10,
|
|
||||||
T_GROUP, 1,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_RADIOBUTTON, O(r1b),
|
|
||||||
T_TITLE, P("Radio 1b"),
|
|
||||||
T_X, 10, T_Y, 35,
|
|
||||||
T_GROUP, 2,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_RADIOBUTTON, O(r2b),
|
|
||||||
T_TITLE, P("Radio 2b"),
|
|
||||||
T_X, 20 + 80, T_Y, 35,
|
|
||||||
T_GROUP, 2,
|
|
||||||
T_SELECTED, 1,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_RADIOBUTTON, O(r3b),
|
|
||||||
T_TITLE, P("Radio 3b"),
|
|
||||||
T_X, 30 + 80 * 2, T_Y, 35,
|
|
||||||
T_GROUP, 2,
|
|
||||||
T_RADIOBUTTON, T_DONE,
|
|
||||||
T_TEXTBOX, O(tb1),
|
|
||||||
T_TITLE, P("Test Textbox"),
|
|
||||||
T_X, 10, T_Y, 60, T_WIDTH, 265,
|
|
||||||
T_VALUE, P("Really long text string to edit!"),
|
|
||||||
T_TEXTBOX, T_DONE,
|
|
||||||
T_TEXTBOX, O(tb2),
|
|
||||||
T_TITLE, P("Test Textbox"),
|
|
||||||
T_X, 10, T_Y, 85, T_WIDTH, 265,
|
|
||||||
T_VALUE, P("Short String."),
|
|
||||||
T_TEXTBOX, T_DONE,
|
|
||||||
T_UPDOWN, O(u1),
|
|
||||||
T_TITLE, P("UpDown"),
|
|
||||||
T_X, 10, T_Y, 120,
|
|
||||||
T_MINIMUM, 0, T_MAXIMUM, 1024, T_STEP, 5,
|
|
||||||
T_UPDOWN, T_DONE,
|
|
||||||
T_WINDOW, T_DONE,
|
|
||||||
|
|
||||||
T_WINDOW, O(w3),
|
|
||||||
T_TITLE, P("Window 3"),
|
|
||||||
T_X, 300, T_Y, 300, T_WIDTH, 300, T_HEIGHT, 200,
|
|
||||||
T_FRAME, O(f1),
|
|
||||||
T_TITLE, P("Test Frame"),
|
|
||||||
T_X, 10, T_Y, 5, T_WIDTH, 175, T_HEIGHT, 125,
|
|
||||||
T_BUTTON, O(b1),
|
|
||||||
T_TITLE, P("Test Button"),
|
|
||||||
T_X, 0, T_Y, 0,
|
|
||||||
T_CLICK, P(buttonClick),
|
|
||||||
T_BUTTON, T_DONE,
|
|
||||||
T_LABEL, O(l1),
|
|
||||||
T_TITLE, P("Test Label"),
|
|
||||||
T_X, 10, T_Y, 40,
|
|
||||||
T_LABEL, T_DONE,
|
|
||||||
T_CHECKBOX, O(c1),
|
|
||||||
T_TITLE, P("Test Checkbox"),
|
|
||||||
T_X, 10, T_Y, 65,
|
|
||||||
T_CHECKBOX, T_DONE,
|
|
||||||
T_FRAME, T_DONE,
|
|
||||||
T_WINDOW, T_DONE,
|
|
||||||
|
|
||||||
T_WINDOW, O(w4),
|
|
||||||
T_TITLE, P("Terminal"),
|
|
||||||
T_X, 10, T_Y, 10, T_WIDTH, 7 + 8 + (80 * 8), T_HEIGHT, 26 + 8 + (24 * 14),
|
|
||||||
T_TERMINAL, O(_t1),
|
|
||||||
T_X, 0, T_Y, 0, T_WIDTH, 80, T_HEIGHT, 24,
|
|
||||||
T_TERMINAL, T_DONE,
|
|
||||||
T_WINDOW, T_DONE,
|
|
||||||
|
|
||||||
T_END
|
|
||||||
};
|
|
||||||
|
|
||||||
tagListRun(ui);
|
|
||||||
|
|
||||||
taskCreate(testTerminal, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void testTerminal(void *data) {
|
|
||||||
FILE *in = NULL;
|
|
||||||
char *buffer = NULL;
|
|
||||||
uint16_t length = 0;
|
|
||||||
|
|
||||||
(void)data;
|
|
||||||
|
|
||||||
// Load ANSI file for terminal test.
|
|
||||||
in = fopen("data/kanga.ans", "rt");
|
|
||||||
fseek(in, 0, SEEK_END);
|
|
||||||
length = ftell(in);
|
|
||||||
fseek(in, 0, SEEK_SET);
|
|
||||||
buffer = (char *)malloc(length + 1);
|
|
||||||
fread(buffer, 1, length, in);
|
|
||||||
fclose(in);
|
|
||||||
buffer[length] = 0;
|
|
||||||
|
|
||||||
terminalStringPrint(_t1, buffer);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void widgetDebugDraw(WidgetT *widget, uint8_t debugToggle) {
|
|
||||||
size_t len = arrlenu(widget->children);
|
|
||||||
size_t i;
|
|
||||||
RectT r;
|
|
||||||
|
|
||||||
if (debugToggle) {
|
|
||||||
// Clipping region (blue)
|
|
||||||
guiWidgetBoundsDrawableOnScreenGet(widget, &r);
|
|
||||||
surfaceRectangleDraw(r.x, r.y, r.x + r.w, r.y + r.h, vbeColorMake(0, 0, 255));
|
|
||||||
} else {
|
|
||||||
// Widget border (red)
|
|
||||||
guiWidgetPositionOnScreenGet(widget, &r);
|
|
||||||
surfaceRectangleDraw(r.x, r.y, r.x + widget->pos.w, r.y + widget->pos.h, vbeColorMake(255, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
for (i=0; i<len; i++) {
|
|
||||||
widgetDebugDraw(widget->children[i], debugToggle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
|
||||||
* Copyright (C) 2020-2021 Scott Duensing
|
|
||||||
*
|
|
||||||
* This program 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.
|
|
||||||
*
|
|
||||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TEST_H
|
|
||||||
#define TEST_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
#include "terminal.h"
|
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t _lastKey;
|
|
||||||
|
|
||||||
|
|
||||||
void comPortScanTest(void *data);
|
|
||||||
void taskTestTagList(void *data);
|
|
||||||
void widgetDebugDraw(WidgetT *widget, uint8_t debugToggle);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // TEST_H
|
|
|
@ -132,16 +132,6 @@ static void taskConnectClick(void *data) {
|
||||||
// Connected! Show icon and negotiate session.
|
// Connected! Show icon and negotiate session.
|
||||||
widgetVisibleSet(W(_picConnect), 1);
|
widgetVisibleSet(W(_picConnect), 1);
|
||||||
taskYield();
|
taskYield();
|
||||||
|
|
||||||
char *testPacket = "Hello Server!";
|
|
||||||
PacketEncodeDataT encoded;
|
|
||||||
encoded.control = PACKET_CONTROL_DAT;
|
|
||||||
encoded.packetType = PACKET_TYPE_TEST;
|
|
||||||
encoded.channel = 1;
|
|
||||||
encoded.encrypt = 0;
|
|
||||||
packetEncode(__packetThreadData, &encoded, testPacket, strlen(testPacket));
|
|
||||||
comWrite(__configData.serialCom - 1, encoded.dataPointer, encoded.length);
|
|
||||||
logWrite("Sent %d bytes (raw length %d)\n", encoded.length, strlen(testPacket));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
|
||||||
static uint8_t clientDequeuePacket(ClientThreadT *client);
|
static uint8_t clientDequeuePacket(ClientThreadT *client);
|
||||||
|
@ -62,13 +63,29 @@ static uint8_t clientDequeuePacket(ClientThreadT *client) {
|
||||||
|
|
||||||
|
|
||||||
static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data) {
|
static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data) {
|
||||||
char temp[PACKET_MAX + 1] = { 0 };
|
PacketEncodeDataT encoded = { 0 };
|
||||||
uint16_t x = 0;
|
|
||||||
|
|
||||||
for (x=0; x<data->length; x++) temp[x] = data->data[x];
|
switch (data->packetType) {
|
||||||
temp[x] = 0;
|
case PACKET_TYPE_PING:
|
||||||
|
// Build PONG packet.
|
||||||
|
encoded.control = PACKET_CONTROL_DAT;
|
||||||
|
encoded.packetType = PACKET_TYPE_PONG;
|
||||||
|
encoded.channel = 1;
|
||||||
|
encoded.encrypt = 0;
|
||||||
|
packetEncode(client->packetThreadData, &encoded, NULL, 0);
|
||||||
|
// Send it.
|
||||||
|
packetSend(client->packetThreadData, &encoded);
|
||||||
|
logWrite("Got PING, sent PONG\n\r");
|
||||||
|
break;
|
||||||
|
|
||||||
consoleMessageQueue("%ld: Channel %d Packet %d [%s]\n", client->threadIndex, data->channel, data->packetType, temp);
|
case PACKET_TYPE_CLIENT_SHUTDOWN:
|
||||||
|
serverDisconnectClient(client);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
consoleMessageQueue("%ld: Channel %d Unknown Packet %d\n", client->threadIndex, data->channel, data->packetType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,14 +111,9 @@ void *clientThread(void *data) {
|
||||||
|
|
||||||
ENetPeer *peer = (ENetPeer *)data;
|
ENetPeer *peer = (ENetPeer *)data;
|
||||||
ClientThreadT *client = (ClientThreadT *)peer->data;
|
ClientThreadT *client = (ClientThreadT *)peer->data;
|
||||||
ENetPacket *packet = NULL;
|
|
||||||
struct timespec remaining = { 0, 0 };
|
struct timespec remaining = { 0, 0 };
|
||||||
struct timespec sleepTime = { 0, 1000000000/100 }; // 1/100th second.
|
struct timespec sleepTime = { 0, 1000000000/100 }; // 1/100th second.
|
||||||
|
|
||||||
// Send service banner.
|
|
||||||
packet = enet_packet_create("KPMPGSMKII\r", 11, ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
enet_peer_send(peer, 0, packet);
|
|
||||||
|
|
||||||
// Process packets until we're done.
|
// Process packets until we're done.
|
||||||
while (client->running) {
|
while (client->running) {
|
||||||
if (!clientDequeuePacket(client)) {
|
if (!clientDequeuePacket(client)) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ typedef struct ClientThreadS {
|
||||||
PacketThreadDataT *packetThreadData;
|
PacketThreadDataT *packetThreadData;
|
||||||
ClientRawPacketT **packetQueue;
|
ClientRawPacketT **packetQueue;
|
||||||
pthread_mutex_t packetQueueMutex;
|
pthread_mutex_t packetQueueMutex;
|
||||||
|
void *peer;
|
||||||
} ClientThreadT;
|
} ClientThreadT;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,35 @@ pthread_t _serverThreadHandle = { 0 };
|
||||||
void *_serverThreadStatus = NULL;
|
void *_serverThreadStatus = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void serverPacketSender(char *data, uint32_t length, void *userData);
|
||||||
|
|
||||||
|
|
||||||
|
void serverDisconnectClient(ClientThreadT *client) {
|
||||||
|
ENetPeer *peer = (ENetPeer *)client->peer;
|
||||||
|
void *status = NULL;
|
||||||
|
char buffer[2048] = { 0 };
|
||||||
|
|
||||||
|
// Stop client processing.
|
||||||
|
client->running = 0;
|
||||||
|
pthread_join(client->threadHandle, &status);
|
||||||
|
// Tell the console.
|
||||||
|
enet_address_get_host_ip(&peer->address, buffer, 2047);
|
||||||
|
consoleMessageQueue("%ld: [%s] disconnected.\n", client->threadIndex, buffer);
|
||||||
|
// Hang up.
|
||||||
|
enet_peer_reset(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void serverPacketSender(char *data, uint32_t length, void *userData) {
|
||||||
|
ENetPeer *peer = (ENetPeer *)userData;
|
||||||
|
ENetPacket *packet = NULL;
|
||||||
|
|
||||||
|
// Send packet.
|
||||||
|
packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
enet_peer_send(peer, 0, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void serverShutdown(void) {
|
void serverShutdown(void) {
|
||||||
pthread_join(_serverThreadHandle, &_serverThreadStatus);
|
pthread_join(_serverThreadHandle, &_serverThreadStatus);
|
||||||
enet_host_destroy(_server);
|
enet_host_destroy(_server);
|
||||||
|
@ -40,6 +69,9 @@ void serverStartup(uint32_t port, uint32_t maxClients) {
|
||||||
ENetAddress address = { 0 };
|
ENetAddress address = { 0 };
|
||||||
pthread_attr_t serverThreadAttributes = { 0 };
|
pthread_attr_t serverThreadAttributes = { 0 };
|
||||||
|
|
||||||
|
// Tell the packet code how to send packets.
|
||||||
|
packetSenderRegister(serverPacketSender);
|
||||||
|
|
||||||
// Set up listening socket.
|
// Set up listening socket.
|
||||||
address.host = ENET_HOST_ANY;
|
address.host = ENET_HOST_ANY;
|
||||||
address.port = port;
|
address.port = port;
|
||||||
|
@ -61,10 +93,10 @@ void serverStartup(uint32_t port, uint32_t maxClients) {
|
||||||
void *serverThread(void *data) {
|
void *serverThread(void *data) {
|
||||||
ENetHost *server = (ENetHost *)data;
|
ENetHost *server = (ENetHost *)data;
|
||||||
ENetEvent event = { 0 };
|
ENetEvent event = { 0 };
|
||||||
|
ENetPacket *packet = NULL;
|
||||||
ClientThreadT *client = NULL;
|
ClientThreadT *client = NULL;
|
||||||
uint64_t nextIndex = 0;
|
uint64_t nextIndex = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
void *status = NULL;
|
|
||||||
char buffer[2048] = { 0 };
|
char buffer[2048] = { 0 };
|
||||||
|
|
||||||
while (_running) {
|
while (_running) {
|
||||||
|
@ -77,7 +109,7 @@ void *serverThread(void *data) {
|
||||||
// Create new client.
|
// Create new client.
|
||||||
NEW(ClientThreadT, client);
|
NEW(ClientThreadT, client);
|
||||||
if (!client) utilDie("Unable to allocate new client.\n");
|
if (!client) utilDie("Unable to allocate new client.\n");
|
||||||
client->packetThreadData = packetThreadDataCreate();
|
client->packetThreadData = packetThreadDataCreate(event.peer);
|
||||||
if (!client->packetThreadData) {
|
if (!client->packetThreadData) {
|
||||||
utilDie("Unable to allocate packetThreadData for new client.\n");
|
utilDie("Unable to allocate packetThreadData for new client.\n");
|
||||||
break; // This break silences an invalid clang warning.
|
break; // This break silences an invalid clang warning.
|
||||||
|
@ -85,6 +117,7 @@ void *serverThread(void *data) {
|
||||||
client->threadIndex = nextIndex++;
|
client->threadIndex = nextIndex++;
|
||||||
client->running = 1;
|
client->running = 1;
|
||||||
client->packetQueue = NULL;
|
client->packetQueue = NULL;
|
||||||
|
client->peer = event.peer;
|
||||||
memset(&client->packetQueueMutex, 1, sizeof(pthread_mutex_t));
|
memset(&client->packetQueueMutex, 1, sizeof(pthread_mutex_t));
|
||||||
pthread_mutex_init(&client->packetQueueMutex, NULL);
|
pthread_mutex_init(&client->packetQueueMutex, NULL);
|
||||||
// Keep our client in the peer data for later.
|
// Keep our client in the peer data for later.
|
||||||
|
@ -96,6 +129,9 @@ void *serverThread(void *data) {
|
||||||
// Tell the console.
|
// Tell the console.
|
||||||
enet_address_get_host_ip(&event.peer->address, buffer, 2047);
|
enet_address_get_host_ip(&event.peer->address, buffer, 2047);
|
||||||
consoleMessageQueue("%ld: [%s] connected.\n", client->threadIndex, buffer);
|
consoleMessageQueue("%ld: [%s] connected.\n", client->threadIndex, buffer);
|
||||||
|
// Send banner to client.
|
||||||
|
packet = enet_packet_create("KPMPGSMKII\r", 11, ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
enet_peer_send(event.peer, 0, packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ENET_EVENT_TYPE_RECEIVE:
|
case ENET_EVENT_TYPE_RECEIVE:
|
||||||
|
@ -106,14 +142,7 @@ void *serverThread(void *data) {
|
||||||
|
|
||||||
case ENET_EVENT_TYPE_DISCONNECT:
|
case ENET_EVENT_TYPE_DISCONNECT:
|
||||||
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
|
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
|
||||||
// Get our client.
|
serverDisconnectClient((ClientThreadT *)event.peer->data);
|
||||||
client = (ClientThreadT *)event.peer->data;
|
|
||||||
// Stop client processing.
|
|
||||||
client->running = 0;
|
|
||||||
pthread_join(client->threadHandle, &status);
|
|
||||||
// Tell the console.
|
|
||||||
enet_address_get_host_ip(&event.peer->address, buffer, 2047);
|
|
||||||
consoleMessageQueue("%ld: [%s] disconnected.\n", client->threadIndex, buffer);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,11 +152,7 @@ void *serverThread(void *data) {
|
||||||
for (i=0; i<server->peerCount; i++) {
|
for (i=0; i<server->peerCount; i++) {
|
||||||
client = (ClientThreadT *)server->peers[i].data;
|
client = (ClientThreadT *)server->peers[i].data;
|
||||||
if (client) {
|
if (client) {
|
||||||
// Stop client processing.
|
serverDisconnectClient(client);
|
||||||
client->running = 0;
|
|
||||||
pthread_join(client->threadHandle, &status);
|
|
||||||
// Hang up.
|
|
||||||
enet_peer_reset(&server->peers[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,10 @@
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
|
||||||
|
void serverDisconnectClient(ClientThreadT *client);
|
||||||
void serverShutdown(void);
|
void serverShutdown(void);
|
||||||
void serverStartup(uint32_t port, uint32_t maxClients);
|
void serverStartup(uint32_t port, uint32_t maxClients);
|
||||||
void *serverThread(void *data);
|
void *serverThread(void *data);
|
||||||
|
|
120
shared/packet.c
120
shared/packet.c
|
@ -21,6 +21,9 @@
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
|
||||||
|
|
||||||
|
static packetSender _packetSender = NULL;
|
||||||
|
|
||||||
|
|
||||||
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt);
|
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt);
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +31,7 @@ static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
|
||||||
uint16_t x = 0;
|
uint16_t x = 0;
|
||||||
|
|
||||||
for (x=0; x<length; x++) {
|
for (x=0; x<length; x++) {
|
||||||
startAt += data[x];
|
startAt ^= data[x]; // Good ole' XOR.
|
||||||
}
|
}
|
||||||
|
|
||||||
return startAt;
|
return startAt;
|
||||||
|
@ -36,8 +39,10 @@ static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
|
||||||
|
|
||||||
|
|
||||||
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length) {
|
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length) {
|
||||||
uint16_t x = 0;
|
uint8_t sequence = 0;
|
||||||
char c = 0;
|
uint16_t x = 0;
|
||||||
|
char c = 0;
|
||||||
|
PacketEncodeDataT nak = { 0 };
|
||||||
|
|
||||||
// input and inputLength are incoming raw data or NULL and 0 to continue processing already received data.
|
// input and inputLength are incoming raw data or NULL and 0 to continue processing already received data.
|
||||||
// Returns 1 on packet ready, 0 on still waiting.
|
// Returns 1 on packet ready, 0 on still waiting.
|
||||||
|
@ -79,6 +84,51 @@ uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, cha
|
||||||
// Check CRC.
|
// Check CRC.
|
||||||
if ((uint8_t)threadData->decodeBuffer[data->length - 1] != packetCRC(threadData->decodeBuffer, data->length - 1, 0)) continue;
|
if ((uint8_t)threadData->decodeBuffer[data->length - 1] != packetCRC(threadData->decodeBuffer, data->length - 1, 0)) continue;
|
||||||
|
|
||||||
|
// Get sequence value.
|
||||||
|
sequence = ((uint8_t)threadData->decodeBuffer[0]) & 0x1f;
|
||||||
|
|
||||||
|
// Is this a NAK?
|
||||||
|
if ((((uint8_t)threadData->decodeBuffer[0]) & 0xc0) >> 6 == PACKET_CONTROL_NAK) {
|
||||||
|
// Rewind until we find the packet we need in history.
|
||||||
|
x = threadData->historyPosition - 1;
|
||||||
|
if (x < 0) x = PACKET_SEQUENCE_MAX - 1;
|
||||||
|
while (threadData->history[x].sequence != sequence && x != threadData->historyPosition) {
|
||||||
|
x--;
|
||||||
|
if (x < 0) x = PACKET_SEQUENCE_MAX - 1;
|
||||||
|
}
|
||||||
|
// Did we find it?
|
||||||
|
if (x == threadData->historyPosition) {
|
||||||
|
// No! BAD!
|
||||||
|
logWrite("Unable to locate missing packet in history!\n\r");
|
||||||
|
} else {
|
||||||
|
// Yes. Replay missing packets.
|
||||||
|
while (x != threadData->historyPosition) {
|
||||||
|
logWrite("Resending %d!\n\r", threadData->history[x].sequence);
|
||||||
|
_packetSender(threadData->history[x].data, threadData->history[x].length, threadData->senderData);
|
||||||
|
x++;
|
||||||
|
if (x >= PACKET_SEQUENCE_MAX) x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this the sequence number we're expecting?
|
||||||
|
if (sequence == threadData->lastRemoteSequence) {
|
||||||
|
// Yes!
|
||||||
|
threadData->lastRemoteSequence++;
|
||||||
|
} else {
|
||||||
|
// No! NAK it!
|
||||||
|
logWrite("Packet out of sequence! Got %d wanted %d!\n\r", sequence, threadData->lastRemoteSequence);
|
||||||
|
nak.control = PACKET_CONTROL_NAK; // Negative acknowledge.
|
||||||
|
nak.packetType = PACKET_TYPE_NONE; // Not destined for the app.
|
||||||
|
nak.channel = 0; // Channel doesn't matter for NAK.
|
||||||
|
nak.encrypt = 0; // Encryption doesn't matter for NAK.
|
||||||
|
nak.sequence = threadData->lastRemoteSequence; // The last good packet we saw.
|
||||||
|
packetEncode(threadData, &nak, NULL, 0);
|
||||||
|
packetSend(threadData, &nak);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Fill decoded data fields.
|
// Fill decoded data fields.
|
||||||
data->packetType = threadData->decodeBuffer[1];
|
data->packetType = threadData->decodeBuffer[1];
|
||||||
data->channel = threadData->decodeBuffer[2];
|
data->channel = threadData->decodeBuffer[2];
|
||||||
|
@ -88,10 +138,15 @@ uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, cha
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy packet data to new buffer.
|
// Copy packet data to new buffer, if any.
|
||||||
data->data = (char *)malloc(data->length - 4); // 4 for 3 byte header and 1 byte CRC.
|
if (data->length - 4 > 0) {
|
||||||
if (!data) continue;
|
data->data = (char *)malloc(data->length - 4); // 4 for 3 byte header and 1 byte CRC.
|
||||||
memcpy(data->data, &threadData->decodeBuffer[3], data->length - 4); // Skip header and CRC.
|
if (!data) continue;
|
||||||
|
memcpy(data->data, &threadData->decodeBuffer[3], data->length - 4); // Skip header and CRC.
|
||||||
|
} else {
|
||||||
|
// No payload.
|
||||||
|
data->data = NULL;
|
||||||
|
}
|
||||||
// Fix length to remove header and checksum.
|
// Fix length to remove header and checksum.
|
||||||
data->length -= 4;
|
data->length -= 4;
|
||||||
break;
|
break;
|
||||||
|
@ -138,11 +193,14 @@ uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, cha
|
||||||
if (length > PACKET_MAX) return 0;
|
if (length > PACKET_MAX) return 0;
|
||||||
|
|
||||||
data->dataPointer = NULL;
|
data->dataPointer = NULL;
|
||||||
data->length = 0;
|
data->length = 0;
|
||||||
data->sequence = threadData->sequence++;
|
|
||||||
|
if (data->control == PACKET_CONTROL_DAT) {
|
||||||
|
data->sequence = threadData->sequence++;
|
||||||
|
}
|
||||||
|
|
||||||
// Make needed header bytes.
|
// Make needed header bytes.
|
||||||
control = (data->control << 6) + (data->encrypt << 5) + (data->sequence & 0x1f);
|
control = (((uint8_t)data->control) << 6) + (data->encrypt << 5) + (data->sequence & 0x1f);
|
||||||
|
|
||||||
// Calculate CRC over header bytes and payload.
|
// Calculate CRC over header bytes and payload.
|
||||||
crc = packetCRC((char *)&control, 1, crc);
|
crc = packetCRC((char *)&control, 1, crc);
|
||||||
|
@ -185,15 +243,47 @@ uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, cha
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PacketThreadDataT *packetThreadDataCreate(void) {
|
void packetSend(PacketThreadDataT *threadData, PacketEncodeDataT *data) {
|
||||||
|
// Valid control type?
|
||||||
|
if (data->control != PACKET_CONTROL_BAD && data->control <= PACKET_CONTROL_COUNT) {
|
||||||
|
_packetSender(data->dataPointer, data->length, threadData->senderData);
|
||||||
|
} else {
|
||||||
|
logWrite("Invalid PACKET_CONTROL!\n\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to history?
|
||||||
|
if (data->control == PACKET_CONTROL_DAT) {
|
||||||
|
threadData->history[threadData->historyPosition].sequence = data->sequence;
|
||||||
|
threadData->history[threadData->historyPosition].length = data->length;
|
||||||
|
memcpy(threadData->history[threadData->historyPosition].data, data->dataPointer, data->length);
|
||||||
|
threadData->historyPosition++;
|
||||||
|
if (threadData->historyPosition >= PACKET_SEQUENCE_MAX) {
|
||||||
|
threadData->historyPosition = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark invalid so caller has to change it.
|
||||||
|
data->control = PACKET_CONTROL_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void packetSenderRegister(packetSender sender) {
|
||||||
|
_packetSender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PacketThreadDataT *packetThreadDataCreate(void *senderData) {
|
||||||
PacketThreadDataT *data = NULL;
|
PacketThreadDataT *data = NULL;
|
||||||
|
|
||||||
data = (PacketThreadDataT *)malloc(sizeof(PacketThreadDataT));
|
data = (PacketThreadDataT *)malloc(sizeof(PacketThreadDataT));
|
||||||
if (data) {
|
if (data) {
|
||||||
data->sequence = 0;
|
data->sequence = 0;
|
||||||
data->decodeQueueHead = 0;
|
data->lastRemoteSequence = 0;
|
||||||
data->decodeQueueTail = 0;
|
data->historyPosition = 0;
|
||||||
data->newPacket = 1;
|
data->decodeQueueHead = 0;
|
||||||
|
data->decodeQueueTail = 0;
|
||||||
|
data->newPacket = 1;
|
||||||
|
data->senderData = senderData;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -39,60 +39,87 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define PACKET_MAX 1024 // Maximum number of bytes per packet
|
#define PACKET_MAX 1024 // Maximum number of bytes per packet
|
||||||
#define PACKET_SEQUENCE_MAX 32 // Five bits of data
|
#define PACKET_SEQUENCE_MAX 16 // Five bits of data, 32 max.
|
||||||
|
|
||||||
#define PACKET_INPUT_QUEUE_SIZE 4096
|
#define PACKET_INPUT_QUEUE_SIZE 4096
|
||||||
#define PACKET_BUFFER_SIZE (PACKET_MAX * 2 + 2 + 8) // Worst case, every byte is a PACKET_FRAME. Add two for ending frame. Add 8 for worst case header and CRC.
|
#define PACKET_BUFFER_SIZE (PACKET_MAX * 2 + 2 + 8) // Worst case, every byte is a PACKET_FRAME. Add two for ending frame. Add 8 for worst case header and CRC.
|
||||||
|
|
||||||
#define PACKET_FRAME 0x7e
|
#define PACKET_FRAME 0x7e
|
||||||
|
|
||||||
#define PACKET_CONTROL_DAT 0 // Regular data packet.
|
|
||||||
#define PACKET_CONTROL_RTX 1 // Retransmission packet.
|
|
||||||
#define PACKET_CONTROL_NAK 2 // Negative acknowledge.
|
|
||||||
|
|
||||||
#define PACKET_TYPE_NONE 0 // No packet.
|
// This enum must be 4 entries or less.
|
||||||
#define PACKET_TYPE_TEST 1
|
typedef enum PacketControlE {
|
||||||
|
PACKET_CONTROL_DAT = 0, // Regular data packet.
|
||||||
|
PACKET_CONTROL_RTX, // Retransmission packet.
|
||||||
|
PACKET_CONTROL_NAK, // Negative acknowledge.
|
||||||
|
PACKET_CONTROL_BAD,
|
||||||
|
PACKET_CONTROL_COUNT
|
||||||
|
} PacketControlT;
|
||||||
|
|
||||||
|
// This enum is treated as BYTES in the code. Do not go over 255 entries.
|
||||||
|
typedef enum PacketTypeE {
|
||||||
|
PACKET_TYPE_NONE = 0, // No packet.
|
||||||
|
PACKET_TYPE_PING,
|
||||||
|
PACKET_TYPE_PONG,
|
||||||
|
PACKET_TYPE_SERVER_SHUTDOWN,
|
||||||
|
PACKET_TYPE_CLIENT_SHUTDOWN,
|
||||||
|
PACKET_TYPE_COUNT
|
||||||
|
} PacketTypeT;
|
||||||
|
|
||||||
|
|
||||||
typedef struct PacketDecodeDataS {
|
typedef struct PacketDecodeDataS {
|
||||||
// Output
|
// Output
|
||||||
uint8_t packetType; // One of PACKET_TYPE_*
|
PacketTypeT packetType; // One of PACKET_TYPE_*
|
||||||
char *data; // Buffer received. MUST FREE.
|
char *data; // Buffer received. MUST FREE.
|
||||||
uint16_t length; // Length of buffer.
|
uint16_t length; // Length of buffer.
|
||||||
uint8_t channel; // Which data channel it arrived on.
|
uint8_t channel; // Which data channel it arrived on.
|
||||||
} PacketDecodeDataT;
|
} PacketDecodeDataT;
|
||||||
|
|
||||||
typedef struct PacketEncodeDataS {
|
typedef struct PacketEncodeDataS {
|
||||||
// Input
|
// Input
|
||||||
uint8_t control; // One of PACKET_CONTROL_*
|
PacketControlT control; // One of PACKET_CONTROL_*
|
||||||
uint8_t packetType; // One of PACKET_TYPE_*
|
PacketTypeT packetType; // One of PACKET_TYPE_*
|
||||||
uint8_t channel; // Which data channel to use.
|
uint8_t channel; // Which data channel to use.
|
||||||
uint8_t encrypt; // Do we want the packet encrypted?
|
uint8_t encrypt; // Do we want the packet encrypted?
|
||||||
// Input & Output
|
// Input & Output
|
||||||
uint16_t sequence; // For NAK packets, input the sequence number we missed. Other packets returns the sequence of this packet.
|
uint8_t sequence; // For NAK packets, input the sequence number we missed. Other packets returns the sequence of this packet.
|
||||||
// Output
|
// Output
|
||||||
char *dataPointer; // Buffer ready to send. DO NOT FREE.
|
char *dataPointer; // Buffer ready to send. DO NOT FREE.
|
||||||
uint16_t length; // Length of buffer.
|
uint16_t length; // Length of buffer.
|
||||||
} PacketEncodeDataT;
|
} PacketEncodeDataT;
|
||||||
|
|
||||||
|
typedef struct PacketHistoryDataS {
|
||||||
|
char data[PACKET_BUFFER_SIZE];
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t sequence;
|
||||||
|
} PacketHistoryDataT;
|
||||||
|
|
||||||
typedef struct PacketThreadDataS {
|
typedef struct PacketThreadDataS {
|
||||||
// Internal state per thread for packet processing.
|
// Internal state per thread for packet processing.
|
||||||
uint8_t sequence;
|
uint8_t sequence;
|
||||||
char decodeBuffer[PACKET_MAX];
|
uint8_t lastRemoteSequence;
|
||||||
char encodeBuffer[PACKET_BUFFER_SIZE];
|
PacketHistoryDataT history[PACKET_SEQUENCE_MAX];
|
||||||
char decodeQueue[PACKET_INPUT_QUEUE_SIZE];
|
uint8_t historyPosition;
|
||||||
uint16_t decodeQueueHead;
|
char decodeBuffer[PACKET_MAX];
|
||||||
uint16_t decodeQueueTail;
|
char encodeBuffer[PACKET_BUFFER_SIZE];
|
||||||
uint8_t inEscape;
|
char decodeQueue[PACKET_INPUT_QUEUE_SIZE];
|
||||||
uint8_t newPacket;
|
uint16_t decodeQueueHead;
|
||||||
|
uint16_t decodeQueueTail;
|
||||||
|
uint8_t inEscape;
|
||||||
|
uint8_t newPacket;
|
||||||
|
void *senderData;
|
||||||
} PacketThreadDataT;
|
} PacketThreadDataT;
|
||||||
|
|
||||||
|
typedef void (*packetSender)(char *data, uint32_t length, void *userData);
|
||||||
|
|
||||||
|
|
||||||
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length);
|
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length);
|
||||||
void packetDecodeDataDestroy(PacketDecodeDataT **packet);
|
void packetDecodeDataDestroy(PacketDecodeDataT **packet);
|
||||||
uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, char *input, uint16_t length);
|
uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, char *input, uint16_t length);
|
||||||
PacketThreadDataT *packetThreadDataCreate(void);
|
void packetSend(PacketThreadDataT *threadData, PacketEncodeDataT *data);
|
||||||
|
void packetSenderRegister(packetSender sender);
|
||||||
|
PacketThreadDataT *packetThreadDataCreate(void *senderData);
|
||||||
void packetThreadDataDestroy(PacketThreadDataT **data);
|
void packetThreadDataDestroy(PacketThreadDataT **data);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,16 +51,12 @@ char *utilAppNameWithNewExtensionGet(char *appName, char *extension) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void utilDie(const char *why, ...) {
|
void utilBitsPrint(uint8_t byte) {
|
||||||
va_list args;
|
int i = 0;
|
||||||
char msg[2048];
|
|
||||||
|
|
||||||
va_start(args, why);
|
for (i = 7; 0 <= i; i--) {
|
||||||
vsprintf(msg, why, args);
|
printf("%c", (byte & (1 << i)) ? '1' : '0');
|
||||||
va_end(args);
|
}
|
||||||
|
|
||||||
logWrite("DIE: %s", msg);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,3 +89,15 @@ char *utilCreateStringVArgs(char *format, va_list args) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void utilDie(const char *why, ...) {
|
||||||
|
va_list args;
|
||||||
|
char msg[2048];
|
||||||
|
|
||||||
|
va_start(args, why);
|
||||||
|
vsprintf(msg, why, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
logWrite("DIE: %s", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
|
@ -26,9 +26,10 @@
|
||||||
|
|
||||||
|
|
||||||
char *utilAppNameWithNewExtensionGet(char *appName, char *extension);
|
char *utilAppNameWithNewExtensionGet(char *appName, char *extension);
|
||||||
void utilDie(const char *why, ...);
|
void utilBitsPrint(uint8_t byte);
|
||||||
char *utilCreateString(char *format, ...);
|
char *utilCreateString(char *format, ...);
|
||||||
char *utilCreateStringVArgs(char *format, va_list args);
|
char *utilCreateStringVArgs(char *format, va_list args);
|
||||||
|
void utilDie(const char *why, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif // UTIL_H
|
#endif // UTIL_H
|
||||||
|
|
Loading…
Add table
Reference in a new issue