diff --git a/Makefile.djgpp b/Makefile.djgpp
index 2305d58..b82d070 100644
--- a/Makefile.djgpp
+++ b/Makefile.djgpp
@@ -33,10 +33,13 @@ BINDIR = bin
# CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI
CFLAGS := $(DEBUG)
+#CFLAGS += -DALLEGRONOTAVAIL -DALLEGRONOTPROGS -DDZCOMM_SRC
CFLAGS += -I$(SRCDIR)/client/src -I$(SRCDIR)/client/src/system -I$(SRCDIR)/client/src/dos -I$(SRCDIR)/client/src/gui -I$(SRCDIR)/client/src/thirdparty
CFLAGS += -I$(SRCDIR)/shared -I$(SRCDIR)/shared/thirdparty
+#CFLAGS += -I$(SRCDIR)/client/src/thirdparty/dzcomm -I$(SRCDIR)/client/src/thirdparty/dzcomm/include
CPPFLAGS :=
LDFLAGS :=
+#LDFLAGS += -L$(SRCDIR)/client/src/thirdparty/dzcomm -ldzcom
PREFIX := /usr/local
TARGET_ARCH :=
@@ -61,6 +64,7 @@ DEP := $(OBJ:.o=.d)
BIN := $(BINDIR)/$(TARGET)
-include $(DEP)
+#obj/client/src/thirdparty/dzcomm/src/dos/djirqs.o
#$(info [${SRC}])
#$(info [${OBJ}])
diff --git a/build.sh b/build.sh
index 108e3fc..53c0aea 100755
--- a/build.sh
+++ b/build.sh
@@ -27,6 +27,7 @@ mkdir -p \
obj/client/src/system \
obj/client/src/dos \
obj/client/src/gui \
+ obj/client/src/embedded \
obj/client/src/thirdparty/serial \
obj/shared/thirdparty/memwatch \
obj/shared/thirdparty/blowfish-api \
diff --git a/buildPrerequisites.sh b/buildPrerequisites.sh
index 76f7338..894d595 100755
--- a/buildPrerequisites.sh
+++ b/buildPrerequisites.sh
@@ -79,8 +79,10 @@ function outputLicense() {
pushd font/data
-
createEmbeddedBinary vga8x14 dat ../../client/src/embedded
-
+popd
+
+pushd client/data
+createEmbeddedBinary mouse png ../../client/src/embedded
popd
diff --git a/client/client.pro b/client/client.pro
index 4bcb464..800790b 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -29,6 +29,9 @@ QMAKE_CFLAGS += -O0
DEFINES *= CLIENT
+UNUSED_CRAP = \
+ src/thirdparty/dzcomm/include/dzcomm.h
+
DOS_HEADERS = \
src/thirdparty/serial/serial.h
@@ -68,9 +71,10 @@ HEADERS = \
$$SHARED/packets.h \
src/config.h \
$$SHARED/util.h \
- src/embedded/vga8x14.h \
- src/firstrun.h \
+ src/embedded/embedded.h \
src/gui/msgbox.h \
+ src/gui/timer.h \
+ src/hangup.h \
src/login.h \
src/menu.h \
src/network.h \
@@ -84,13 +88,13 @@ HEADERS = \
src/system/surface.h \
src/system/taglist.h \
src/system/keyboard.h \
- src/system/task.h \
- src/system/timer.h \
$$SHARED/array.h \
$$SHARED/log.h \
src/system/mouse.h \
src/system/vesa.h \
src/system/os.h \
+ src/embedded/vga8x14.h \
+ src/embedded/mouse.h \
src/gui/listbox.h \
src/gui/terminal.h \
src/gui/updown.h \
@@ -117,16 +121,11 @@ SOURCES = \
$$SHARED/packet.c \
$$SHARED/thirdparty/tiny-AES-c/aes.c \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
- src/config.c \
$$SHARED/memory.c \
src/embedded/embedded.c \
- src/firstrun.c \
src/gui/msgbox.c \
- src/login.c \
- src/menu.c \
- src/network.c \
- src/settings.c \
- src/signup.c \
+ src/gui/timer.c \
+ src/hangup.c \
src/system/comport.c \
src/system/os.c \
src/system/surface.c \
@@ -134,8 +133,6 @@ SOURCES = \
$$SHARED/util.c \
$$SHARED/array.c \
$$SHARED/log.c \
- src/system/timer.c \
- src/system/task.c \
src/gui/listbox.c \
src/gui/terminal.c \
src/gui/updown.c \
@@ -152,8 +149,14 @@ SOURCES = \
src/gui/button.c \
src/gui/checkbox.c \
src/gui/label.c \
+ src/config.c \
src/main.c \
- src/welcome.c
+ src/welcome.c \
+ src/login.c \
+ src/menu.c \
+ src/signup.c \
+ src/network.c \
+ src/settings.c
LIBS = \
-lSDL2 \
diff --git a/client/src/embedded/embedded.c b/client/src/embedded/embedded.c
index d96da36..8885719 100644
--- a/client/src/embedded/embedded.c
+++ b/client/src/embedded/embedded.c
@@ -19,4 +19,4 @@
#define EMBED_HERE
-#include "vga8x14.h"
+#include "embedded/embedded.h"
diff --git a/client/src/system/task.h b/client/src/embedded/embedded.h
similarity index 69%
rename from client/src/system/task.h
rename to client/src/embedded/embedded.h
index fbe64fc..0d511e5 100644
--- a/client/src/system/task.h
+++ b/client/src/embedded/embedded.h
@@ -18,23 +18,12 @@
*/
-#ifndef TASK_H
-#define TASK_H
+#ifndef EMBEDDED_H
+#define EMBEDDED_H
-#include "os.h"
-#include "widget.h"
+#include "mouse.h"
+#include "vga8x14.h"
-typedef void (*taskFunction)(void *data);
-
-
-uint8_t taskCreate(void (*function)(void *), void *data);
-void taskProxy(WidgetT *widget);
-void taskRun(void);
-void taskShutdown(void);
-void taskStartup(void);
-void taskYield(void);
-
-
-#endif // TASK_H
+#endif // EMBEDDED_H
diff --git a/client/src/embedded/mouse.h b/client/src/embedded/mouse.h
new file mode 100644
index 0000000..de48447
--- /dev/null
+++ b/client/src/embedded/mouse.h
@@ -0,0 +1,457 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#ifndef MOUSE_PNG_H
+#define MOUSE_PNG_H
+
+
+// ===== THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT =====
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+
+#ifdef EMBED_HERE
+
+unsigned char mouse_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xf3, 0xa0, 0x7d, 0x0c, 0x00, 0x00, 0x10,
+ 0x66, 0x7a, 0x54, 0x58, 0x74, 0x52, 0x61, 0x77, 0x20, 0x70, 0x72, 0x6f,
+ 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x78,
+ 0x69, 0x66, 0x00, 0x00, 0x78, 0xda, 0xc5, 0x9a, 0x5b, 0x76, 0x1b, 0x39,
+ 0x12, 0x44, 0xff, 0xb1, 0x8a, 0x59, 0x02, 0xde, 0x8f, 0xe5, 0xe0, 0x91,
+ 0x38, 0xa7, 0x77, 0x30, 0xcb, 0x9f, 0x9b, 0xa8, 0x22, 0x2d, 0xca, 0x94,
+ 0x65, 0xbb, 0x3f, 0xc6, 0x6c, 0x89, 0xa5, 0x62, 0x15, 0x0a, 0xc8, 0x8c,
+ 0x8c, 0xc8, 0x00, 0xdb, 0xc8, 0x7f, 0xff, 0xd9, 0xe6, 0x3f, 0xfc, 0x4b,
+ 0xd6, 0x66, 0x13, 0x53, 0xa9, 0xb9, 0xe5, 0x6c, 0xf9, 0x17, 0x5b, 0x6c,
+ 0xbe, 0x73, 0x50, 0xed, 0xf5, 0xaf, 0x9f, 0xdf, 0xce, 0xc6, 0xf3, 0xfb,
+ 0xfe, 0xc3, 0x3e, 0x0e, 0x5e, 0xce, 0x1b, 0xf7, 0xb8, 0xc9, 0x73, 0x2a,
+ 0xf0, 0x1e, 0xae, 0x3f, 0x6b, 0xbe, 0xcf, 0x0b, 0xe7, 0x3d, 0xd7, 0xfb,
+ 0xfb, 0xfc, 0xbc, 0xc7, 0xe9, 0x9c, 0x4f, 0x1f, 0x06, 0x6a, 0x72, 0x7f,
+ 0x30, 0x5e, 0x3f, 0xe8, 0xf7, 0x40, 0xbe, 0xde, 0x0f, 0x78, 0x4c, 0xe5,
+ 0x7e, 0x50, 0x70, 0xd7, 0x03, 0xec, 0xba, 0x07, 0xea, 0xf7, 0x40, 0xc1,
+ 0xdf, 0x4f, 0x8e, 0xd7, 0xdf, 0xe3, 0x7e, 0x72, 0x6e, 0xb5, 0x7c, 0x5c,
+ 0xc2, 0x7a, 0x2c, 0xad, 0xde, 0x67, 0xea, 0xf5, 0x63, 0xf4, 0x57, 0x0c,
+ 0xc5, 0xe7, 0x94, 0x5d, 0x89, 0xfc, 0x8e, 0xde, 0x96, 0x92, 0x1b, 0xc7,
+ 0xd5, 0xdb, 0x58, 0x88, 0xdb, 0xd2, 0x89, 0xee, 0xe9, 0x9b, 0xde, 0x97,
+ 0xc6, 0x35, 0xce, 0xe7, 0xbf, 0xcd, 0xe3, 0x52, 0xcf, 0x9c, 0xbc, 0x04,
+ 0x17, 0xec, 0xf9, 0x5d, 0xaf, 0x59, 0x06, 0xfd, 0x71, 0xa1, 0xeb, 0xf9,
+ 0xf3, 0x9b, 0x50, 0xe9, 0xa7, 0x1c, 0x87, 0x73, 0x26, 0x84, 0x72, 0xe2,
+ 0x6b, 0x0d, 0x29, 0x63, 0x0a, 0xcc, 0xbc, 0xdd, 0xb1, 0x15, 0xfb, 0x8c,
+ 0xe6, 0x4b, 0x6c, 0x9e, 0xe9, 0x7a, 0xff, 0xcf, 0xfc, 0xce, 0xb2, 0x6e,
+ 0x38, 0xbc, 0xa4, 0xbb, 0xf7, 0x57, 0x18, 0x98, 0x0f, 0x4f, 0x72, 0xef,
+ 0x60, 0x90, 0xe5, 0x3e, 0x1f, 0x3e, 0x65, 0x2f, 0x3f, 0xdf, 0xcf, 0x79,
+ 0xf3, 0xf9, 0x03, 0x97, 0xde, 0xa7, 0xfb, 0xe4, 0xf4, 0xc3, 0x8c, 0x4a,
+ 0x7c, 0x3e, 0xd8, 0xbf, 0xcc, 0xc8, 0xc5, 0x07, 0xe4, 0x9e, 0xe9, 0x7d,
+ 0xfe, 0xec, 0xbd, 0xea, 0xde, 0x72, 0xad, 0xae, 0xc7, 0xcc, 0x92, 0xf3,
+ 0xbd, 0xa8, 0xc7, 0x4a, 0x9c, 0x39, 0xa9, 0xdc, 0x6b, 0x28, 0x08, 0xce,
+ 0x6d, 0x99, 0x57, 0xe1, 0x27, 0x71, 0x5c, 0xce, 0xab, 0xf1, 0xaa, 0x94,
+ 0xcb, 0x04, 0x63, 0xcb, 0x4e, 0x3b, 0x78, 0x4d, 0xd7, 0x9c, 0x27, 0x95,
+ 0x9b, 0x09, 0x2c, 0xd7, 0xdd, 0x36, 0x4e, 0xce, 0xc1, 0x74, 0x93, 0x39,
+ 0x46, 0x2f, 0xbe, 0xf0, 0xee, 0xfd, 0x24, 0xeb, 0x7a, 0xae, 0x92, 0x8b,
+ 0xe6, 0x67, 0xd0, 0xa4, 0x47, 0x7d, 0xb9, 0xed, 0x4b, 0x68, 0x61, 0x01,
+ 0x01, 0x1f, 0x26, 0x50, 0x09, 0x9c, 0xf5, 0x7b, 0x9b, 0x7b, 0x2e, 0xee,
+ 0x3c, 0xb7, 0x9d, 0xe7, 0x4d, 0xea, 0x6f, 0xd9, 0xe5, 0xb8, 0xd4, 0x3b,
+ 0x06, 0x73, 0xdc, 0xf2, 0xed, 0xcb, 0xfc, 0xce, 0x45, 0xbf, 0x7a, 0xed,
+ 0xad, 0xb5, 0xe4, 0x9c, 0x79, 0xd4, 0x0c, 0xb8, 0x60, 0x5e, 0x5e, 0x03,
+ 0xce, 0x34, 0x34, 0x73, 0xfa, 0x9b, 0xcb, 0xc8, 0x88, 0xdb, 0x77, 0x50,
+ 0xd3, 0x09, 0xf0, 0xe3, 0xf5, 0x0a, 0xc8, 0x3b, 0xb1, 0x81, 0x14, 0xa6,
+ 0x13, 0xe6, 0xca, 0x02, 0xbb, 0x1d, 0xd7, 0x10, 0x23, 0xb9, 0x1f, 0xd8,
+ 0x0a, 0x27, 0xd1, 0x81, 0xeb, 0x12, 0xef, 0x57, 0x71, 0xbb, 0xb2, 0xae,
+ 0xfb, 0x75, 0xa0, 0xc8, 0xb3, 0x13, 0x93, 0xa1, 0x92, 0xa2, 0xb3, 0xd9,
+ 0x85, 0xe4, 0xb2, 0xb3, 0xc5, 0xfb, 0xe2, 0x1c, 0x81, 0xac, 0x24, 0xa8,
+ 0x3b, 0x5b, 0x7d, 0x88, 0x7e, 0x90, 0x01, 0x97, 0x92, 0x5f, 0x4c, 0xd2,
+ 0xc7, 0x10, 0x32, 0xb9, 0xa1, 0x08, 0x78, 0xb4, 0xe1, 0x9e, 0xe2, 0xce,
+ 0xb5, 0x3e, 0xf9, 0xeb, 0x3c, 0x2c, 0x49, 0x26, 0x52, 0xc8, 0xa1, 0x90,
+ 0x9b, 0x16, 0x3a, 0xc9, 0x8a, 0x31, 0x81, 0x9f, 0x12, 0x2b, 0x18, 0xea,
+ 0x29, 0xa4, 0x98, 0x52, 0xca, 0xa9, 0xa4, 0x9a, 0x5a, 0xea, 0x39, 0xe4,
+ 0x68, 0xa8, 0xb0, 0x9c, 0x4b, 0x56, 0xba, 0xed, 0x25, 0x94, 0x58, 0x52,
+ 0xc9, 0xa5, 0x94, 0x5a, 0x5a, 0xe9, 0x35, 0xd4, 0x58, 0x53, 0xcd, 0xb5,
+ 0xd4, 0x5a, 0x5b, 0xed, 0xcd, 0xb7, 0x00, 0x1b, 0xa7, 0x46, 0x39, 0xb6,
+ 0xda, 0x5a, 0xeb, 0x9d, 0x67, 0x76, 0x46, 0xee, 0xd9, 0x74, 0xae, 0xef,
+ 0x9c, 0x19, 0x7e, 0x84, 0x11, 0x47, 0x1a, 0x79, 0x94, 0x51, 0x47, 0x1b,
+ 0x7d, 0x02, 0x9f, 0x19, 0x67, 0x9a, 0x79, 0x96, 0x59, 0x67, 0x9b, 0x7d,
+ 0xf9, 0x15, 0x16, 0x75, 0xbc, 0xf2, 0x2a, 0xab, 0xae, 0xb6, 0xba, 0x38,
+ 0x01, 0x4a, 0x12, 0x25, 0x19, 0xc9, 0x52, 0xa4, 0x4a, 0x93, 0xbe, 0xc1,
+ 0xda, 0x0e, 0x3b, 0xee, 0xb4, 0xf3, 0x2e, 0xbb, 0xee, 0xb6, 0xfb, 0x33,
+ 0x6b, 0xee, 0x2e, 0xdb, 0xcf, 0xaf, 0x3f, 0xc8, 0x9a, 0xbb, 0xb3, 0xe6,
+ 0x4f, 0xa6, 0xf4, 0xba, 0xf2, 0xcc, 0x1a, 0x67, 0x4b, 0xb9, 0xde, 0xcd,
+ 0xc1, 0x0b, 0x83, 0x68, 0xce, 0xc8, 0x98, 0x8f, 0x8e, 0x8c, 0x17, 0xcd,
+ 0x00, 0x80, 0xf6, 0x9a, 0x33, 0x5b, 0x5d, 0x8c, 0x5e, 0x33, 0xa7, 0x39,
+ 0xb3, 0xcd, 0x53, 0x15, 0xc9, 0x33, 0xc9, 0xa4, 0xb9, 0x59, 0xce, 0x76,
+ 0x97, 0x7d, 0x34, 0x21, 0x8a, 0xf3, 0x69, 0xbb, 0x67, 0xee, 0x7e, 0x64,
+ 0xee, 0x8f, 0xf2, 0x66, 0x72, 0xfc, 0x65, 0xde, 0xfc, 0xef, 0x66, 0xce,
+ 0x68, 0xea, 0xfe, 0x65, 0xe6, 0x4e, 0xde, 0x8c, 0xa4, 0x0f, 0x79, 0x7b,
+ 0x93, 0xb5, 0xa5, 0xdc, 0x3c, 0x4f, 0xc6, 0xae, 0x2a, 0xd4, 0x98, 0xda,
+ 0x40, 0xf5, 0xf1, 0xb9, 0xf0, 0xd8, 0xb8, 0xf5, 0xb8, 0x9a, 0x5d, 0xf2,
+ 0xde, 0x65, 0xec, 0x6e, 0xfb, 0x5c, 0xbd, 0x89, 0x1b, 0xbd, 0x10, 0xe0,
+ 0xde, 0x6b, 0x02, 0xfa, 0x73, 0x87, 0x24, 0x33, 0xc7, 0x54, 0x57, 0x4f,
+ 0xd5, 0xcf, 0xd4, 0xfb, 0xd2, 0x09, 0x13, 0xef, 0x3e, 0x1c, 0xc1, 0x5c,
+ 0x84, 0x75, 0x11, 0xae, 0x68, 0x58, 0x48, 0x2f, 0x4d, 0x92, 0xef, 0x4a,
+ 0x80, 0x76, 0x34, 0xf1, 0x7d, 0xad, 0x22, 0x6d, 0x71, 0x5f, 0x5e, 0xe7,
+ 0x67, 0xe7, 0x15, 0x4b, 0x0e, 0xb5, 0x27, 0x52, 0x52, 0x72, 0x76, 0x31,
+ 0xf1, 0x5f, 0x49, 0xcd, 0x5f, 0x47, 0x4a, 0xd4, 0xe6, 0x71, 0xf0, 0x67,
+ 0xef, 0xd9, 0xe9, 0xbb, 0x4b, 0xbb, 0x16, 0x27, 0x0d, 0xc2, 0xec, 0x66,
+ 0xce, 0x01, 0xa1, 0xa7, 0x56, 0xe1, 0xfe, 0x2e, 0x3c, 0x75, 0x14, 0xe2,
+ 0x02, 0x1a, 0x76, 0x49, 0xba, 0x7a, 0xef, 0xb6, 0x84, 0xd4, 0x06, 0x33,
+ 0x18, 0x8e, 0x49, 0x6e, 0xe6, 0x54, 0x7d, 0xd7, 0x05, 0xd7, 0x91, 0xf2,
+ 0x86, 0x02, 0x5a, 0xf2, 0x75, 0x9a, 0xb6, 0x56, 0x1b, 0xe3, 0x9a, 0xab,
+ 0x0c, 0x0f, 0x4e, 0xcf, 0xb3, 0xe2, 0x9f, 0xbe, 0x9b, 0xe7, 0x09, 0x57,
+ 0x53, 0x22, 0x65, 0x5b, 0xa6, 0x84, 0xbd, 0x7d, 0x24, 0xcc, 0xc8, 0xcb,
+ 0x20, 0x07, 0x4d, 0x67, 0x06, 0x5a, 0x7c, 0xdf, 0xad, 0xfa, 0x21, 0xe7,
+ 0xef, 0xd5, 0x66, 0xd9, 0x12, 0x9b, 0x64, 0x24, 0x84, 0xbf, 0x0d, 0xab,
+ 0x6d, 0xdc, 0x18, 0x15, 0xa9, 0xd7, 0x8a, 0x6b, 0x91, 0xe5, 0xd6, 0x59,
+ 0x16, 0xa3, 0x31, 0x34, 0x47, 0x3a, 0x5e, 0xd9, 0x9b, 0xb1, 0xd2, 0x3d,
+ 0x9a, 0x94, 0xed, 0x7c, 0xa9, 0x69, 0xc4, 0xbc, 0x49, 0x40, 0x33, 0xdc,
+ 0x53, 0xf3, 0x68, 0xb9, 0xec, 0x3c, 0x46, 0xaa, 0x92, 0x28, 0x31, 0xd2,
+ 0x08, 0x17, 0x88, 0x9b, 0x5a, 0xad, 0x13, 0x76, 0x2c, 0x34, 0x22, 0x7b,
+ 0xca, 0x68, 0x0c, 0x06, 0x2c, 0xd2, 0xb6, 0x00, 0x4e, 0x6a, 0x12, 0x7d,
+ 0xc8, 0x6c, 0x6b, 0xd4, 0x6d, 0x08, 0x65, 0x63, 0x5d, 0xdb, 0xdb, 0x94,
+ 0x47, 0x62, 0xd6, 0xb3, 0x74, 0x5f, 0x58, 0x1d, 0xf7, 0xf9, 0xdc, 0x53,
+ 0x1c, 0x54, 0x41, 0x88, 0x00, 0x8b, 0x21, 0xdc, 0x52, 0xe5, 0x2c, 0x5c,
+ 0x67, 0x25, 0xf3, 0x91, 0x87, 0x22, 0xa6, 0x42, 0x2b, 0x2e, 0x88, 0xcd,
+ 0x65, 0xf0, 0x59, 0x4a, 0xdc, 0x7d, 0xa4, 0x55, 0xa7, 0x00, 0xa8, 0xb9,
+ 0x52, 0xa3, 0xd6, 0x59, 0xad, 0xa3, 0x68, 0x6a, 0xcb, 0x64, 0xb5, 0x8f,
+ 0x41, 0x5d, 0xae, 0xb9, 0xe1, 0x87, 0xd2, 0xc7, 0x8e, 0x7d, 0x0e, 0x28,
+ 0x2c, 0x6e, 0x07, 0xc8, 0xd6, 0x30, 0xc9, 0x47, 0xca, 0x87, 0x21, 0x98,
+ 0x65, 0x9e, 0xe2, 0x1b, 0x85, 0x95, 0x56, 0xab, 0x17, 0x4e, 0x56, 0x8f,
+ 0xf5, 0xff, 0x9f, 0xb5, 0x26, 0xf3, 0x01, 0xe0, 0x32, 0xa7, 0x5e, 0xc5,
+ 0xd0, 0x42, 0xbf, 0xa0, 0xc3, 0xd9, 0x06, 0xa1, 0xe8, 0x11, 0xa3, 0x64,
+ 0x7d, 0x07, 0xad, 0x94, 0xfd, 0x16, 0xe3, 0xdb, 0xb6, 0x6b, 0x49, 0xa9,
+ 0xb1, 0xcc, 0x08, 0x0d, 0x75, 0x32, 0x3f, 0x1b, 0xbd, 0x7b, 0x21, 0xf8,
+ 0x23, 0x14, 0xba, 0xdb, 0x19, 0x39, 0x39, 0x2b, 0xb8, 0xb7, 0xb1, 0x6a,
+ 0x06, 0xad, 0xac, 0xb4, 0x4b, 0x58, 0x30, 0x8b, 0xdb, 0x6e, 0xe8, 0xcc,
+ 0xba, 0xd1, 0xac, 0xeb, 0xc8, 0xf9, 0xa4, 0x72, 0x77, 0x0d, 0x1e, 0xcf,
+ 0xb3, 0x8b, 0x12, 0xf7, 0xd3, 0x79, 0x35, 0x05, 0x91, 0x05, 0x55, 0x2d,
+ 0xe6, 0xbd, 0x73, 0x8d, 0x69, 0x53, 0xd4, 0x7b, 0x32, 0xb1, 0xba, 0x72,
+ 0x5e, 0x4e, 0xab, 0xc5, 0x0e, 0x13, 0xd6, 0x4c, 0x62, 0x7b, 0xa3, 0x92,
+ 0xba, 0x87, 0x22, 0x68, 0x80, 0x24, 0xc5, 0x1e, 0x60, 0xf5, 0x9c, 0x41,
+ 0xe6, 0x29, 0x4d, 0xe2, 0x34, 0xbf, 0x29, 0x64, 0xf3, 0xb6, 0xb2, 0xcb,
+ 0x0a, 0x07, 0xcf, 0x81, 0x46, 0x6d, 0xb6, 0x30, 0x57, 0x04, 0x7f, 0xd3,
+ 0x53, 0x8a, 0xc0, 0x10, 0x36, 0x1d, 0x92, 0x6d, 0xdf, 0x9d, 0x60, 0xe5,
+ 0x72, 0x42, 0xdd, 0xbc, 0x01, 0xc4, 0x4c, 0x72, 0x55, 0x5a, 0x5a, 0xe8,
+ 0x10, 0x76, 0xa0, 0x76, 0x1d, 0xa0, 0xcc, 0x65, 0x7c, 0x4e, 0xb4, 0x93,
+ 0x6b, 0x78, 0x42, 0x79, 0x0d, 0x1f, 0xf6, 0x19, 0xfe, 0xca, 0x1a, 0x4f,
+ 0x68, 0xf9, 0x7a, 0xc2, 0x68, 0x00, 0x15, 0x8e, 0x64, 0xdd, 0x03, 0x2c,
+ 0x75, 0x74, 0x20, 0xbb, 0x2e, 0xc0, 0x1d, 0x62, 0x5e, 0x99, 0x0a, 0x00,
+ 0xc6, 0xe4, 0x7b, 0x4c, 0x94, 0x41, 0xbb, 0x44, 0x18, 0x32, 0x3a, 0xa9,
+ 0xe0, 0x20, 0x74, 0x38, 0xfb, 0x24, 0xd1, 0x91, 0x26, 0x78, 0xfe, 0xa4,
+ 0xd8, 0x95, 0x13, 0x7e, 0x5f, 0xb2, 0x4e, 0x81, 0xf2, 0x53, 0x1c, 0x54,
+ 0x97, 0xfa, 0xa2, 0x22, 0xa9, 0xc1, 0xda, 0x20, 0x74, 0xee, 0x9d, 0xad,
+ 0x43, 0x45, 0x92, 0x73, 0x5d, 0x08, 0x24, 0xeb, 0x75, 0xa8, 0x15, 0xa2,
+ 0x96, 0x78, 0x6a, 0x0c, 0x8d, 0xcf, 0x14, 0xfb, 0x94, 0xee, 0x48, 0x28,
+ 0x1b, 0x48, 0x57, 0xe5, 0x58, 0x2b, 0x48, 0x5f, 0xf0, 0x2d, 0x5c, 0x6d,
+ 0x4b, 0x20, 0x10, 0x79, 0x12, 0x06, 0x7e, 0x8b, 0x78, 0xb4, 0x29, 0x1b,
+ 0xcf, 0xac, 0xa9, 0x2b, 0x50, 0x61, 0x41, 0x56, 0xdf, 0xcb, 0x6b, 0x29,
+ 0x12, 0xed, 0x59, 0x92, 0x53, 0xb2, 0x6e, 0x21, 0x0e, 0xa4, 0x87, 0xb0,
+ 0x50, 0x77, 0x95, 0xd2, 0xfc, 0x48, 0xdb, 0xf9, 0x49, 0xdb, 0xe6, 0x57,
+ 0xb4, 0x7c, 0x92, 0x77, 0x52, 0xa7, 0x64, 0xf1, 0xab, 0xe4, 0x69, 0x89,
+ 0x68, 0xfe, 0x9a, 0x7f, 0x49, 0x1e, 0x95, 0xf4, 0xcb, 0xf4, 0x3d, 0xd3,
+ 0xb8, 0x03, 0xa5, 0x32, 0x03, 0x8f, 0xaa, 0x66, 0x2a, 0x43, 0xf9, 0xa4,
+ 0x95, 0x77, 0x58, 0xb1, 0x9d, 0x40, 0xd7, 0x95, 0x0a, 0x47, 0xac, 0x64,
+ 0x86, 0x82, 0x5a, 0x39, 0x4a, 0xc1, 0x51, 0x49, 0x95, 0x25, 0xd2, 0x67,
+ 0xf8, 0xb4, 0x52, 0x97, 0xb9, 0x64, 0xa3, 0x97, 0x9e, 0x93, 0xde, 0x9b,
+ 0x51, 0xa9, 0x03, 0xab, 0x49, 0x0c, 0x83, 0xb5, 0x4c, 0x74, 0x16, 0x8b,
+ 0x84, 0x9a, 0xe9, 0x3c, 0x07, 0x79, 0x57, 0x5b, 0x70, 0x06, 0x17, 0x16,
+ 0xa7, 0x0e, 0x64, 0x86, 0xd4, 0x7f, 0xd6, 0x1e, 0xf3, 0x77, 0xe2, 0xf3,
+ 0xb3, 0xf6, 0x98, 0x6f, 0x68, 0xeb, 0xb7, 0x59, 0xca, 0xbc, 0xa7, 0xa9,
+ 0x5f, 0xb2, 0xd4, 0xdb, 0x77, 0xa3, 0xb0, 0x55, 0x0f, 0x75, 0x14, 0xe8,
+ 0xd6, 0x1f, 0xe8, 0xe4, 0xd6, 0x9f, 0xf3, 0xcc, 0xaf, 0x14, 0xe8, 0x45,
+ 0x80, 0xcc, 0xef, 0x28, 0x10, 0x59, 0x7c, 0xd5, 0xa0, 0x4b, 0x81, 0x0e,
+ 0x3f, 0x3e, 0x24, 0xc8, 0x5c, 0x1a, 0x04, 0xe0, 0xfe, 0x4e, 0x85, 0x9e,
+ 0x22, 0x64, 0xfe, 0xa5, 0x0a, 0x3d, 0x45, 0xc8, 0xe8, 0x6c, 0x7e, 0x4f,
+ 0x87, 0x1e, 0x09, 0x64, 0x41, 0xf3, 0x62, 0xa6, 0x47, 0x12, 0x55, 0xd2,
+ 0xcd, 0xc9, 0xe3, 0xab, 0xd6, 0xbc, 0xa6, 0xf0, 0x4e, 0x20, 0xde, 0xe7,
+ 0x97, 0x29, 0x34, 0x5f, 0xe5, 0xf4, 0x56, 0x22, 0xfb, 0xd4, 0xa2, 0x87,
+ 0x12, 0x5d, 0x3a, 0xf4, 0x50, 0xa1, 0xa7, 0x08, 0x99, 0xbf, 0x52, 0x21,
+ 0xd8, 0x95, 0x62, 0x98, 0x64, 0x87, 0x10, 0x45, 0x1d, 0x2e, 0x1b, 0x6e,
+ 0x6a, 0x99, 0xbc, 0xef, 0x95, 0xb2, 0x28, 0xb5, 0x6d, 0x8f, 0x69, 0x82,
+ 0x9c, 0x74, 0x53, 0x8a, 0x43, 0x6f, 0x29, 0x46, 0xcc, 0x31, 0x0e, 0x17,
+ 0x63, 0x56, 0xb9, 0xbb, 0xda, 0x30, 0x07, 0x6c, 0x99, 0xe9, 0x4e, 0x21,
+ 0xc1, 0x89, 0xe5, 0x48, 0xc5, 0x99, 0x99, 0xd2, 0x8c, 0x03, 0xfa, 0x5c,
+ 0x64, 0x93, 0x18, 0x45, 0x02, 0x14, 0x5d, 0x1c, 0x08, 0x14, 0x68, 0x83,
+ 0x35, 0xe9, 0x5a, 0x17, 0x9c, 0x4b, 0xaa, 0x71, 0x84, 0x30, 0x3d, 0xfe,
+ 0x60, 0xe2, 0xc2, 0x75, 0xea, 0x20, 0x8f, 0xb9, 0x4c, 0xdd, 0x92, 0x49,
+ 0x06, 0x4b, 0x8b, 0x66, 0x61, 0x16, 0xa9, 0xcb, 0x11, 0x3a, 0xd5, 0x4c,
+ 0x66, 0x9b, 0x96, 0x21, 0x4b, 0x01, 0xca, 0x7d, 0x43, 0x12, 0x73, 0xca,
+ 0x76, 0x98, 0x85, 0xc4, 0xdc, 0x56, 0x50, 0x34, 0x2b, 0x25, 0x8c, 0x05,
+ 0x9a, 0x4a, 0x94, 0x80, 0x1e, 0x36, 0xda, 0x63, 0xb2, 0x51, 0xa4, 0xcc,
+ 0x53, 0xfd, 0x61, 0x25, 0xd0, 0xbb, 0xbb, 0xa3, 0x6d, 0xcf, 0x76, 0x82,
+ 0x78, 0x7c, 0xaa, 0x74, 0x0f, 0x7e, 0x00, 0xe6, 0xb1, 0x18, 0x68, 0x2d,
+ 0x59, 0x8c, 0x10, 0x62, 0x6a, 0xd8, 0x99, 0xda, 0x7d, 0xa5, 0xd3, 0x8e,
+ 0xe6, 0xdf, 0xc9, 0xe2, 0x0f, 0x62, 0x35, 0xdf, 0xca, 0xe2, 0x77, 0xef,
+ 0xb7, 0x6c, 0x9a, 0xf7, 0xba, 0xf9, 0xe7, 0xb2, 0x69, 0xde, 0xeb, 0xe6,
+ 0x3e, 0x4f, 0x71, 0xb9, 0x4c, 0x6f, 0x31, 0xe6, 0x19, 0x2c, 0x83, 0xbb,
+ 0xe2, 0x79, 0xd4, 0x8e, 0x7e, 0x7b, 0x51, 0x91, 0x8b, 0x9b, 0x7a, 0x44,
+ 0x4e, 0xf7, 0x48, 0x53, 0x4c, 0xc9, 0x98, 0x29, 0xc4, 0x2e, 0x8a, 0x1d,
+ 0x62, 0x05, 0xbb, 0xb8, 0x32, 0x48, 0x91, 0x44, 0x08, 0x49, 0x23, 0x4a,
+ 0xbb, 0x63, 0x44, 0xe8, 0x76, 0x03, 0x63, 0x2b, 0x82, 0x8a, 0x10, 0x62,
+ 0x46, 0x4e, 0xa1, 0x15, 0x7c, 0x1a, 0xc6, 0xa9, 0x43, 0x47, 0x1e, 0x1c,
+ 0x31, 0xaf, 0x4c, 0x09, 0xa1, 0xb0, 0x58, 0x1f, 0xd8, 0x5a, 0xfc, 0xc2,
+ 0x02, 0x0a, 0x45, 0xa7, 0x18, 0x77, 0x6d, 0x25, 0x3c, 0x24, 0x56, 0x0e,
+ 0x6c, 0xd6, 0xde, 0x03, 0x9e, 0xd0, 0x21, 0xc5, 0x81, 0xa8, 0xe6, 0x59,
+ 0x17, 0x26, 0x08, 0x4e, 0xdf, 0xa9, 0x40, 0xb5, 0xa9, 0xc1, 0x43, 0xd8,
+ 0xb5, 0xd0, 0xeb, 0x1e, 0xb9, 0xc7, 0xd6, 0xd5, 0x48, 0x8d, 0x2d, 0x4a,
+ 0xc0, 0x29, 0x54, 0x2c, 0xe0, 0x08, 0x56, 0xb3, 0xec, 0xe1, 0xfb, 0xc6,
+ 0xe1, 0xbb, 0xd2, 0x36, 0xaf, 0xb5, 0x1d, 0xec, 0xf7, 0x20, 0xd8, 0xf0,
+ 0xe2, 0x0a, 0x01, 0x1b, 0x76, 0x30, 0xa4, 0x9b, 0xa7, 0xbc, 0x9b, 0xc7,
+ 0xc1, 0xfd, 0x3e, 0x9c, 0x6c, 0x92, 0xa3, 0x06, 0x70, 0x05, 0xa2, 0x1a,
+ 0x61, 0x38, 0x3a, 0x10, 0x9b, 0x5b, 0xc2, 0xc4, 0x26, 0x72, 0x8d, 0x64,
+ 0x86, 0x25, 0xb3, 0xe0, 0x10, 0x25, 0x5a, 0xaf, 0x98, 0x15, 0x5c, 0xb3,
+ 0x81, 0x9d, 0xb7, 0x6e, 0x39, 0x2e, 0x1d, 0xa5, 0x5d, 0xb6, 0x32, 0xca,
+ 0x56, 0x0e, 0xd1, 0x79, 0x62, 0x20, 0xaf, 0x2e, 0xb6, 0x06, 0xa7, 0x07,
+ 0x1a, 0xa6, 0x2d, 0x8e, 0xd1, 0xb9, 0x6f, 0x2f, 0xbb, 0x8a, 0x2e, 0x4c,
+ 0xec, 0xa4, 0x3d, 0x3e, 0xb8, 0xf1, 0x9d, 0x54, 0x61, 0x47, 0xff, 0x7a,
+ 0x30, 0xa3, 0xa3, 0x7d, 0x1a, 0x4c, 0x49, 0xd9, 0x4b, 0x1b, 0x54, 0x67,
+ 0x10, 0x58, 0x17, 0x82, 0x1d, 0x83, 0x1a, 0xa3, 0xcf, 0x1a, 0x6b, 0xf8,
+ 0xd6, 0x97, 0xd0, 0x37, 0xe9, 0x86, 0x05, 0x39, 0xb5, 0x58, 0x7a, 0x60,
+ 0xd8, 0x0c, 0xce, 0x97, 0x1a, 0xed, 0xa7, 0x37, 0x69, 0x6b, 0x57, 0xc5,
+ 0x37, 0xfc, 0xb1, 0xec, 0xbe, 0xd8, 0xfc, 0x6a, 0xd4, 0xa9, 0xfd, 0x78,
+ 0x98, 0xac, 0xc8, 0xf5, 0x37, 0xb7, 0xa0, 0xdf, 0xa4, 0xc3, 0xd1, 0x34,
+ 0x9c, 0x12, 0x81, 0x8f, 0x54, 0x22, 0x9f, 0xed, 0xc9, 0xdf, 0x76, 0x27,
+ 0xe6, 0x73, 0x7b, 0xf2, 0xa9, 0x3b, 0x39, 0x32, 0xf8, 0xcd, 0x5c, 0xe9,
+ 0x5f, 0x66, 0x61, 0x46, 0x7b, 0xd0, 0x95, 0xdd, 0xcc, 0x7b, 0x11, 0x6f,
+ 0x29, 0x36, 0xad, 0x85, 0xbe, 0x90, 0x57, 0x3a, 0x4e, 0xa2, 0x11, 0x6b,
+ 0x5d, 0xb5, 0x7a, 0xfa, 0x2a, 0x48, 0xea, 0x23, 0xe9, 0x56, 0x41, 0x36,
+ 0x5b, 0x26, 0x46, 0x00, 0xc5, 0xea, 0x16, 0x0d, 0xc0, 0x80, 0x79, 0x3d,
+ 0xca, 0x54, 0x0a, 0xab, 0xed, 0xda, 0xc5, 0xa1, 0xb0, 0x09, 0x6a, 0x26,
+ 0xe2, 0xdf, 0xf3, 0xa6, 0x79, 0x4f, 0x9c, 0x5f, 0xf1, 0x66, 0x69, 0x47,
+ 0x3e, 0x76, 0x3a, 0x42, 0x09, 0xd5, 0xc3, 0x63, 0xc4, 0x8e, 0x2a, 0x35,
+ 0xa7, 0x53, 0x90, 0x1d, 0xe9, 0xa8, 0xa0, 0xfe, 0x99, 0xc3, 0x1f, 0xb5,
+ 0xa0, 0x3f, 0x3a, 0x50, 0xf3, 0xa6, 0x05, 0xa5, 0x35, 0xe9, 0xf1, 0x2d,
+ 0x55, 0xa6, 0xcb, 0xa3, 0xb1, 0x32, 0xaa, 0xb9, 0xcf, 0xad, 0xde, 0xcc,
+ 0x0d, 0x08, 0x61, 0x33, 0x23, 0x64, 0x72, 0x35, 0x2f, 0x1d, 0xb2, 0x71,
+ 0x1e, 0x2a, 0xdb, 0xbe, 0x79, 0x16, 0xe9, 0xaa, 0x44, 0x1f, 0xb3, 0xee,
+ 0x3b, 0x2e, 0x5d, 0x25, 0xc2, 0xea, 0x14, 0xb7, 0x40, 0x53, 0xfc, 0x01,
+ 0x30, 0x3e, 0x2a, 0x5c, 0xcc, 0x4d, 0x4f, 0xb8, 0x8d, 0x7e, 0x9f, 0x90,
+ 0x45, 0xa9, 0x6c, 0x6c, 0x22, 0xcc, 0x7b, 0xc8, 0xd7, 0xa2, 0xd0, 0x34,
+ 0x1e, 0x25, 0x6b, 0x5d, 0x85, 0xa2, 0x3c, 0xc3, 0x15, 0x42, 0x63, 0xb4,
+ 0xd0, 0x6a, 0x97, 0x01, 0x84, 0xaa, 0x74, 0x9f, 0xda, 0xd0, 0x64, 0xd3,
+ 0x57, 0x0f, 0x65, 0x75, 0xd2, 0x45, 0x93, 0x22, 0x39, 0x8e, 0x9d, 0x7b,
+ 0x6b, 0xa8, 0xce, 0x22, 0x75, 0x81, 0x60, 0xaa, 0x0b, 0xd4, 0xef, 0x6b,
+ 0x4e, 0x3f, 0xa0, 0x1d, 0x3f, 0x72, 0xce, 0x01, 0xe8, 0x04, 0xe6, 0x78,
+ 0x39, 0x80, 0x50, 0x43, 0x9e, 0x86, 0xfe, 0x2b, 0x86, 0xa5, 0x71, 0x86,
+ 0x25, 0x68, 0xb1, 0x00, 0x0d, 0x04, 0xcb, 0xc8, 0xf0, 0x94, 0xaf, 0x70,
+ 0xbb, 0x6d, 0x54, 0x6a, 0xf6, 0xa1, 0xc3, 0x7b, 0xb3, 0x8f, 0x09, 0x56,
+ 0xb5, 0x21, 0x1c, 0x89, 0x5b, 0x74, 0xef, 0x49, 0xb3, 0x3a, 0xcf, 0xd2,
+ 0x52, 0xa0, 0x63, 0xaa, 0x72, 0x0a, 0x42, 0xc8, 0xaf, 0x74, 0xf4, 0x03,
+ 0xfe, 0x62, 0x4a, 0x93, 0xb5, 0x85, 0x19, 0x84, 0x16, 0x04, 0xef, 0xd9,
+ 0x6a, 0x59, 0xd9, 0x7b, 0xa8, 0x5b, 0x9d, 0xd2, 0xce, 0x61, 0x9c, 0xcc,
+ 0x35, 0x80, 0xd5, 0x9b, 0xe9, 0xe1, 0x1a, 0x98, 0x58, 0xe9, 0xc0, 0x3a,
+ 0xea, 0xee, 0x1a, 0xea, 0x4d, 0xaf, 0x52, 0xd6, 0xe5, 0x74, 0x9b, 0xa3,
+ 0x4c, 0x27, 0xba, 0xd3, 0x3e, 0x4c, 0xe5, 0xc3, 0x1d, 0xcc, 0xc3, 0x30,
+ 0x91, 0x7b, 0x1a, 0x00, 0x27, 0xc5, 0xa0, 0xed, 0x0d, 0x6d, 0xe7, 0xb8,
+ 0x42, 0xec, 0x49, 0x50, 0xaa, 0x28, 0x43, 0x88, 0x48, 0xc1, 0x3d, 0xf1,
+ 0xe7, 0xf5, 0xc3, 0xad, 0x53, 0xd2, 0x13, 0xf5, 0x32, 0x8b, 0x89, 0x72,
+ 0x9a, 0x68, 0x8c, 0x4d, 0x55, 0xef, 0xcb, 0xf4, 0x49, 0x8c, 0xa4, 0x51,
+ 0xf7, 0x34, 0xb3, 0xca, 0xd2, 0xcb, 0x2d, 0xe7, 0x8e, 0x6b, 0x5d, 0xd7,
+ 0xaa, 0xa0, 0xb9, 0x85, 0x39, 0x7e, 0x8d, 0xc3, 0x33, 0x0c, 0x7f, 0x8a,
+ 0x6f, 0xf3, 0x95, 0xc5, 0x42, 0xee, 0xc6, 0xc7, 0x56, 0xf1, 0xd1, 0xe8,
+ 0xd5, 0x45, 0xd2, 0xc7, 0x49, 0x7a, 0x15, 0x4a, 0x8b, 0x85, 0x0c, 0xaa,
+ 0x93, 0x26, 0x62, 0x68, 0x7b, 0xdc, 0xc6, 0x42, 0x64, 0x71, 0xfb, 0x4f,
+ 0x4e, 0x0a, 0x9e, 0x5a, 0xd5, 0xc4, 0x77, 0xf9, 0x82, 0xee, 0x9f, 0x04,
+ 0x3d, 0x04, 0x6f, 0x60, 0xea, 0x58, 0xf4, 0x5e, 0x24, 0x8a, 0xf2, 0x41,
+ 0xad, 0xf3, 0x86, 0x00, 0x9a, 0xf8, 0x31, 0x55, 0x0b, 0x91, 0xd2, 0x16,
+ 0x60, 0x86, 0xda, 0x94, 0x12, 0xb9, 0x17, 0x17, 0xdd, 0x8a, 0x57, 0x65,
+ 0xf7, 0x78, 0x5c, 0x6c, 0xac, 0x8b, 0x72, 0x7a, 0x26, 0xfc, 0x1a, 0xed,
+ 0x2a, 0x2e, 0x0a, 0x0e, 0xda, 0x14, 0x9a, 0xf8, 0x29, 0x95, 0x2a, 0x21,
+ 0x71, 0x40, 0x5e, 0x5a, 0xe9, 0xf4, 0x1f, 0x18, 0x01, 0xa2, 0xcc, 0xe2,
+ 0x7a, 0x82, 0x8e, 0xd3, 0x42, 0xfa, 0x3b, 0xde, 0x00, 0x8c, 0x8a, 0xcd,
+ 0x6a, 0x98, 0xdb, 0x1c, 0xd5, 0xc8, 0x82, 0xe3, 0x90, 0xbd, 0x28, 0xc8,
+ 0x04, 0x56, 0x81, 0xde, 0xbf, 0x51, 0x40, 0xc0, 0xb9, 0xe7, 0x45, 0x17,
+ 0xef, 0x93, 0x55, 0x0b, 0x0c, 0xfd, 0x21, 0x54, 0x44, 0xf2, 0xb4, 0xf3,
+ 0xfe, 0x67, 0x23, 0x64, 0xbe, 0x70, 0x42, 0x20, 0x1b, 0x9c, 0x20, 0xa2,
+ 0x9c, 0x81, 0x2e, 0x5c, 0x56, 0x4f, 0x19, 0x51, 0x5f, 0x21, 0xc2, 0xbd,
+ 0x30, 0x2d, 0xd1, 0x15, 0xd1, 0x20, 0x39, 0x44, 0xb8, 0xfa, 0x6d, 0x2e,
+ 0x43, 0xa8, 0x1b, 0x43, 0x08, 0x13, 0x1d, 0x2b, 0x9e, 0x91, 0x16, 0xa0,
+ 0xab, 0xf6, 0x00, 0xfe, 0x7b, 0xd7, 0xc8, 0xa5, 0x90, 0xce, 0xe6, 0xc2,
+ 0x74, 0x25, 0x2e, 0xdd, 0x7c, 0x5f, 0xfa, 0xc5, 0x62, 0xd5, 0xf2, 0xdb,
+ 0x95, 0x7e, 0xa3, 0x74, 0xc3, 0x2d, 0x3c, 0xca, 0x37, 0x35, 0x35, 0x15,
+ 0xeb, 0x43, 0x14, 0x97, 0xfa, 0xcb, 0xc5, 0xe0, 0x3c, 0x36, 0xcb, 0xd2,
+ 0x56, 0x11, 0x51, 0xd9, 0x94, 0xf8, 0xb2, 0x97, 0xfd, 0xcc, 0xdd, 0x5f,
+ 0xed, 0xc9, 0xa9, 0xdf, 0xf3, 0x6e, 0x1e, 0x07, 0x8f, 0x6e, 0xe5, 0x1b,
+ 0x37, 0xf9, 0x68, 0x57, 0x7e, 0x82, 0xaa, 0xf9, 0xa2, 0x5f, 0xd9, 0xa1,
+ 0x1c, 0xec, 0x79, 0x1a, 0x35, 0xfa, 0xbf, 0x40, 0xb3, 0xa4, 0x7d, 0xc9,
+ 0xb2, 0xb2, 0xc3, 0x2b, 0xe3, 0xa8, 0x43, 0xc8, 0x09, 0xa5, 0x2d, 0xde,
+ 0xa1, 0x57, 0x20, 0x43, 0xb4, 0x37, 0xa0, 0xfb, 0xb2, 0xf5, 0xf2, 0x8c,
+ 0x54, 0x17, 0x45, 0xaf, 0xa2, 0xa8, 0xdf, 0x45, 0x91, 0xb8, 0x72, 0x79,
+ 0x46, 0xb5, 0xec, 0xd4, 0xd8, 0xbd, 0xe7, 0x62, 0xed, 0xb5, 0xeb, 0x72,
+ 0xfc, 0x5a, 0x78, 0x70, 0xc9, 0x4d, 0x52, 0xca, 0x51, 0x09, 0xe7, 0xe5,
+ 0xa7, 0x36, 0x8b, 0x10, 0xb7, 0xee, 0xc2, 0x24, 0x24, 0x4f, 0x22, 0x44,
+ 0xa7, 0xdf, 0xe5, 0x3d, 0x2c, 0x64, 0x8b, 0xe9, 0xf2, 0x90, 0xd9, 0x90,
+ 0xe3, 0xb2, 0x92, 0x67, 0x20, 0xaf, 0x4d, 0x24, 0xe8, 0xc3, 0x10, 0x2d,
+ 0x2d, 0xbe, 0x59, 0x46, 0x3f, 0xea, 0xb5, 0xb4, 0x30, 0x72, 0x5e, 0xba,
+ 0xe3, 0xe2, 0x7c, 0xc4, 0x53, 0x26, 0x32, 0x9c, 0xf1, 0x49, 0x99, 0x35,
+ 0x5c, 0xc4, 0x30, 0xcd, 0xc5, 0x0b, 0xe0, 0x70, 0x15, 0xbb, 0x33, 0x1d,
+ 0x1b, 0x1d, 0x57, 0x49, 0xbd, 0xc5, 0xee, 0xe9, 0x2e, 0x75, 0xd7, 0x4d,
+ 0xbb, 0x49, 0x8c, 0xa5, 0xee, 0xcd, 0x57, 0xfa, 0xdf, 0xc9, 0xa3, 0x81,
+ 0xb6, 0xea, 0x04, 0x25, 0xc8, 0x3a, 0xa6, 0x76, 0x25, 0xc8, 0x91, 0xb6,
+ 0x4e, 0x3c, 0xe6, 0x22, 0x32, 0xc0, 0x5d, 0xd6, 0x65, 0xf8, 0x46, 0x49,
+ 0x88, 0xaf, 0xea, 0x84, 0x26, 0x21, 0xd2, 0xdd, 0x0e, 0xb8, 0x0d, 0x94,
+ 0x46, 0x35, 0xa4, 0x42, 0x4f, 0x82, 0x88, 0xd1, 0x56, 0xaf, 0x35, 0x72,
+ 0x2e, 0xc9, 0xe8, 0x17, 0x96, 0x4f, 0xa1, 0x40, 0xa4, 0xa5, 0x30, 0xb9,
+ 0xfa, 0xdc, 0x8e, 0xb1, 0x8f, 0xbd, 0xe0, 0x4f, 0x3e, 0x7c, 0x28, 0xe0,
+ 0xf1, 0x91, 0x78, 0x2f, 0xac, 0x32, 0x37, 0x99, 0x8d, 0x5f, 0xd3, 0x1d,
+ 0x91, 0x7d, 0x9a, 0x59, 0xbd, 0xcc, 0x67, 0x57, 0x61, 0x1b, 0x80, 0x74,
+ 0x9a, 0x54, 0xca, 0x0b, 0x37, 0xfa, 0x19, 0x7f, 0x1f, 0xe1, 0x07, 0x90,
+ 0x84, 0x86, 0x1d, 0x8d, 0xb2, 0xba, 0x4b, 0x0d, 0x9a, 0x1c, 0xea, 0xb7,
+ 0x80, 0xd5, 0xa0, 0x3d, 0x58, 0xfa, 0x18, 0x7c, 0xf8, 0xdc, 0x34, 0x09,
+ 0xa8, 0x18, 0xd1, 0xc3, 0x75, 0x70, 0x86, 0xfe, 0x86, 0xe8, 0xd3, 0x89,
+ 0x10, 0x6c, 0x81, 0x6d, 0x84, 0xda, 0x77, 0x63, 0x98, 0x4a, 0x1a, 0x03,
+ 0x25, 0x95, 0x2c, 0x0c, 0x01, 0xeb, 0x45, 0x60, 0x75, 0x36, 0x62, 0x60,
+ 0x3b, 0x69, 0xba, 0x0d, 0xa4, 0x73, 0x87, 0xac, 0xfa, 0x85, 0xae, 0xe6,
+ 0xf4, 0x9b, 0xdf, 0x7e, 0xc4, 0x3a, 0xf3, 0x50, 0x84, 0x1f, 0x39, 0xf5,
+ 0xc3, 0x14, 0xe5, 0xd0, 0x05, 0xad, 0x61, 0xe6, 0xa9, 0x05, 0xdd, 0xe9,
+ 0xcb, 0x5e, 0xbd, 0x34, 0x2c, 0x83, 0xe8, 0x6e, 0x4a, 0x81, 0x96, 0xee,
+ 0x94, 0x2e, 0xf3, 0xda, 0xc8, 0xd4, 0xc1, 0x99, 0x34, 0x40, 0x06, 0x36,
+ 0x89, 0xe7, 0xd0, 0xef, 0xbc, 0x96, 0x61, 0x85, 0x18, 0x22, 0x4a, 0x9e,
+ 0x12, 0xdf, 0x04, 0xda, 0xe5, 0x58, 0x6a, 0x9c, 0xa0, 0x10, 0x28, 0x52,
+ 0xe5, 0x61, 0x97, 0x2e, 0xba, 0xc7, 0x5a, 0x90, 0x1a, 0x38, 0x95, 0xd4,
+ 0xc5, 0xce, 0xcf, 0xbc, 0xda, 0x7c, 0x9c, 0x51, 0x68, 0x5a, 0x53, 0xe6,
+ 0xf4, 0xfc, 0xd3, 0x6b, 0x7f, 0xa0, 0x05, 0x60, 0x9b, 0xba, 0x37, 0x4f,
+ 0xaf, 0x06, 0x7c, 0x96, 0x7a, 0x3a, 0x00, 0x15, 0x15, 0x35, 0x4a, 0x52,
+ 0xd4, 0x1f, 0x4e, 0xcc, 0xc3, 0x9f, 0x4b, 0x1a, 0x8e, 0x7f, 0x94, 0x98,
+ 0x8f, 0x35, 0xd0, 0x0d, 0x84, 0xa7, 0x3b, 0xd8, 0x6d, 0x0f, 0x28, 0x59,
+ 0xd0, 0x2c, 0x85, 0x53, 0x80, 0xb1, 0x23, 0xbc, 0xd2, 0x66, 0x9d, 0xf4,
+ 0x8c, 0xba, 0x65, 0xf0, 0xd8, 0x86, 0xd0, 0xed, 0x93, 0xcc, 0xea, 0x86,
+ 0xd0, 0xce, 0x5a, 0x96, 0x31, 0x2a, 0xbe, 0xbf, 0x2c, 0xbf, 0x81, 0x1e,
+ 0xcd, 0x0c, 0x88, 0x8e, 0x5e, 0xf9, 0x13, 0x83, 0xce, 0x2c, 0x20, 0x31,
+ 0x6f, 0x21, 0xbb, 0xe4, 0xb5, 0x1f, 0x8c, 0xd0, 0xf6, 0x50, 0x1b, 0xdc,
+ 0xcf, 0xf7, 0x58, 0x2a, 0xd8, 0x3c, 0x95, 0xf9, 0xa3, 0xb9, 0xba, 0x11,
+ 0x64, 0xfa, 0xa5, 0xe2, 0x99, 0x78, 0xe3, 0xa5, 0xe1, 0xb6, 0xaa, 0x91,
+ 0xa5, 0x15, 0x83, 0xe0, 0x37, 0x5d, 0x35, 0xb9, 0x57, 0xf7, 0xa5, 0xdf,
+ 0xf8, 0x53, 0xec, 0x9d, 0x36, 0x77, 0xfb, 0x5d, 0x10, 0x34, 0xf0, 0x32,
+ 0x46, 0x0b, 0x54, 0x8d, 0x4a, 0x07, 0xda, 0x9f, 0xc8, 0x4d, 0xfa, 0xb8,
+ 0x57, 0xfe, 0x6e, 0xab, 0x9c, 0x2b, 0xe9, 0xa8, 0xb9, 0xd6, 0x22, 0x3e,
+ 0x09, 0xb4, 0xa0, 0x06, 0xb9, 0xe3, 0x27, 0x0a, 0x2d, 0x3c, 0x60, 0xae,
+ 0xcd, 0x40, 0x04, 0xfa, 0x45, 0x60, 0xd3, 0x4d, 0x2a, 0x9a, 0xb3, 0xb6,
+ 0xbd, 0x53, 0xbd, 0x2c, 0xc0, 0xaa, 0x4d, 0x48, 0x72, 0x52, 0xf7, 0x17,
+ 0x73, 0x02, 0x27, 0x0b, 0x4c, 0xcf, 0xf0, 0x28, 0x49, 0x87, 0x2f, 0x7b,
+ 0x92, 0xe8, 0xea, 0xe8, 0x60, 0xc0, 0xd0, 0xe7, 0xab, 0xd4, 0x2e, 0x49,
+ 0x85, 0x5e, 0xb2, 0x08, 0xed, 0x2d, 0xe6, 0xb3, 0x83, 0xd3, 0x79, 0x3b,
+ 0xbb, 0x4d, 0xc5, 0xbf, 0x9a, 0xbc, 0x2b, 0xcf, 0xfa, 0x25, 0xe2, 0x45,
+ 0x75, 0xd4, 0x2d, 0xdd, 0x88, 0xa8, 0xf7, 0x60, 0xfe, 0x37, 0xaf, 0x5c,
+ 0xb4, 0x02, 0xf1, 0x4c, 0x25, 0x1f, 0x59, 0xf1, 0x6c, 0x86, 0xc0, 0x87,
+ 0x60, 0x11, 0x30, 0xc1, 0x15, 0xf4, 0xe8, 0x6e, 0xc2, 0x7b, 0x08, 0x7e,
+ 0x72, 0x67, 0xca, 0x24, 0x99, 0x26, 0xc2, 0xc5, 0xaa, 0x2e, 0x3f, 0x65,
+ 0xc5, 0x67, 0x23, 0x26, 0xc7, 0x48, 0xca, 0x44, 0x8b, 0xdf, 0x54, 0xe8,
+ 0xbb, 0x26, 0x07, 0x12, 0x99, 0x00, 0x12, 0x58, 0x5b, 0xad, 0x37, 0x5a,
+ 0x4f, 0x1e, 0xae, 0xd5, 0x2b, 0x89, 0xbc, 0xe6, 0x18, 0x6a, 0xd3, 0x92,
+ 0xd4, 0x95, 0xeb, 0xa3, 0x29, 0x40, 0xcd, 0x68, 0xd6, 0x3e, 0x21, 0xd1,
+ 0x71, 0x71, 0x65, 0x4a, 0x88, 0x24, 0xb2, 0xbc, 0x54, 0x45, 0xee, 0xdd,
+ 0xb2, 0xa4, 0x65, 0x7b, 0xed, 0x96, 0x11, 0x7c, 0x18, 0x8f, 0x8a, 0xd3,
+ 0xf6, 0x07, 0x57, 0xe0, 0xaa, 0x06, 0x59, 0x79, 0x13, 0x2c, 0x23, 0x11,
+ 0xc1, 0xa7, 0xad, 0xfe, 0xaa, 0xed, 0xac, 0xbb, 0x43, 0x1e, 0xe9, 0x40,
+ 0x4c, 0xcc, 0xad, 0x26, 0x6a, 0x80, 0xf0, 0x3d, 0xcf, 0xe6, 0x95, 0xdf,
+ 0xfb, 0x29, 0x24, 0xba, 0xc5, 0x71, 0x35, 0x31, 0xb7, 0x98, 0x20, 0x25,
+ 0x09, 0xa5, 0x42, 0xf7, 0xd2, 0xbe, 0xbf, 0x66, 0x31, 0x5f, 0x63, 0xe7,
+ 0x57, 0x7d, 0xfe, 0xd5, 0xe6, 0x5f, 0xbd, 0xfb, 0xc5, 0xc8, 0xe6, 0xd9,
+ 0xba, 0xf7, 0x45, 0x03, 0x97, 0xab, 0xca, 0x6d, 0xde, 0x3f, 0xf8, 0x98,
+ 0xaa, 0xa9, 0xa2, 0x4e, 0x24, 0x1c, 0x46, 0x26, 0xe4, 0xfe, 0x99, 0x76,
+ 0x6d, 0xdd, 0x48, 0x98, 0xee, 0x2f, 0x45, 0xd3, 0xf1, 0x7a, 0xd7, 0xd7,
+ 0x83, 0xd0, 0xeb, 0x79, 0x96, 0x5a, 0x14, 0x92, 0x43, 0x88, 0x56, 0x18,
+ 0x87, 0x39, 0x63, 0x9a, 0x03, 0x0d, 0xc3, 0xb5, 0xee, 0x07, 0xe9, 0xe2,
+ 0xb0, 0xe6, 0x8c, 0x1f, 0xd0, 0x65, 0x5e, 0x60, 0xf6, 0xe5, 0x7b, 0xef,
+ 0x2a, 0x59, 0x52, 0x28, 0xe5, 0x2d, 0x39, 0xa3, 0xeb, 0x03, 0x8f, 0x31,
+ 0xd4, 0xdd, 0x07, 0xd7, 0xaa, 0xeb, 0xce, 0x28, 0x47, 0x74, 0xfd, 0xe6,
+ 0x9c, 0x8a, 0x07, 0xdb, 0x54, 0x3e, 0xe9, 0xcf, 0x22, 0xfa, 0x9d, 0xbc,
+ 0x78, 0x01, 0x62, 0x6e, 0x2f, 0x75, 0xc8, 0x34, 0xba, 0x47, 0xa0, 0x2f,
+ 0x87, 0x30, 0xd6, 0x7d, 0x1a, 0xbb, 0xa3, 0x1f, 0xb8, 0xd3, 0xb0, 0x33,
+ 0x6f, 0x70, 0x38, 0xa8, 0xbe, 0x4d, 0x24, 0xfd, 0xf9, 0xb8, 0x91, 0x90,
+ 0xad, 0x5f, 0x65, 0xec, 0x39, 0x61, 0x00, 0xed, 0xb0, 0xc0, 0xc7, 0x61,
+ 0xdd, 0xc3, 0xb9, 0x84, 0xe2, 0x4a, 0x4c, 0x92, 0x43, 0xc6, 0xe6, 0x67,
+ 0x36, 0x56, 0x01, 0x52, 0x1f, 0x31, 0x4a, 0x4b, 0x17, 0x7e, 0xf5, 0x7f,
+ 0x8d, 0x68, 0x9d, 0x00, 0x65, 0x27, 0x0b, 0x85, 0x9f, 0x0a, 0xef, 0x8c,
+ 0x75, 0x86, 0xac, 0x48, 0xab, 0x40, 0x7d, 0xd9, 0x00, 0x67, 0xe2, 0xad,
+ 0x8d, 0x21, 0xcd, 0xac, 0x2b, 0x96, 0x06, 0x92, 0x1f, 0xa6, 0x9d, 0x90,
+ 0x46, 0x20, 0x45, 0x52, 0x72, 0x8c, 0xba, 0x91, 0xc2, 0x0d, 0x57, 0xcc,
+ 0x40, 0x7b, 0xfc, 0x1c, 0x45, 0x6a, 0x8d, 0x7b, 0xcc, 0xff, 0x00, 0x59,
+ 0x81, 0x84, 0x20, 0x42, 0x67, 0xd2, 0x1b, 0x00, 0x00, 0x01, 0x86, 0x69,
+ 0x43, 0x43, 0x50, 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69,
+ 0x6c, 0x65, 0x00, 0x00, 0x78, 0x9c, 0x7d, 0x91, 0x3d, 0x48, 0xc3, 0x40,
+ 0x1c, 0xc5, 0x5f, 0x53, 0xa5, 0x52, 0x2b, 0x0e, 0x16, 0x11, 0x11, 0xc9,
+ 0x50, 0x9d, 0x2c, 0x88, 0x8a, 0x08, 0x2e, 0x5a, 0x85, 0x22, 0x54, 0x08,
+ 0xb5, 0x42, 0xab, 0x0e, 0x26, 0x97, 0x7e, 0x08, 0x4d, 0x1a, 0x92, 0x14,
+ 0x17, 0x47, 0xc1, 0xb5, 0xe0, 0xe0, 0xc7, 0x62, 0xd5, 0xc1, 0xc5, 0x59,
+ 0x57, 0x07, 0x57, 0x41, 0x10, 0xfc, 0x00, 0x71, 0x73, 0x73, 0x52, 0x74,
+ 0x91, 0x12, 0xff, 0x97, 0x14, 0x5a, 0xc4, 0x7a, 0x70, 0xdc, 0x8f, 0x77,
+ 0xf7, 0x1e, 0x77, 0xef, 0x00, 0xa1, 0x5a, 0x64, 0x9a, 0xd5, 0x36, 0x0a,
+ 0x68, 0xba, 0x6d, 0x26, 0xe3, 0x31, 0x31, 0x9d, 0x59, 0x11, 0x03, 0xaf,
+ 0x08, 0xa2, 0x13, 0xbd, 0x98, 0xc6, 0xa0, 0xcc, 0x2c, 0x63, 0x56, 0x92,
+ 0x12, 0x68, 0x39, 0xbe, 0xee, 0xe1, 0xe3, 0xeb, 0x5d, 0x94, 0x67, 0xb5,
+ 0x3e, 0xf7, 0xe7, 0xe8, 0x52, 0xb3, 0x16, 0x03, 0x7c, 0x22, 0xf1, 0x0c,
+ 0x33, 0x4c, 0x9b, 0x78, 0x9d, 0x78, 0x72, 0xd3, 0x36, 0x38, 0xef, 0x13,
+ 0x87, 0x59, 0x41, 0x56, 0x89, 0xcf, 0x89, 0x47, 0x4c, 0xba, 0x20, 0xf1,
+ 0x23, 0xd7, 0x15, 0x8f, 0xdf, 0x38, 0xe7, 0x5d, 0x16, 0x78, 0x66, 0xd8,
+ 0x4c, 0x25, 0xe7, 0x88, 0xc3, 0xc4, 0x62, 0xbe, 0x89, 0x95, 0x26, 0x66,
+ 0x05, 0x53, 0x23, 0x9e, 0x20, 0x8e, 0xa8, 0x9a, 0x4e, 0xf9, 0x42, 0xda,
+ 0x63, 0x95, 0xf3, 0x16, 0x67, 0xad, 0x58, 0x66, 0xf5, 0x7b, 0xf2, 0x17,
+ 0x86, 0xb2, 0xfa, 0xf2, 0x12, 0xd7, 0x69, 0x0e, 0x20, 0x8e, 0x05, 0x2c,
+ 0x42, 0x82, 0x08, 0x05, 0x65, 0x6c, 0xa0, 0x08, 0x1b, 0x51, 0x5a, 0x75,
+ 0x52, 0x2c, 0x24, 0x69, 0x3f, 0xd6, 0xc2, 0xdf, 0xef, 0xfa, 0x25, 0x72,
+ 0x29, 0xe4, 0xda, 0x00, 0x23, 0xc7, 0x3c, 0x4a, 0xd0, 0x20, 0xbb, 0x7e,
+ 0xf0, 0x3f, 0xf8, 0xdd, 0xad, 0x95, 0x1b, 0x1f, 0xf3, 0x92, 0x42, 0x31,
+ 0xa0, 0xfd, 0xc5, 0x71, 0x3e, 0x86, 0x80, 0xc0, 0x2e, 0x50, 0xab, 0x38,
+ 0xce, 0xf7, 0xb1, 0xe3, 0xd4, 0x4e, 0x00, 0xff, 0x33, 0x70, 0xa5, 0x37,
+ 0xfc, 0xa5, 0x2a, 0x30, 0xf5, 0x49, 0x7a, 0xa5, 0xa1, 0x45, 0x8e, 0x80,
+ 0xee, 0x6d, 0xe0, 0xe2, 0xba, 0xa1, 0x29, 0x7b, 0xc0, 0xe5, 0x0e, 0xd0,
+ 0xf7, 0x64, 0xc8, 0xa6, 0xec, 0x4a, 0x7e, 0x9a, 0x42, 0x2e, 0x07, 0xbc,
+ 0x9f, 0xd1, 0x37, 0x65, 0x80, 0x9e, 0x5b, 0x20, 0xb8, 0xea, 0xf5, 0x56,
+ 0xdf, 0xc7, 0xe9, 0x03, 0x90, 0xa2, 0xae, 0x12, 0x37, 0xc0, 0xc1, 0x21,
+ 0x30, 0x9c, 0xa7, 0xec, 0xb5, 0x16, 0xef, 0xee, 0x68, 0xee, 0xed, 0xdf,
+ 0x33, 0xf5, 0xfe, 0x7e, 0x00, 0xb6, 0x7a, 0x72, 0xc2, 0xb7, 0x19, 0xd7,
+ 0x5a, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f, 0x00, 0x00, 0x00, 0x09, 0x70,
+ 0x48, 0x59, 0x73, 0x00, 0x00, 0x2e, 0x23, 0x00, 0x00, 0x2e, 0x23, 0x01,
+ 0x78, 0xa5, 0x3f, 0x76, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45,
+ 0x07, 0xe5, 0x0a, 0x0b, 0x17, 0x1e, 0x25, 0x91, 0xc0, 0xe1, 0x5c, 0x00,
+ 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65,
+ 0x6e, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77,
+ 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0x0e, 0x17,
+ 0x00, 0x00, 0x00, 0x8f, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0xa5, 0x92,
+ 0x49, 0x0e, 0xc0, 0x20, 0x0c, 0x03, 0x1d, 0x8b, 0xff, 0x7f, 0xd9, 0x3d,
+ 0x54, 0xdd, 0x21, 0x5b, 0x91, 0x10, 0x82, 0x90, 0x89, 0x21, 0x36, 0x00,
+ 0x02, 0x84, 0xee, 0xe0, 0xbe, 0xd8, 0x5f, 0x40, 0x1f, 0x42, 0x00, 0x90,
+ 0xd4, 0x86, 0x9c, 0x0a, 0xba, 0x10, 0xde, 0x37, 0x1d, 0x08, 0xdf, 0x07,
+ 0x55, 0x08, 0x67, 0x87, 0x15, 0x08, 0x57, 0x81, 0x2c, 0x84, 0x5e, 0x30,
+ 0x03, 0x61, 0x24, 0x31, 0x82, 0x30, 0xf3, 0x51, 0x1e, 0x84, 0xd9, 0x76,
+ 0xad, 0x20, 0xac, 0x98, 0x66, 0x06, 0x61, 0xd5, 0xba, 0x6f, 0xc8, 0xf0,
+ 0x2e, 0x9b, 0x45, 0x3e, 0xb0, 0xb9, 0x82, 0x23, 0xf1, 0xaa, 0xa6, 0xe5,
+ 0x64, 0xbd, 0xaa, 0xd3, 0x85, 0x3d, 0x59, 0x93, 0x37, 0x27, 0x8c, 0xf4,
+ 0x4c, 0x56, 0x5a, 0x09, 0x57, 0x95, 0xb3, 0x2a, 0x78, 0x7d, 0x52, 0xa7,
+ 0x0b, 0x80, 0x01, 0x92, 0x1b, 0x7e, 0x6a, 0xf9, 0xdc, 0x18, 0x81, 0x6d,
+ 0x42, 0x05, 0x1b, 0x88, 0xd3, 0x3f, 0x1e, 0x42, 0x28, 0x07, 0xad, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+unsigned int mouse_png_len = 4907;
+
+#else // EMBED_HERE
+
+extern unsigned char mouse_png[];
+extern unsigned int mouse_png_len;
+
+#endif // EMBED_HERE
+
+
+#pragma GCC diagnostic pop
+
+
+#endif // MOUSE_PNG_H
diff --git a/client/src/firstrun.c b/client/src/firstrun.c
deleted file mode 100644
index d931b06..0000000
--- a/client/src/firstrun.c
+++ /dev/null
@@ -1,138 +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 .
- *
- */
-
-
-#include "config.h"
-#include "log.h"
-#include "memory.h"
-#include "timer.h"
-#include "task.h"
-#include "network.h"
-#include "settings.h"
-
-#include "firstrun.h"
-
-
-static uint8_t _firstRunRunning = 1;
-
-
-static void firstRunFail(void);
-static void taskFirstRun(void *data);
-static void taskFirstRunHelper(void *data);
-
-
-static void firstRunFail(void) {
- netShutdown();
- taskShutdown();
- timerShutdown();
- configShutdown();
- osShutdown();
- logClose();
- memoryShutdown();
- exit(1);
-}
-
-
-void firstRunCheckSetup(void) {
- // ***TODO*** Check for needed files here.
- mkdir("cache", 0777);
-
- taskCreate(taskFirstRunHelper, NULL);
- taskCreate(taskFirstRun, NULL);
- taskRun();
-}
-
-
-static void taskFirstRun(void *data) {
- int8_t comPort = -1;
- int8_t r = 0;
-
- (void)data;
-
- logWrite("First Run Setup\n");
- logWrite("===============\n\n");
-
- // 0 1 2 3 4 5 6 7 8
- // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
- logWrite("Welcome to the KangaWorld Client! Before you can connect to KangaWorld, Setup\n");
- logWrite("needs to detect a compatible softmodem and download several files.\n\n");
- logWrite("One moment while we check for a compatible softmodem...\n\n");
-
- comPort = settingsScanComPorts();
-
- if (comPort < 0) {
- logWrite("Unable to detect a compatible softmodem! For assistance, visit:\n");
- logWrite("https://Kanga.World\n");
- firstRunFail();
- }
-
- logWrite("Compatible softmodem found on COM%d:! Connecting to KangaWorld...\n\n", comPort + 1);
-
- logWrite("Initializing modem...\n");
- r = netConnectStep1();
- if (r == NETWORK_CONNECT_OPEN_FAILED) {
- logWrite("Unable to open COM port! Please check settings.\n");
- _firstRunRunning = 0;
- return;
- }
- if (r == NETWORK_CONNECT_BAD_MODEM) {
- logWrite("Modem does not support ENET! Please check settings.\n");
- _firstRunRunning = 0;
- return;
- }
-
- logWrite("Dialing modem...\n");
- r = netConnectStep2();
- if (r == NETWORK_CONNECT_NO_CARRIER) {
- logWrite("Unable to connect to server! Please check settings or try later.\n");
- _firstRunRunning = 0;
- return;
- }
- if (r == NETWORK_CONNECT_BAD_ENCRYPTION) {
- logWrite("Unable to negotiate encryption settings!\n");
- _firstRunRunning = 0;
- return;
- }
- if (r == NETWORK_CONNECT_BAD_SETTINGS) {
- logWrite("Unable to fetch client settings!\n");
- _firstRunRunning = 0;
- return;
- }
-
- logWrite("Connected! Pre-caching needed files...\n");
-
-
- logWrite("Disconnecting...\n");
- netDisconnect();
-
- _firstRunRunning = 0;
-
- return;
-}
-
-
-static void taskFirstRunHelper(void *data) {
-
- (void)data;
-
- while (_firstRunRunning) {
- timerUpdate();
- taskYield();
- }
-}
diff --git a/client/src/gui/button.c b/client/src/gui/button.c
index 45d19b0..9c87cb7 100644
--- a/client/src/gui/button.c
+++ b/client/src/gui/button.c
@@ -77,7 +77,7 @@ static void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_
// Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) {
- if (b->clicked) b->clicked(widget);
+ if (b->clicked) guiPendingEventAdd(widget, b->clicked);
}
}
diff --git a/client/src/gui/checkbox.c b/client/src/gui/checkbox.c
index f2e151a..dd399b0 100644
--- a/client/src/gui/checkbox.c
+++ b/client/src/gui/checkbox.c
@@ -64,7 +64,7 @@ static void checkboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint1
// Toggle value.
checkboxValueSet(c, !checkboxValueGet(c));
// Fire callback on mouse up.
- if (c->clicked) c->clicked(widget);
+ if (c->clicked) guiPendingEventAdd(widget, c->clicked);
}
}
diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c
index 369df14..51110e5 100644
--- a/client/src/gui/gui.c
+++ b/client/src/gui/gui.c
@@ -22,10 +22,16 @@
#include "gui.h"
-#include "embedded/vga8x14.h"
#include "widget.h"
#include "desktop.h"
#include "window.h"
+#include "embedded/embedded.h"
+
+
+typedef struct PendingEventsS {
+ WidgetT *widget;
+ widgetCallback callback;
+} PendingEventsT;
int16_t _guiMetric[METRIC_COUNT];
@@ -37,13 +43,23 @@ uint16_t _guiDragOffsetY = 0;
WindowT *_guiActiveWindow = NULL;
-static DesktopT *_guiDesktop = NULL;
-static WidgetT *_guiLastWidgetLeft = NULL;
-static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
-static WidgetT *_guiFocused = NULL;
-static uint8_t _guiHasStopped = 0; // This starts as 0 even if the GUI hasn't been started.
-static WidgetT ***_guiDeleteList = NULL;
-
+static DesktopT *_guiDesktop = NULL;
+static WidgetT *_guiLastWidgetLeft = NULL;
+static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
+static WidgetT *_guiFocused = NULL;
+static uint8_t _guiHasStopped = 0; // This starts as 0 even if the GUI hasn't been started.
+static WidgetT ***_guiDeleteList = NULL;
+static uint32_t _guiTimerValue = 0;
+static uint32_t _guiTimerLast = 0;
+static uint32_t _guiTimerHalfSecond = 0;
+static uint32_t _guiTimerSecond = 0;
+static uint32_t _guiTimerQuarterSecondTick = 0;
+static uint32_t _guiTimerHalfSecondTick = 0;
+static uint32_t _guiTimerSecondTick = 0;
+static uint32_t _guiTimerQuarterSecondOn = 0;
+static uint32_t _guiTimerHalfSecondOn = 0;
+static uint32_t _guiTimerSecondOn = 0;
+static PendingEventsT **_guiPendingEvents = NULL;
// Widget Magic Debug Info. Don't forget to change MagicE!
static char *_magicDebugNames[MAGIC_COUNT] = {
@@ -191,6 +207,10 @@ void guiDelete(WidgetT **widget) {
// Since deleting happens in widget events, it's not safe to do it
// immediately. Instead, we make a list of what to delete and
// then process it before painting.
+
+ // This may be redundant now since there is a pending event list
+ // that is also handled in the paint event.
+
arrput(_guiDeleteList, widget);
}
@@ -249,7 +269,6 @@ static void guiDeleteListItem(WidgetT **widget) {
if (plen == 1) {
// Erase the list.
arrfree(w->parent->children);
- w->parent->children = NULL;
}
}
}
@@ -259,7 +278,6 @@ static void guiDeleteListItem(WidgetT **widget) {
if (w == _guiFocused) _guiFocused = NULL;
// Delete us.
- //logWrite("Deleting %s %p\n", _magicDebugNames[w->magic], w);
if (w->delMethod != NULL) w->delMethod(&w);
arrfree(w->children);
if (w->surface != NULL) {
@@ -455,6 +473,14 @@ void guiMouseProcess(MouseT *mouse) {
void guiPaint(WidgetT *widget) {
+ // Process any pending events.
+ while (arrlen(_guiPendingEvents)) {
+ _guiPendingEvents[0]->callback(_guiPendingEvents[0]->widget);
+ DEL(_guiPendingEvents[0]);
+ arrdel(_guiPendingEvents, 0);
+ }
+ arrfree(_guiPendingEvents);
+
// Process any pending widget deletions.
guiDeleteList();
@@ -512,6 +538,16 @@ void guiParentAndChildrenDirtySet(WidgetT *widget) {
}
+void guiPendingEventAdd(WidgetT *widget, void *callback) {
+ PendingEventsT *p = NULL;
+
+ NEW(PendingEventsT, p);
+ p->callback = callback;
+ p->widget = widget;
+ arrput(_guiPendingEvents, p);
+}
+
+
WidgetT *guiRootGet(void) {
return (WidgetT *)_guiDesktop;
}
@@ -648,6 +684,86 @@ void guiStop(void) {
}
+uint32_t guiTimerGet(void) {
+ return _guiTimerValue;
+}
+
+
+uint8_t guiTimerHalfSecondOn(void) {
+ return _guiTimerHalfSecondOn;
+}
+
+
+uint8_t guiTimerHalfSecondTick(void) {
+ return _guiTimerHalfSecondTick;
+}
+
+
+void guiTimerProcess(uint32_t rawClock) {
+ uint32_t delta;
+
+ _guiTimerValue = rawClock;
+
+ // Reset ticks.
+ _guiTimerQuarterSecondTick = 0;
+ _guiTimerHalfSecondTick = 0;
+ _guiTimerSecondTick = 0;
+
+ // Ensure we haven't rolled past midnight between calls.
+ if (_guiTimerValue >= _guiTimerLast) {
+ delta = _guiTimerValue - _guiTimerLast;
+ } else {
+ // Compensate for midnight rollover.
+ delta = (_guiTimerValue + TICKS_PER_DAY) - _guiTimerLast;
+ }
+
+ // Everything ticks off the quarter second.
+ if (delta > TICKS_PER_SECOND * 0.25) {
+ _guiTimerLast = _guiTimerValue;
+
+ // Quarter Second timer.
+ _guiTimerQuarterSecondOn = !_guiTimerQuarterSecondOn;
+ _guiTimerQuarterSecondTick = 1;
+
+ // Half Second timer.
+ if (--_guiTimerHalfSecond == 0) {
+ _guiTimerHalfSecond = 2;
+ _guiTimerHalfSecondOn = !_guiTimerHalfSecondOn;
+ _guiTimerHalfSecondTick = 1;
+
+ // Second timer
+ if (--_guiTimerSecond == 0) {
+ _guiTimerSecond = 2;
+ _guiTimerSecondOn = !_guiTimerSecondOn;
+ _guiTimerSecondTick = 1;
+ } // Second.
+
+ } // Half Second.
+
+ } // Quarter Second.
+}
+
+
+uint8_t guiTimerQuarterSecondOn(void) {
+ return _guiTimerQuarterSecondOn;
+}
+
+
+uint8_t guiTimerQuarterSecondTick(void) {
+ return _guiTimerQuarterSecondTick;
+}
+
+
+uint8_t guiTimerSecondOn(void) {
+ return _guiTimerSecondOn;
+}
+
+
+uint8_t guiTimerSecondTick(void) {
+ return _guiTimerSecondTick;
+}
+
+
void *guiUserDataGet(WidgetT *widget) {
return widget->userData;
}
diff --git a/client/src/gui/gui.h b/client/src/gui/gui.h
index 948d0bd..1d2b246 100644
--- a/client/src/gui/gui.h
+++ b/client/src/gui/gui.h
@@ -54,6 +54,7 @@ enum MagicE {
MAGIC_UPDOWN,
MAGIC_LISTBOX,
MAGIC_TERMINAL,
+ MAGIC_TIMER,
//MAGIC_DROPDOWN,
MAGIC_COUNT
};
@@ -201,10 +202,19 @@ void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *
void guiMouseProcess(MouseT *mouse);
void guiPaint(WidgetT *widget);
void guiParentAndChildrenDirtySet(WidgetT *widget);
+void guiPendingEventAdd(WidgetT *widget, void *callback);
WidgetT *guiRootGet(void);
void guiShutdown(void);
DesktopT *guiStartup(void);
void guiStop(void);
+uint32_t guiTimerGet(void);
+uint8_t guiTimerHalfSecondOn(void);
+uint8_t guiTimerHalfSecondTick(void);
+void guiTimerProcess(uint32_t rawClock);
+uint8_t guiTimerQuarterSecondOn(void);
+uint8_t guiTimerQuarterSecondTick(void);
+uint8_t guiTimerSecondOn(void);
+uint8_t guiTimerSecondTick(void);
void *guiUserDataGet(WidgetT *widget);
void guiUserDataSet(WidgetT *widget, void *userData);
void guiWidgetAndChildrenDirtySet(WidgetT *widget);
diff --git a/client/src/gui/image.c b/client/src/gui/image.c
index e93e3af..811dc58 100644
--- a/client/src/gui/image.c
+++ b/client/src/gui/image.c
@@ -26,6 +26,9 @@
#include "vesa.h"
+static ImageT *imageNativeImageGet(unsigned char *raw, uint16_t x, uint16_t y);
+
+
ImageT *imageAllocate(uint16_t w, uint16_t h) {
uint16_t x;
uint16_t y;
@@ -78,6 +81,20 @@ ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color) {
}
+ImageT *imageFromRAMLoad(uint8_t *buffer, size_t len) {
+ uint16_t x;
+ uint16_t y;
+ uint16_t n;
+ unsigned char *raw;
+
+ // Load image from RAM.
+ raw = stbi_load_from_memory((const unsigned char *)buffer, len, (int *)&x, (int *)&y, (int *)&n, 3);
+ if (!raw) return NULL;
+
+ return imageNativeImageGet(raw, x, y);
+}
+
+
uint16_t imageHeightGet(ImageT *image) {
return image->height;
}
@@ -104,14 +121,20 @@ ImageT *imageLoad(char *filename) {
uint16_t x;
uint16_t y;
uint16_t n;
- uint32_t b;
unsigned char *raw;
- ImageT *image;
// Load image from disk
raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, 3);
if (!raw) return NULL;
+ return imageNativeImageGet(raw, x, y);
+}
+
+
+static ImageT *imageNativeImageGet(unsigned char *raw, uint16_t x, uint16_t y) {
+ uint32_t b;
+ ImageT *image;
+
// Create native image.
image = imageAllocate(x, y);
if (!image) {
diff --git a/client/src/gui/image.h b/client/src/gui/image.h
index 57ee183..5ebac64 100644
--- a/client/src/gui/image.h
+++ b/client/src/gui/image.h
@@ -37,6 +37,7 @@ typedef struct ImageS {
ImageT *imageAllocate(uint16_t w, uint16_t h);
ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color);
+ImageT *imageFromRAMLoad(uint8_t *buffer, size_t len);
uint16_t imageHeightGet(ImageT *image);
uint8_t imageInfoGet(char *filename, uint16_t *width, uint16_t *height);
ImageT *imageLoad(char *filename);
diff --git a/client/src/gui/label.c b/client/src/gui/label.c
index 0bd5213..de75bc1 100644
--- a/client/src/gui/label.c
+++ b/client/src/gui/label.c
@@ -95,7 +95,7 @@ static void labelMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t
// Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) {
- if (l->clicked) l->clicked(widget);
+ if (l->clicked) guiPendingEventAdd(widget, l->clicked);
}
}
diff --git a/client/src/gui/picture.c b/client/src/gui/picture.c
index 1986c27..6cc5077 100644
--- a/client/src/gui/picture.c
+++ b/client/src/gui/picture.c
@@ -67,7 +67,7 @@ static void pictureMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16
// Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) {
- if (p->clicked) p->clicked(widget);
+ if (p->clicked) guiPendingEventAdd(widget, p->clicked);
}
}
diff --git a/client/src/gui/radio.c b/client/src/gui/radio.c
index cf01acf..3c42180 100644
--- a/client/src/gui/radio.c
+++ b/client/src/gui/radio.c
@@ -70,7 +70,7 @@ static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t
// Select us.
radioSelectedSet(r);
// Fire callback on mouse up.
- if (r->clicked) r->clicked(widget);
+ if (r->clicked) guiPendingEventAdd(widget, r->clicked);
}
}
diff --git a/client/src/gui/textbox.c b/client/src/gui/textbox.c
index c1806e1..6fc8dba 100644
--- a/client/src/gui/textbox.c
+++ b/client/src/gui/textbox.c
@@ -301,7 +301,7 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
free(draw);
// Draw cursor.
- if (guiFocusGet() == widget && __timerQuarterSecondOn) {
+ if (guiFocusGet() == widget && guiTimerQuarterSecondOn()) {
caretPos = textX + fontWidthGet(_guiFont) * t->caret;
fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], caretPos, textY);
}
diff --git a/client/src/gui/timer.c b/client/src/gui/timer.c
new file mode 100644
index 0000000..8f8ebcb
--- /dev/null
+++ b/client/src/gui/timer.c
@@ -0,0 +1,109 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#include "timer.h"
+
+
+static void timerPaint(WidgetT *widget, uint8_t enabled, RectT pos);
+
+
+WidgetT *timerInit(WidgetT *widget, widgetCallback timeout, uint16_t quarterSeconds) {
+ TimerT *t = (TimerT *)widget;
+
+ t->running = 1;
+ t->counter = 0;
+ t->quarterSeconds = quarterSeconds;
+ t->timeout = timeout;
+ t->base.paintMethod = timerPaint;
+
+ // We use the paint event to handle timer processing.
+ GUI_SET_FLAG(widget, WIDGET_FLAG_ALWAYS_PAINT);
+
+ return widget;
+}
+
+
+TimerT *timerNew(widgetCallback timeout, uint16_t quarterSeconds) {
+ TimerT *timer = (TimerT *)malloc(sizeof(TimerT));
+ WidgetT *widget = NULL;
+
+ if (!timer) return NULL;
+
+ widget = widgetInit(W(timer), MAGIC_TIMER, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (!widget) {
+ free(timer);
+ return NULL;
+ }
+
+ timer = (TimerT *)timerInit((WidgetT *)timer, timeout, quarterSeconds);
+ if (!timer) {
+ free(timer);
+ return NULL;
+ }
+
+ return timer;
+}
+
+
+static void timerPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
+ TimerT *t = (TimerT *)widget;
+
+ (void)enabled;
+ (void)pos;
+
+ // Do we care?
+ if (t->running) {
+ // Everything ticks off the quarter second.
+ if (guiTimerQuarterSecondTick()) t->counter++;
+ // We don't check for timeout inside the tick condition so that timers of 0 fire immediately.
+ if (t->counter >= t->quarterSeconds) {
+ // Timeout! Call user.
+ guiPendingEventAdd(widget, t->timeout);
+ t->counter = 0;
+ }
+ }
+}
+
+
+void timerQuarterSecondsSet(TimerT *timer, uint16_t quarterSeconds) {
+ timer->quarterSeconds = quarterSeconds;
+ timer->counter = 0;
+}
+
+
+void timerReset(TimerT *timer) {
+ timer->counter = 0;
+}
+
+
+void timerStart(TimerT *timer) {
+ timer->counter = 0;
+ timer->running = 1;
+}
+
+
+void timerStop(TimerT *timer) {
+ timer->running = 0;
+}
+
+
+void timerTimeoutSet(TimerT *timer, widgetCallback timeout) {
+ timer->timeout = timeout;
+}
diff --git a/client/src/system/timer.h b/client/src/gui/timer.h
similarity index 55%
rename from client/src/system/timer.h
rename to client/src/gui/timer.h
index f9b8fd0..5c74278 100644
--- a/client/src/system/timer.h
+++ b/client/src/gui/timer.h
@@ -22,22 +22,26 @@
#define TIMER_H
-#include "os.h"
+#include "gui.h"
+#include "widget.h"
-extern uint8_t __timerQuarterSecondTick;
-extern uint8_t __timerHalfSecondTick;
-extern uint8_t __timerSecondTick;
-
-extern uint8_t __timerQuarterSecondOn;
-extern uint8_t __timerHalfSecondOn;
-extern uint8_t __timerSecondOn;
+typedef struct TimerS {
+ WidgetT base; // Must be first in every widget
+ widgetCallback timeout;
+ uint16_t quarterSeconds;
+ uint16_t counter;
+ uint8_t running;
+} TimerT;
-void timerShutdown(void);
-void timerStartup(void);
-void timerUpdate(void);
-void timerQuarterSecondsWait(uint8_t quarterSeconds);
+WidgetT *timerInit(WidgetT *widget, widgetCallback timeout, uint16_t quarterSeconds);
+TimerT *timerNew(widgetCallback timeout, uint16_t quarterSeconds);
+void timerQuarterSecondsSet(TimerT *timer, uint16_t quarterSeconds);
+void timerReset(TimerT *timer);
+void timerStart(TimerT *timer);
+void timerStop(TimerT *timer);
+void timerTimeoutSet(TimerT *timer, widgetCallback timeout);
#endif // TIMER_H
diff --git a/client/src/gui/updown.c b/client/src/gui/updown.c
index 7ef5b93..d33b6ca 100644
--- a/client/src/gui/updown.c
+++ b/client/src/gui/updown.c
@@ -310,7 +310,7 @@ static void updownPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
fontRender(_guiFont, draw, _guiColor[COLOR_UPDOWN_TEXT], _guiColor[COLOR_UPDOWN_BACKGROUND], textX, textY);
// Draw cursor.
- if (guiFocusGet() == widget && __timerQuarterSecondOn) {
+ if (guiFocusGet() == widget && guiTimerQuarterSecondOn()) {
textX += (strlen(draw) - 1) * fontWidthGet(_guiFont);
fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], textX, textY);
}
diff --git a/client/src/hangup.c b/client/src/hangup.c
new file mode 100644
index 0000000..7438dbc
--- /dev/null
+++ b/client/src/hangup.c
@@ -0,0 +1,107 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#include "window.h"
+#include "label.h"
+#include "timer.h"
+
+#include "taglist.h"
+#include "config.h"
+#include "network.h"
+#include "comport.h"
+
+#include "hangup.h"
+
+
+typedef enum HangupStateE {
+ S_START_HANGUP = 0,
+ S_WAITING
+} HangupStateT;
+
+
+static widgetCallback _done = NULL;
+static WindowT *_winHangup = NULL;
+static LabelT *_lblHangup = NULL;
+static TimerT *_timProgress = NULL;
+static HangupStateT _state = S_START_HANGUP;
+
+
+static void timHangupProgress(WidgetT *widget);
+
+
+void hangupShow(void *nextFunction) {
+
+ _done = (widgetCallback)nextFunction;
+
+ TagItemT uiDetecting[] = {
+ T_START,
+ T_WINDOW, O(_winHangup),
+ T_TITLE, P("Goodbye"),
+ T_WIDTH, 200, T_HEIGHT, 100,
+ T_LABEL, O(_lblHangup),
+ T_X, 41, T_Y, 25,
+ T_TITLE, P("Disconnecting!"),
+ T_LABEL, T_DONE,
+ T_TIMER, O(_timProgress),
+ T_EVENT, P(timHangupProgress),
+ T_VALUE, 0,
+ T_TIMER, T_DONE,
+ T_WINDOW, T_DONE,
+ T_END
+ };
+
+ // We can use a module-global variable instead of widget user data
+ // because there will never be more than one disconnect dialog on
+ // the screen at a time.
+ _state = S_START_HANGUP;
+
+ tagListRun(uiDetecting);
+}
+
+
+static void timHangupProgress(WidgetT *widget) {
+ PacketEncodeDataT encoded = { 0 };
+ TimerT *t = (TimerT *)widget;
+
+ switch (_state) {
+ case S_START_HANGUP:
+ // Tell server we're disconnecting.
+ encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
+ encoded.control = PACKET_CONTROL_DAT;
+ encoded.channel = 0;
+ encoded.encrypt = 0;
+ packetEncode(__packetThreadData, &encoded, NULL, 0);
+ packetSend(__packetThreadData, &encoded);
+ // Snooze a bit for the packet to send.
+ _state = S_WAITING;
+ timerQuarterSecondsSet(t, 3 * 4);
+ break;
+
+ case S_WAITING:
+ // Shut down packet processing & COM port.
+ netShutdown();
+ comClose(__configData.serialCom - 1);
+ timerStop(t);
+ // On to the next dialog.
+ guiDelete(D(_winHangup));
+ _done(NULL);
+ break;
+ }
+}
diff --git a/client/src/firstrun.h b/client/src/hangup.h
similarity index 89%
rename from client/src/firstrun.h
rename to client/src/hangup.h
index dd7f45b..e64d166 100644
--- a/client/src/firstrun.h
+++ b/client/src/hangup.h
@@ -18,14 +18,14 @@
*/
-#ifndef FIRSTRUN_H
-#define FIRSTRUN_H
+#ifndef HANGUP_H
+#define HANGUP_H
#include "os.h"
-void firstRunCheckSetup(void);
+void hangupShow(void *nextFunction);
-#endif // FIRSTRUN_H
+#endif // HANGUP_H
diff --git a/client/src/linux/linux.c b/client/src/linux/linux.c
index 359a92f..57d5519 100644
--- a/client/src/linux/linux.c
+++ b/client/src/linux/linux.c
@@ -32,9 +32,6 @@
#include "comport.h"
-#define SECONDS_IN_DAY 86400
-#define TICKS_PER_SECOND 18.2
-#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
#define TIMER_INTERVAL (1000 / TICKS_PER_SECOND)
#define COM_BUFFER_SIZE 2048
@@ -61,7 +58,7 @@ static uint8_t _ASCIIKeep = 0;
static uint8_t _scanCodeKeep = 0;
static uint8_t _keyPressed = 0;
static uint8_t _debounce = 0;
-static long _timerTicks = 0;
+static uint32_t _timerTicks = 0;
static SDL_TimerID _timerID = { 0 };
static ENetHost *_host = NULL;
static ENetPeer *_peer = NULL;
@@ -86,10 +83,7 @@ static uint32_t timerCallback(uint32_t interval, void *param);
static void vbeScreenshot(void);
-long biostime(int cmd, long newtime) {
- (void)cmd;
- (void)newtime;
-
+uint32_t rawclock(void) {
return _timerTicks;
}
diff --git a/client/src/login.c b/client/src/login.c
index 8328a95..b5e2612 100644
--- a/client/src/login.c
+++ b/client/src/login.c
@@ -21,61 +21,82 @@
#include "textbox.h"
#include "button.h"
#include "msgbox.h"
+#include "timer.h"
#include "runtime.h"
#include "config.h"
#include "comport.h"
#include "network.h"
#include "taglist.h"
-#include "timer.h"
-#include "task.h"
#include "login.h"
#include "signup.h"
#include "welcome.h"
#include "menu.h"
+#include "hangup.h"
-static WindowT *_winLogin = NULL;
-static TextboxT *_txtUser = NULL;
-static TextboxT *_txtPass = NULL;
-static ButtonT *_btnCancel = NULL;
-static ButtonT *_btnSignUp = NULL;
-static ButtonT *_btnLogin = NULL;
+typedef enum LoginStateE {
+ S_START_LOGIN = 0,
+ S_WAIT_LOGIN
+} LoginStateT;
+
+
+static WindowT *_winLogin = NULL;
+static TextboxT *_txtUser = NULL;
+static TextboxT *_txtPass = NULL;
+static ButtonT *_btnCancel = NULL;
+static ButtonT *_btnSignUp = NULL;
+static ButtonT *_btnLogin = NULL;
+static TimerT *_timProgress = NULL;
+static LoginStateT _state = S_START_LOGIN;
+static uint8_t _channel = 0;
static void btnCancelClick(WidgetT *widget);
+static void btnLoginClick(WidgetT *widget);
static void btnSignUpClick(WidgetT *widget);
static void btnMsgBoxCancel(MsgBoxButtonT button);
static void btnMsgBoxContinue(MsgBoxButtonT button);
+static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled);
-static void taskDisconnect(void *data);
-static void taskLoginClick(void *data);
+static void timLoginProgress(WidgetT *widget);
static void btnCancelClick(WidgetT *widget) {
(void)widget;
- // ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
-
setButtons(0);
msgBoxTwo("Cancel?", MSGBOX_ICON_QUESTION, "Cancel login?\n \nThis will disconnect you from the server.", "Okay", btnMsgBoxCancel, "Cancel", btnMsgBoxCancel);
}
+static void btnLoginClick(WidgetT *widget) {
+ (void)widget;
+
+ setButtons(0);
+
+ _state = S_START_LOGIN;
+ timerQuarterSecondsSet(_timProgress, 0);
+ timerStart(_timProgress);
+}
+
+
static void btnSignUpClick(WidgetT *widget) {
(void)widget;
+ netChannelRelease(_channel);
guiDelete(D(_winLogin));
- taskCreate(taskSignUp, NULL);
+ signupShow();
}
static void btnMsgBoxCancel(MsgBoxButtonT button) {
if (button == MSGBOX_BUTTON_ONE) {
+ netChannelRelease(_channel);
guiDelete(D(_winLogin));
- taskCreate(taskDisconnect, taskWelcome);
+ hangupShow(welcomeShow);
} else {
setButtons(1);
}
@@ -89,24 +110,9 @@ static void btnMsgBoxContinue(MsgBoxButtonT button) {
}
-static void setButtons(uint8_t enabled) {
- widgetEnableSet(W(_btnCancel), enabled);
- widgetEnableSet(W(_btnSignUp), enabled);
- widgetEnableSet(W(_btnLogin), enabled);
-}
+void loginShow() {
-
-static void taskDisconnect(void *nextTask) {
- netDisconnect();
- if (nextTask) taskCreate(taskWelcome, nextTask);
-}
-
-
-void taskLogin(void *data) {
-
- (void)data;
-
- // ***TODO*** We used to have a FORGOT PASSWORD button here, too.
+ // ***TODO*** We used to have a FORGOT PASSWORD link here, too.
TagItemT uiLogin[] = {
T_START,
@@ -142,70 +148,88 @@ void taskLogin(void *data) {
T_BUTTON, O(_btnLogin),
T_TITLE, P("Login"),
T_X, 199, T_Y, 85,
- T_CLICK, P(taskProxy),
- T_USER_DATA, P(taskLoginClick),
+ T_CLICK, P(btnLoginClick),
T_BUTTON, T_DONE,
+ T_TIMER, O(_timProgress),
+ T_EVENT, P(timLoginProgress),
+ T_VALUE, 0,
+ T_ENABLED, 0,
+ T_TIMER, T_DONE,
T_WINDOW, T_DONE,
T_END
};
tagListRun(uiLogin);
+ _channel = netChannelGet(packetHandler);
}
-static void taskLoginClick(void *data) {
- char *packetData = NULL;
- int8_t success = 0;
- uint16_t length = 0;
- int16_t timeout = 10;
- PacketEncodeDataT encoded = { 0 };
- PacketDecodeDataT *decoded = NULL;
+static void packetHandler(PacketDecodeDataT *packet) {
+ char *packetData;
+ int8_t success;
- (void)data;
+ switch (packet->packetType) {
+ case PACKET_TYPE_LOGIN_RESULT:
+ packetContentUnpack(packet->data, "is", &success, &packetData);
+ logWrite("Login: %d %s\n", success, packetData);
+ if (success) {
+ netChannelRelease(_channel);
+ guiDelete(D(_winLogin));
+ menuShow();
+ } else {
+ msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
+ }
+ DEL(packetData);
+ timerStop(_timProgress);
+ break;
+ default:
+ timerStop(_timProgress);
+ msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "Unexpected packet received.", "Okay", btnMsgBoxContinue);
+ break;
+ }
+
+ packetDecodeDataDestroy(&packet);
+}
+
+
+static void setButtons(uint8_t enabled) {
// ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
- setButtons(0);
-
- packetData = packetContentPack(&length, "ss", textboxValueGet(_txtUser), textboxValueGet(_txtPass));
-
- // Send login request.
- encoded.packetType = PACKET_TYPE_LOGIN;
- encoded.control = PACKET_CONTROL_DAT;
- encoded.channel = 0;
- encoded.encrypt = 1;
- packetEncode(__packetThreadData, &encoded, packetData, length);
- packetSend(__packetThreadData, &encoded);
-
- DEL(packetData);
-
- // Wait for response.
- do {
- decoded = netGetPacket(0);
- if (decoded) {
- switch (decoded->packetType) {
- case PACKET_TYPE_LOGIN_RESULT:
- packetContentUnpack(decoded->data, "is", &success, &packetData);
- logWrite("Login: %d %s\n", success, packetData);
- if (success) {
- guiDelete(D(_winLogin));
- taskCreate(taskMenu, NULL);
- } else {
- msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
- }
- DEL(packetData);
- timeout = 0;
- break;
-
- default:
- msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "Unexpected packet received.", "Okay", btnMsgBoxContinue);
- timeout = 0;
- break;
- }
- packetDecodeDataDestroy(&decoded);
- }
- taskYield();
- if (__timerQuarterSecondTick) timeout--;
- } while (!guiHasStopped() && timeout > 0);
+ widgetEnableSet(W(_btnCancel), enabled);
+ widgetEnableSet(W(_btnSignUp), enabled);
+ widgetEnableSet(W(_btnLogin), enabled);
}
+
+
+static void timLoginProgress(WidgetT *widget) {
+ char *packetData;
+ uint16_t length;
+ PacketEncodeDataT encoded;
+ TimerT *t = (TimerT *)widget;
+
+ switch (_state) {
+ case S_START_LOGIN:
+ setButtons(0);
+ packetData = packetContentPack(&length, "ss", textboxValueGet(_txtUser), textboxValueGet(_txtPass));
+ // Send login request.
+ encoded.packetType = PACKET_TYPE_LOGIN;
+ encoded.control = PACKET_CONTROL_DAT;
+ encoded.channel = _channel;
+ encoded.encrypt = 1;
+ packetEncode(__packetThreadData, &encoded, packetData, length);
+ packetSend(__packetThreadData, &encoded);
+ DEL(packetData);
+ // Wait for response.
+ timerQuarterSecondsSet(t, 10 * 4);
+ _state = S_WAIT_LOGIN;
+ break;
+
+ case S_WAIT_LOGIN:
+ timerStop(t);
+ msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "No response received.", "Okay", btnMsgBoxContinue);
+ break;
+ }
+}
+
diff --git a/client/src/login.h b/client/src/login.h
index c1dfa23..e1461fb 100644
--- a/client/src/login.h
+++ b/client/src/login.h
@@ -25,7 +25,7 @@
#include "os.h"
-void taskLogin(void *data);
+void loginShow(void);
#endif // LOGIN_H
diff --git a/client/src/main.c b/client/src/main.c
index e34b682..5792504 100644
--- a/client/src/main.c
+++ b/client/src/main.c
@@ -40,71 +40,125 @@
#include "surface.h"
#include "mouse.h"
#include "keyboard.h"
-#include "task.h"
#include "image.h"
#include "font.h"
-#include "timer.h"
#include "gui.h"
#include "config.h"
#include "runtime.h"
#include "comport.h"
#include "network.h"
-#include "firstrun.h"
+#include "timer.h"
+#include "embedded/embedded.h"
#include "welcome.h"
-#include "signup.h"
+#include "settings.h"
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
RuntimeDataT __runtimeData; // Exported in runtime.h
+static MouseT *_mouse = NULL;
+static ImageT *_pointer = NULL;
+static ColorT _alpha = 0;
-static void taskGuiEventLoop(void *data);
+#ifndef __linux__
+char *_logName = NULL;
+#endif
-static void taskGuiEventLoop(void *data) {
- MouseT *mouse = NULL;
- ImageT *pointer = NULL;
- ColorT alpha = { 0 };
+static void checkSettings(void);
+static void eventLoop(void);
+static uint8_t hasValidSettings(void);
+static void shutdown(void);
+static uint8_t startup(int argc, char *argv[]);
- (void)data;
- pointer = imageLoad("data/mouse.png");
- alpha = imagePixelGet(pointer, 5, 0);
+static void checkSettings(void) {
+ // Do we have a valid COM port?
+ if (!hasValidSettings()) {
+ logWrite("No compatible modem found. Cannot continue.\n");
+ guiStop();
+ return;
+ }
+ welcomeShow();
+ eventLoop();
+}
+
+
+static void eventLoop(void) {
+ // Main Event Loop.
do {
- timerUpdate();
- mouse = mouseRead();
+ netProcess();
+ guiTimerProcess(rawclock());
+ _mouse = mouseRead();
if (keyHit()) {
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());
if (keyASCIIGet() == 27) guiStop();
}
- guiMouseProcess(mouse);
+ guiMouseProcess(_mouse);
guiComposite();
- imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
+ imageRenderWithAlpha(_pointer, _mouse->x, _mouse->y, _alpha);
vbeVBlankWait();
vbePresent();
- taskYield();
} while (!guiHasStopped());
- imageUnload(&pointer);
+ shutdown();
}
+static uint8_t hasValidSettings(void) {
+ return (__configData.serialCom > 0 && __configData.serialCom < 5);
+}
-int main(int argc, char *argv[]) {
+
+static void shutdown(void) {
#ifndef __linux__
// On DOS, display the contets of the log now that we're back in text mode.
- char *logName = NULL;
FILE *in = NULL;
#endif
+ imageUnload(&_pointer);
+
+ netShutdown();
+ guiShutdown();
+ mouseShutdown();
+ surfaceShutdown();
+ vbeShutdown();
+ configShutdown();
+ osShutdown();
+ logClose();
+ memoryShutdown();
+
+#ifndef __linux__
+ //***TODO*** Why the frack does this not work?!
+ textmode(C80);
+ // On DOS, display the contets of the log now that we're back in text mode.
+ in = fopen(_logName, "r");
+ if (in) {
+ while (!feof(in)) {
+ putc(fgetc(in), stdout);
+ }
+ fclose(in);
+ free(in);
+ }
+ free(_logName);
+ _Exit(0);
+#endif
+}
+
+
+static uint8_t startup(int argc, char *argv[]) {
memoryStartup(argv[0]);
logOpenByHandle(memoryLogHandleGet());
osStartup();
configStartup(argv[0]);
+#ifndef __linux__
+ _logName = utilAppNameWithNewExtensionGet(argv[0], "log");
+#endif
+
// 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
logWrite("%s", "Kangaroo Punch MultiPlayer DOS Game Client Mark II\n");
@@ -116,16 +170,10 @@ int main(int argc, char *argv[]) {
configShutdown();
logClose();
memoryShutdown();
- return 0;
+ return 1;
}
}
- timerStartup();
- taskStartup();
-
- // Perform "first run" setup tasks.
- firstRunCheckSetup();
-
// Do we have the video mode they asked for?
if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) {
configShutdown();
@@ -137,42 +185,29 @@ int main(int argc, char *argv[]) {
surfaceStartup();
mouseStartup();
guiStartup();
- // Do not call netStartup() here. It will be started when needed.
+ netStartup();
-// taskCreate(taskSignUp, NULL);
- taskCreate(taskWelcome, NULL);
- taskCreate(taskGuiEventLoop, NULL);
-
- taskRun();
-
- netShutdown();
- guiShutdown();
- mouseShutdown();
- surfaceShutdown();
- vbeShutdown();
- taskShutdown();
- timerShutdown();
- configShutdown();
- osShutdown();
- logClose();
- memoryShutdown();
-
-#ifndef __linux__
- //***TODO*** Why the frack does this not work?!
- textmode(C80);
- // On DOS, display the contets of the log now that we're back in text mode.
- logName = utilAppNameWithNewExtensionGet(argv[0], "log");
- in = fopen(logName, "r");
- if (in) {
- while (!feof(in)) {
- putc(fgetc(in), stdout);
- }
- fclose(in);
- free(in);
- }
- free(logName);
- _Exit(0);
-#endif
+ _pointer = imageFromRAMLoad(mouse_png, mouse_png_len);
+ _alpha = imagePixelGet(_pointer, 5, 0);
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[]) {
+
+ if (startup(argc, argv)) return 1;
+
+ // Perform "first run" setup tasks or start the client?
+ if (hasValidSettings()) {
+ // We have what we need, start the client.
+ welcomeShow();
+ } else {
+ // Run the setup.
+ settingsShow(checkSettings);
+ }
+
+ eventLoop();
return 0;
}
diff --git a/client/src/menu.c b/client/src/menu.c
index f504656..597ea66 100644
--- a/client/src/menu.c
+++ b/client/src/menu.c
@@ -21,7 +21,6 @@
#include "menu.h"
-void taskMenu(void *data) {
- (void)data;
+void menuShow(void) {
}
diff --git a/client/src/menu.h b/client/src/menu.h
index 738a4ce..eaeb502 100644
--- a/client/src/menu.h
+++ b/client/src/menu.h
@@ -25,7 +25,7 @@
#include "os.h"
-void taskMenu(void *data);
+void menuShow(void);
#endif // MENU_H
diff --git a/client/src/network.c b/client/src/network.c
index db6d4fd..0c72974 100644
--- a/client/src/network.c
+++ b/client/src/network.c
@@ -19,7 +19,6 @@
#include "gui.h"
-#include "task.h"
#include "comport.h"
#include "config.h"
#include "timer.h"
@@ -28,174 +27,30 @@
#include "network.h"
-typedef struct NetworkPacketS {
- uint8_t key;
- PacketDecodeDataT **value;
-} NetworkPacketT;
+typedef struct NetworkChannelsS {
+ uint8_t key;
+ netPacketHandler value;
+} NetworkChannelsT;
-static NetworkPacketT *_packets = NULL;
-static uint8_t _netRunning = 0;
-static uint8_t _netStarted = 0;
+static netPacketHandler *_systemHandlers = NULL;
+static NetworkChannelsT *_channels = NULL;
+static uint8_t _netRunning = 0;
+static uint8_t _netStarted = 0;
-int8_t netConnectStep1(void) {
- int32_t r = 0;
- char buffer[1024] = { 0 };
-
- // Open COM port.
- r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
- if (r != SER_SUCCESS) return NETWORK_CONNECT_OPEN_FAILED;
- // Send a CR to clear anything in the modem.
- 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
- 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, "OK");
- if (r <= 0) {
- comClose(__configData.serialCom - 1);
- return NETWORK_CONNECT_BAD_MODEM;
- }
- // Flush COM port.
- timerQuarterSecondsWait(4);
- comReceiveBufferFlush(__configData.serialCom - 1);
-
- return NETWORK_CONNECT_SUCCESS;
-}
-
-
-int8_t netConnectStep2(void) {
- int32_t r = 0;
- char buffer[1024] = { 0 };
- PacketDecodeDataT *decoded = NULL;
- PacketEncodeDataT encoded = { 0 };
- uint8_t waiting = 1;
- int16_t timeout = 0;
-
- 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);
- return NETWORK_CONNECT_NO_CARRIER;
- }
-
- // Start packet handler and negotiate encryption.
- netStartup();
- packetEncryptionSetup(__packetThreadData);
- timeout = 5;
- do {
- if (packetEncryptionReady()) break;
- taskYield();
- if (__timerSecondTick) timeout--;
- } while (!guiHasStopped() && timeout >= 0);
- if (timeout < 0) {
- comClose(__configData.serialCom - 1);
- return NETWORK_CONNECT_BAD_ENCRYPTION;
- }
-
- // ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
-
- // Wait for version and table packets to arrive.
- timeout = 10;
- do {
- decoded = netGetPacket(0);
- if (decoded) {
- switch (decoded->packetType) {
- case PACKET_TYPE_NUMBER:
- // Store in number table.
- shput(__runtimeData.integers, &decoded->data[4], (int32_t)decoded->data[0]);
- // Reset timeout.
- timeout = 10;
- break;
-
- case PACKET_TYPE_PROCEED:
- waiting = 0;
- break;
-
- case PACKET_TYPE_STRING:
- // Store in string table.
- //logWrite("Storing [%s]=[%s]\n", decoded->data, &decoded->data[strlen(decoded->data) + 1]);
- shput(__runtimeData.strings, decoded->data, strdup(&decoded->data[strlen(decoded->data) + 1]));
- // Reset timeout.
- timeout = 10;
- break;
-
- case PACKET_TYPE_VERSION:
- packetContentUnpack(decoded->data, "i", &__runtimeData.protocolVersion);
- // Do we need to update?
- if (PACKET_PROTOCOL_VERSION == __runtimeData.protocolVersion) {
- // Nope, we're good.
- encoded.packetType = PACKET_TYPE_VERSION_OKAY;
- } else {
- // Version mismatch - upgrade time!
- encoded.packetType = PACKET_TYPE_VERSION_BAD;
- //***TODO***
- }
- encoded.control = PACKET_CONTROL_DAT;
- encoded.channel = 0;
- encoded.encrypt = 0;
- packetEncode(__packetThreadData, &encoded, NULL, 0);
- // Send GOOD or BAD.
- packetSend(__packetThreadData, &encoded);
- // Reset timeout.
- timeout = 10;
- break;
-
- default:
- logWrite("Unexpected packet received: %d\n", decoded->packetType);
- break;
- }
- packetDecodeDataDestroy(&decoded);
- }
- taskYield();
- if (__timerSecondTick) timeout--;
- } while (!guiHasStopped() && timeout >= 0 && waiting);
- if (timeout < 0) {
- comClose(__configData.serialCom - 1);
- return NETWORK_CONNECT_BAD_SETTINGS;
- }
-
- return NETWORK_CONNECT_SUCCESS;
-}
-
-
-void netDisconnect(void) {
- PacketEncodeDataT encoded = { 0 };
- int16_t timeout = 2;
-
- // Tell server we're disconnecting.
- encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
- encoded.control = PACKET_CONTROL_DAT;
- encoded.channel = 0;
- encoded.encrypt = 0;
- packetEncode(__packetThreadData, &encoded, NULL, 0);
- packetSend(__packetThreadData, &encoded);
-
- // Snooze a bit for the packet to send.
- while (timeout > 0) {
- taskYield();
- if (__timerQuarterSecondTick) timeout--;
- }
-
- // Shut down packet processing & COM port.
- netShutdown();
- comClose(__configData.serialCom - 1);
-}
-
-
-uint8_t netGetChannelFree(void) {
- uint8_t channel = 0; // We reserve 0 for system stuff. Returning 0 means no channel was found.
+uint8_t netChannelGet(netPacketHandler handler) {
+ uint8_t channel = 0;
uint16_t x = 0;
- for (x=1; x<255; x++) {
- if (hmgeti(_packets, x) < 0) {
+ // We reserve 0 for system stuff.
+ // Returning 0 means no channel was found.
+
+ // Find first unused channel.
+ for (x=1; x<255; x++) {
+ if (hmgeti(_channels, x) < 0) {
channel = x;
+ hmput(_channels, x, handler);
break;
}
}
@@ -204,23 +59,121 @@ uint8_t netGetChannelFree(void) {
}
-PacketDecodeDataT *netGetPacket(uint8_t channel) {
- int32_t r = 0;
- PacketDecodeDataT *packet = NULL;
+void netChannelRelease(uint8_t channel) {
+ hmdel(_channels, channel);
+}
- r = hmgeti(_packets, channel);
- if (r < 0) return NULL;
- if (arrlen(_packets[r].value) == 0) return NULL;
- packet = _packets[r].value[0];
- arrdel(_packets[r].value, 0);
- return packet;
+void netChannelSystemGet(netPacketHandler handler) {
+ arrput(_systemHandlers, handler);
+}
+
+
+void netChannelSystemRelease(netPacketHandler handler) {
+ uint16_t x;
+
+ for (x=0; xchannel = decoded.channel;
+ packet->length = decoded.length;
+ packet->packetType = decoded.packetType;
+ packet->data = (char *)malloc(decoded.length);
+ memcpy(packet->data, decoded.data, decoded.length);
+ // Send it to the subscriber.
+ _systemHandlers[r](packet);
+ }
+ } else {
+ // Does someone want this channel?
+ r = hmgeti(_channels, decoded.channel);
+ if (r >= 0) {
+ // Copy the packet out.
+ NEW(PacketDecodeDataT, packet);
+ packet->channel = decoded.channel;
+ packet->length = decoded.length;
+ packet->packetType = decoded.packetType;
+ packet->data = (char *)malloc(decoded.length);
+ memcpy(packet->data, decoded.data, decoded.length);
+ // Send it to the subscriber.
+ _channels[r].value(packet);
+ }
+ }
+ // Destroy our copy.
+ packetDecodeDataStaticDestroy(&decoded);
+ break;
+ }
+ }
+
+ } // _netRunning
}
void netShutdown(void) {
FILE *cache = NULL;
+ netPacketHandlerStop();
+
if (_netStarted) {
_netStarted = 0;
@@ -230,7 +183,7 @@ void netShutdown(void) {
if (__runtimeData.integers) {
while (shlen(__runtimeData.integers) > 0) {
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
- fprintf(cache, "%s=%d\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
+ fprintf(cache, "%s=%ld\n", __runtimeData.integers[0].key, (long)__runtimeData.integers[0].value);
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
}
shfree(__runtimeData.integers);
@@ -255,8 +208,6 @@ void netShutdown(void) {
packetThreadDataDestroy(&__packetThreadData);
}
-
- _netRunning = 0;
}
@@ -264,131 +215,59 @@ void netStartup(void) {
FILE *cache = NULL;
char *line = NULL;
char *p = NULL;
+ char *temp = NULL;
- _netStarted = 1;
+ if (!_netStarted) {
+ _netStarted = 1;
- __packetThreadData = packetThreadDataCreate(NULL);
- packetSenderRegister(comPacketSender);
+ __packetThreadData = packetThreadDataCreate(NULL);
+ packetSenderRegister(comPacketSender);
- __runtimeData.integers = NULL;
- __runtimeData.strings = NULL;
- __runtimeData.protocolVersion = 0;
+ __runtimeData.integers = NULL;
+ __runtimeData.strings = NULL;
+ __runtimeData.protocolVersion = 0;
- sh_new_strdup(__runtimeData.integers);
- sh_new_strdup(__runtimeData.strings);
+ sh_new_strdup(__runtimeData.integers);
+ sh_new_strdup(__runtimeData.strings);
- // ***TODO*** Default initial tables
+ // ***TODO*** Default initial tables
- line = (char *)malloc(4096);
- if (line) {
- // Load string cache.
- cache = fopen("cache/string.dat", "rt");
- if (cache) {
- while (fscanf(cache, "%s\n", line) != EOF) {
- p = strstr(line, "=");
- if (p) {
- *p = 0;
- p++;
- shput(__runtimeData.strings, line, strdup(p));
+ line = (char *)malloc(4096);
+ if (line) {
+ // Load string cache.
+ cache = fopen("cache/string.dat", "rt");
+ if (cache) {
+ while (fscanf(cache, "%s\n", line) != EOF) {
+ p = strstr(line, "=");
+ if (p) {
+ *p = 0;
+ p++;
+ // Do we have this string already?
+ temp = shget(__runtimeData.strings, line);
+ if (temp) {
+ DEL(temp);
+ shdel(__runtimeData.strings, line);
+ }
+ shput(__runtimeData.strings, line, strdup(p));
+ }
}
+ fclose(cache);
}
- fclose(cache);
- }
- // Load integer cache.
- cache = fopen("cache/integer.dat", "rt");
- if (cache) {
- while (fscanf(cache, "%s\n", line) != EOF) {
- p = strstr(line, "=");
- if (p) {
- *p = 0;
- p++;
- shput(__runtimeData.integers, line, atol(p));
+ // Load integer cache.
+ cache = fopen("cache/integer.dat", "rt");
+ if (cache) {
+ while (fscanf(cache, "%s\n", line) != EOF) {
+ p = strstr(line, "=");
+ if (p) {
+ *p = 0;
+ p++;
+ shput(__runtimeData.integers, line, atol(p));
+ }
}
+ fclose(cache);
}
- fclose(cache);
+ free(line);
+ line = NULL;
}
- free(line);
- line = NULL;
}
-
- taskCreate(taskNetwork, NULL);
-}
-
-
-void taskNetwork(void *data) {
- int32_t r = 0;
- char buffer[1024] = { 0 };
- PacketDecodeDataT *packet = NULL;
- PacketDecodeDataT decoded = { 0 };
- PacketEncodeDataT encoded = { 0 };
-
- (void)data;
-
- _netRunning = 1;
-
- do {
-
- // ***TODO*** Detect disconnection. Maybe have callbacks registered that can notify tasks?
-
- // Read pending bytes.
- r = comRead(__configData.serialCom - 1, buffer, 1024);
- // New data or not, process anything in the queue.
- if (packetDecode(__packetThreadData, &decoded, buffer, r)) {
-
- // Is this something we care about?
- switch (decoded.packetType) {
- case PACKET_TYPE_PING:
- // Reply with PONG
- encoded.control = PACKET_CONTROL_DAT;
- encoded.packetType = PACKET_TYPE_PONG;
- encoded.channel = 0;
- encoded.encrypt = 0;
- packetEncode(__packetThreadData, &encoded, NULL, 0);
- packetSend(__packetThreadData, &encoded);
- packetDecodeDataStaticDestroy(&decoded);
- continue;
- break;
-
- default:
- // Silences a warning.
- break;
- }
-
- // Copy the packet out.
- NEW(PacketDecodeDataT, packet);
- packet->channel = decoded.channel;
- packet->length = decoded.length;
- packet->packetType = decoded.packetType;
- packet->data = (char *)malloc(decoded.length);
- memcpy(packet->data, decoded.data, decoded.length);
-
- // Is there a list of packets for this channel already?
- r = hmgeti(_packets, packet->channel);
- if (r < 0) {
- // No. Create dynamic array for this channel.
- hmput(_packets, packet->channel, NULL);
- r = hmgeti(_packets, packet->channel);
- }
- // Add new packet to existing list.
- arrput(_packets[r].value, packet);
-
- packetDecodeDataStaticDestroy(&decoded);
- }
-
- // Yield to UI.
- taskYield();
-
- } while (!guiHasStopped() && _netRunning);
-
- // Free any unclaimed packets.
- while (hmlenu(_packets) > 0) {
- // Free any packets for this channel.
- while (arrlenu(_packets[0].value) > 0) {
- packetDecodeDataDestroy(&_packets[0].value[0]);
- arrdel(_packets[0].value, 0);
- }
- arrfree(_packets[0].value);
- hmdel(_packets, _packets[0].key);
- }
- hmfree(_packets);
}
diff --git a/client/src/network.h b/client/src/network.h
index fccc4c5..e12e0fd 100644
--- a/client/src/network.h
+++ b/client/src/network.h
@@ -25,23 +25,18 @@
#include "os.h"
-#define NETWORK_CONNECT_SUCCESS 0
-#define NETWORK_CONNECT_OPEN_FAILED 1
-#define NETWORK_CONNECT_BAD_MODEM 2
-#define NETWORK_CONNECT_NO_CARRIER 3
-#define NETWORK_CONNECT_BAD_ENCRYPTION 4
-#define NETWORK_CONNECT_BAD_SETTINGS 5
+typedef void (*netPacketHandler)(PacketDecodeDataT *packet);
-int8_t netConnectStep1(void);
-int8_t netConnectStep2(void);
-void netDisconnect(void);
-uint8_t netGetChannelFree(void);
-PacketDecodeDataT *netGetPacket(uint8_t channel);
-void netShutdown(void);
-void netStartup(void);
-
-void taskNetwork(void *data);
+uint8_t netChannelGet(netPacketHandler handler);
+void netChannelRelease(uint8_t channel);
+void netChannelSystemGet(netPacketHandler handler);
+void netChannelSystemRelease(netPacketHandler handler);
+void netPacketHandlerStart(void);
+void netPacketHandlerStop(void);
+void netProcess(void);
+void netShutdown(void);
+void netStartup(void);
#endif // NETWORK_H
diff --git a/client/src/settings.c b/client/src/settings.c
index d9ced81..739bea5 100644
--- a/client/src/settings.c
+++ b/client/src/settings.c
@@ -22,9 +22,7 @@
#include "welcome.h"
#include "taglist.h"
-#include "task.h"
#include "comport.h"
-#include "timer.h"
#include "config.h"
#include "window.h"
@@ -34,6 +32,7 @@
#include "textbox.h"
#include "updown.h"
#include "label.h"
+#include "timer.h"
#define GROUP_COM 1
@@ -46,6 +45,14 @@
#define TITLE_LEN 80
+typedef enum SettingsStateE {
+ S_START_SCAN = 0,
+ S_OPEN_COM,
+ S_WAIT_FOR_INIT,
+ S_SCAN_COMPLETE
+} SettingsStateT;
+
+
typedef struct PortS {
uint8_t status;
char title[TITLE_LEN];
@@ -55,19 +62,23 @@ typedef struct PortS {
} PortT;
-static WindowT *_winDetecting;
-static LabelT *_lblOneMoment;
-static WindowT *_winSettings;
-static FrameT *_frmComPorts;
-static FrameT *_frmServer;
-static ButtonT *_btnOkay;
-static TextboxT *_txtServer;
-static UpdownT *_updPort;
-static PortT _port[4];
-static widgetCallback _done;
+static WindowT *_winDetecting = NULL;
+static LabelT *_lblOneMoment = NULL;
+static WindowT *_winSettings = NULL;
+static FrameT *_frmComPorts = NULL;
+static FrameT *_frmServer = NULL;
+static ButtonT *_btnOkay = NULL;
+static TextboxT *_txtServer = NULL;
+static TimerT *_timProgress = NULL;
+static UpdownT *_updPort = NULL;
+static PortT _port[4] = { 0 };
+static widgetCallback _done = NULL;
+static SettingsStateT _state = S_START_SCAN;
static void btnOkayClick(WidgetT *widget);
+static void settingsComShow(void);
+static void timSettingsProgress(WidgetT *widget);
static void btnOkayClick(WidgetT *widget) {
@@ -95,61 +106,9 @@ static void btnOkayClick(WidgetT *widget) {
}
-int8_t settingsScanComPorts(void) {
- char buffer[1024] = { 0 };
- uint8_t selected = 1;
- int32_t rc = 0;
- uint32_t len = 0;
- int8_t lastFound = -1;
+void settingsShow(void *callback) {
- // Scan the COM ports for a compatable modem.
- for (int x=0; x<4; x++) {
- rc = comOpen(x, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
- if (rc == SER_SUCCESS) {
- snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
- comWrite(x, buffer, strlen(buffer));
- timerQuarterSecondsWait(4);
- len = comRead(x, buffer, 1023);
- buffer[len] = 0;
- if (strstr(buffer, "OK")) {
- snprintf(_port[x].title, TITLE_LEN - 1, "COM%d - SoftModem Found!", x + 1);
- _port[x].status = PORT_GOOD_MODEM;
- _port[x].selected = selected;
- _port[x].enabled = 1;
- selected = 0;
- lastFound = x;
- } else {
- if (strstr(buffer, "ERROR")) {
- snprintf(_port[x].title, TITLE_LEN - 1, "COM%d - Incompatable Modem", x + 1);
- _port[x].status = PORT_BAD_MODEM;
- _port[x].selected = 0;
- _port[x].enabled = 0;
- } else {
- snprintf(_port[x].title, TITLE_LEN - 1, "COM%d - No Modem", x + 1);
- _port[x].status = PORT_NO_MODEM;
- _port[x].selected = 0;
- _port[x].enabled = 0;
- }
- }
- comClose(x);
- } else {
- snprintf(_port[x].title, TITLE_LEN - 1, "COM%d - Not Present", x + 1);
- _port[x].status = PORT_NONE;
- _port[x].selected = 0;
- _port[x].enabled = 0;
- }
- }
-
- return lastFound;
-}
-
-
-void taskSettings(void *data) {
-
- int32_t rc;
- uint32_t len;
-
- _done = (widgetCallback)data;
+ _done = (widgetCallback)callback;
TagItemT uiDetecting[] = {
T_START,
@@ -160,14 +119,27 @@ void taskSettings(void *data) {
T_X, 25, T_Y, 25,
T_TITLE, P("One Moment Please!"),
T_LABEL, T_DONE,
+ T_TIMER, O(_timProgress),
+ T_EVENT, P(timSettingsProgress),
+ T_VALUE, 0,
+ T_TIMER, T_DONE,
T_WINDOW, T_DONE,
T_END
};
- tagListRun(uiDetecting);
- taskYield(); // Cause dialog to paint.
+ // We can use a module-global variable instead of widget user data
+ // because there will never be more than one settings dialog on
+ // the screen at a time.
+ _state = S_START_SCAN;
- settingsScanComPorts();
+ tagListRun(uiDetecting);
+}
+
+
+static void settingsComShow(void) {
+
+ int32_t y;
+ uint32_t len;
guiDelete(D(_winDetecting));
@@ -222,12 +194,88 @@ void taskSettings(void *data) {
}
// Add COM discovery to GUI.
- rc = 0;
+ y = 0;
for (len=0; len<4; len++) {
- _port[len].rdoCOM = radioNew(5, rc, _port[len].title, GROUP_COM);
+ _port[len].rdoCOM = radioNew(5, y, _port[len].title, GROUP_COM);
if (_port[len].selected) radioSelectedSet(_port[len].rdoCOM);
widgetEnableSet(W(_port[len].rdoCOM), _port[len].enabled);
guiAttach(W(_frmComPorts), W(_port[len].rdoCOM));
- rc += 20;
+ y += 20;
+ }
+}
+
+
+static void timSettingsProgress(WidgetT *widget) {
+ char buffer[1024];
+ int32_t rc;
+ uint32_t len;
+
+ static uint8_t selected;
+ static int32_t com;
+
+ switch (_state) {
+ case S_START_SCAN:
+ com = 0;
+ selected = 1;
+ _state = S_OPEN_COM;
+ break;
+
+ case S_OPEN_COM:
+ rc = comOpen(com, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
+ if (rc == SER_SUCCESS) {
+ snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
+ comWrite(com, buffer, strlen(buffer));
+ timerQuarterSecondsSet((TimerT *)widget, 4);
+ _state = S_WAIT_FOR_INIT;
+ } else {
+ snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Not Present", com + 1);
+ _port[com].status = PORT_NONE;
+ _port[com].selected = 0;
+ _port[com].enabled = 0;
+ com++;
+ if (com < 4) {
+ _state = S_OPEN_COM;
+ } else {
+ _state = S_SCAN_COMPLETE;
+ }
+ }
+ break;
+
+ case S_WAIT_FOR_INIT:
+ len = comRead(com, buffer, 1023);
+ buffer[len] = 0;
+ if (strstr(buffer, "OK")) {
+ snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Modem Found!", com + 1);
+ _port[com].status = PORT_GOOD_MODEM;
+ _port[com].selected = selected;
+ _port[com].enabled = 1;
+ selected = 0;
+ } else {
+ if (strstr(buffer, "ERROR")) {
+ snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Incompatable Modem", com + 1);
+ _port[com].status = PORT_BAD_MODEM;
+ _port[com].selected = 0;
+ _port[com].enabled = 0;
+ } else {
+ snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - No Modem", com + 1);
+ _port[com].status = PORT_NO_MODEM;
+ _port[com].selected = 0;
+ _port[com].enabled = 0;
+ }
+ }
+ comClose(com);
+ com++;
+ if (com < 4) {
+ _state = S_OPEN_COM;
+ } else {
+ _state = S_SCAN_COMPLETE;
+ }
+ timerQuarterSecondsSet((TimerT *)widget, 0);
+ break;
+
+ case S_SCAN_COMPLETE:
+ timerStop(_timProgress);
+ settingsComShow();
+ break;
}
}
diff --git a/client/src/settings.h b/client/src/settings.h
index a63c3fe..a89b2d5 100644
--- a/client/src/settings.h
+++ b/client/src/settings.h
@@ -25,8 +25,7 @@
#include "os.h"
-int8_t settingsScanComPorts(void);
-void taskSettings(void *data);
+void settingsShow(void *callback);
#endif // SETTINGS_H
diff --git a/client/src/signup.c b/client/src/signup.c
index 4addc96..7e7e522 100644
--- a/client/src/signup.c
+++ b/client/src/signup.c
@@ -22,34 +22,44 @@
#include "button.h"
#include "label.h"
#include "msgbox.h"
+#include "timer.h"
#include "network.h"
#include "runtime.h"
#include "taglist.h"
-#include "timer.h"
-#include "task.h"
#include "signup.h"
#include "login.h"
-static WindowT *_winSignUp = NULL;
-static LabelT *_lblRequired = NULL;
-static TextboxT *_txtEmail = NULL;
-static TextboxT *_txtFirst = NULL;
-static TextboxT *_txtLast = NULL;
-static TextboxT *_txtUser = NULL;
-static TextboxT *_txtPass1 = NULL;
-static TextboxT *_txtPass2 = NULL;
-static ButtonT *_btnCancel = NULL;
-static ButtonT *_btnSignUp = NULL;
+typedef enum SignUpStateE {
+ S_START_SIGNUP = 0,
+ S_SIGNUP_WAIT
+} SignUpStateT;
+
+
+static WindowT *_winSignUp = NULL;
+static LabelT *_lblRequired = NULL;
+static TextboxT *_txtEmail = NULL;
+static TextboxT *_txtFirst = NULL;
+static TextboxT *_txtLast = NULL;
+static TextboxT *_txtUser = NULL;
+static TextboxT *_txtPass1 = NULL;
+static TextboxT *_txtPass2 = NULL;
+static ButtonT *_btnCancel = NULL;
+static ButtonT *_btnSignUp = NULL;
+static TimerT *_timProgress = NULL;
+static SignUpStateT _state = S_START_SIGNUP;
+static uint8_t _channel = 0;
static void btnCancelClick(WidgetT *widget);
static void btnMsgBoxContinue(MsgBoxButtonT button);
static void btnMsgBoxFinish(MsgBoxButtonT button);
+static void btnSignUpClick(WidgetT *widget);
+static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled);
-static void taskSignUpClick(void *data);
+static void timSignUpProgress(WidgetT *widget);
static uint8_t validateEmail(char *email);
static uint8_t validateEmailLetter(char c);
static uint8_t validateName(char *username);
@@ -61,7 +71,8 @@ static void btnCancelClick(WidgetT *widget) {
(void)widget;
guiDelete(D(_winSignUp));
- taskCreate(taskLogin, NULL);
+ netChannelRelease(_channel);
+ loginShow();
}
@@ -76,7 +87,73 @@ static void btnMsgBoxFinish(MsgBoxButtonT button) {
(void)button;
guiDelete(D(_winSignUp));
- taskCreate(taskLogin, NULL);
+ netChannelRelease(_channel);
+ loginShow();
+}
+
+
+static void btnSignUpClick(WidgetT *widget) {
+ (void)widget;
+
+ setButtons(0);
+
+ // Validate it. ***TODO*** These messages could be a lot better.
+ if (!validateEmail(textboxValueGet(_txtEmail))) {
+ msgBoxOne("Invalid E-Mail", MSGBOX_ICON_ERROR, "Please enter a valid E-mail address.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+ if (!validateName(textboxValueGet(_txtFirst))) {
+ msgBoxOne("Invalid First Name", MSGBOX_ICON_ERROR, "Please enter a valid first name.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+ if (!validateName(textboxValueGet(_txtLast))) {
+ msgBoxOne("Invalid Last Name", MSGBOX_ICON_ERROR, "Please enter a valid last name.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+ if (strcmp(textboxValueGet(_txtPass1), textboxValueGet(_txtPass2)) != 0) {
+ msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Passwords must match.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+ if (!validatePassword(textboxValueGet(_txtPass1))) {
+ msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Please enter a valid password.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+ if (!validateUser(textboxValueGet(_txtUser))) {
+ msgBoxOne("Invalid User Name", MSGBOX_ICON_ERROR, "Please enter a valid user name.", "Okay", btnMsgBoxContinue);
+ return;
+ }
+
+ _state = S_START_SIGNUP;
+ timerQuarterSecondsSet(_timProgress, 0);
+ timerStart(_timProgress);
+}
+
+
+static void packetHandler(PacketDecodeDataT *packet) {
+ uint16_t length;
+ char *packetData;
+
+ // Reset timeout.
+ timerReset(_timProgress);
+
+ switch (packet->packetType) {
+ case PACKET_TYPE_SIGNUP_RESULT:
+ packetContentUnpack(packet->data, "is", &length, &packetData);
+ if (length) {
+ msgBoxOne("Success!", MSGBOX_ICON_INFORMATION, packetData, "Okay", btnMsgBoxFinish);
+ } else {
+ msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
+ }
+ DEL(packetData);
+ timerStop(_timProgress);
+ break;
+
+ default:
+ logWrite("Unexpected packet received: %d\n", packet->packetType);
+ break;
+ }
+
+ packetDecodeDataDestroy(&packet);
}
@@ -86,9 +163,7 @@ static void setButtons(uint8_t enabled) {
}
-void taskSignUp(void *data) {
-
- (void)data;
+void signupShow(void) {
TagItemT uiSignUp[] = {
T_START,
@@ -160,101 +235,56 @@ void taskSignUp(void *data) {
T_BUTTON, O(_btnSignUp),
T_TITLE, P("Sign Up"),
T_X, 291, T_Y, 270,
- T_CLICK, P(taskProxy),
- T_USER_DATA, P(taskSignUpClick),
+ T_CLICK, P(btnSignUpClick),
T_BUTTON, T_DONE,
+ T_TIMER, O(_timProgress),
+ T_EVENT, P(timSignUpProgress),
+ T_VALUE, 0,
+ T_ENABLED, 0,
+ T_TIMER, T_DONE,
T_WINDOW, T_DONE,
T_END
};
tagListRun(uiSignUp);
+ _channel = netChannelGet(packetHandler);
}
-static void taskSignUpClick(void *data) {
- PacketEncodeDataT encoded = { 0 };
- PacketDecodeDataT *decoded = NULL;
- int16_t timeout = 10;
- uint16_t length = 0;
- char *packetData = NULL;
+static void timSignUpProgress(WidgetT *widget) {
+ PacketEncodeDataT encoded;
+ uint16_t length;
+ char *packetData;
+ TimerT *t = (TimerT *)widget;
- (void)data;
+ switch (_state) {
+ case S_START_SIGNUP:
+ packetData = packetContentPack(&length, "sssss",
+ textboxValueGet(_txtEmail),
+ textboxValueGet(_txtFirst),
+ textboxValueGet(_txtLast),
+ textboxValueGet(_txtPass1),
+ textboxValueGet(_txtUser)
+ );
- // ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
+ // Send signup request.
+ encoded.packetType = PACKET_TYPE_SIGNUP;
+ encoded.control = PACKET_CONTROL_DAT;
+ encoded.channel = _channel;
+ encoded.encrypt = 1;
+ packetEncode(__packetThreadData, &encoded, packetData, length);
+ packetSend(__packetThreadData, &encoded);
+ DEL(packetData);
+ // Wait for response.
+ timerQuarterSecondsSet(_timProgress, 10 * 4);
+ break;
- setButtons(0);
-
- // Validate it. ***TODO*** These messages could be a lot better.
- if (!validateEmail(textboxValueGet(_txtEmail))) {
- msgBoxOne("Invalid E-Mail", MSGBOX_ICON_ERROR, "Please enter a valid E-mail address.", "Okay", btnMsgBoxContinue);
- return;
+ case S_SIGNUP_WAIT:
+ timerStop(t);
+ msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "No response received.", "Okay", btnMsgBoxContinue);
+ break;
}
- if (!validateName(textboxValueGet(_txtFirst))) {
- msgBoxOne("Invalid First Name", MSGBOX_ICON_ERROR, "Please enter a valid first name.", "Okay", btnMsgBoxContinue);
- return;
- }
- if (!validateName(textboxValueGet(_txtLast))) {
- msgBoxOne("Invalid Last Name", MSGBOX_ICON_ERROR, "Please enter a valid last name.", "Okay", btnMsgBoxContinue);
- return;
- }
- if (strcmp(textboxValueGet(_txtPass1), textboxValueGet(_txtPass2)) != 0) {
- msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Passwords must match.", "Okay", btnMsgBoxContinue);
- return;
- }
- if (!validatePassword(textboxValueGet(_txtPass1))) {
- msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Please enter a valid password.", "Okay", btnMsgBoxContinue);
- return;
- }
- if (!validateUser(textboxValueGet(_txtUser))) {
- msgBoxOne("Invalid User Name", MSGBOX_ICON_ERROR, "Please enter a valid user name.", "Okay", btnMsgBoxContinue);
- return;
- }
-
- packetData = packetContentPack(&length, "sssss",
- textboxValueGet(_txtEmail),
- textboxValueGet(_txtFirst),
- textboxValueGet(_txtLast),
- textboxValueGet(_txtPass1),
- textboxValueGet(_txtUser)
- );
-
- // Send signup request.
- encoded.packetType = PACKET_TYPE_SIGNUP;
- encoded.control = PACKET_CONTROL_DAT;
- encoded.channel = 0;
- encoded.encrypt = 1;
- packetEncode(__packetThreadData, &encoded, packetData, length);
- packetSend(__packetThreadData, &encoded);
-
- DEL(packetData);
-
- // Wait for response.
- do {
- decoded = netGetPacket(0);
- if (decoded) {
- switch (decoded->packetType) {
- case PACKET_TYPE_SIGNUP_RESULT:
- packetContentUnpack(decoded->data, "is", &length, &packetData);
- if (length) {
- msgBoxOne("Success!", MSGBOX_ICON_INFORMATION, packetData, "Okay", btnMsgBoxFinish);
- } else {
- msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
- }
- DEL(packetData);
- timeout = 0;
- break;
-
- default:
- msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "Unexpected packet received.", "Okay", btnMsgBoxContinue);
- timeout = 0;
- break;
- }
- packetDecodeDataDestroy(&decoded);
- }
- taskYield();
- if (__timerQuarterSecondTick) timeout--;
- } while (!guiHasStopped() && timeout > 0);
}
diff --git a/client/src/signup.h b/client/src/signup.h
index aa29d5d..b7118f9 100644
--- a/client/src/signup.h
+++ b/client/src/signup.h
@@ -25,7 +25,7 @@
#include "os.h"
-void taskSignUp(void *data);
+void signupShow(void);
#endif // SIGNUP_H
diff --git a/client/src/system/comport.c b/client/src/system/comport.c
index 6d76190..1482330 100644
--- a/client/src/system/comport.c
+++ b/client/src/system/comport.c
@@ -17,10 +17,8 @@
*
*/
-
#include "comport.h"
#include "timer.h"
-#include "task.h"
#include "config.h"
@@ -43,44 +41,65 @@ int comReceiveBufferFlush(int com) {
}
-int comWaitWithTimeout(int com, char *buffer, int len, int quarterSeconds, char *expecting) {
- int r;
- int quarterTicks = 0;
- int count = 0;
- int bufferIndex = 0;
- char data[2];
+/*
+TASKBEGIN(comWaitWithTimeout)
+ int32_t r;
+ uint32_t quarterTicks;
+ int32_t count;
+ int32_t bufferIndex;
+ char incoming[2];
+ ComWaitWithTimeoutT *args;
- // Returns number of bytes read into buffer.
- // Value is positive if "expect" was found.
- // Value is negative if not found.
+ taskCode({
+ // Returns number of bytes read into buffer.
+ // Value is positive if "expect" was found.
+ // Value is negative if not found.
- while (quarterTicks <= quarterSeconds) {
- r = comRead(com, data, 1);
- if (r == 1) {
- buffer[bufferIndex++] = data[0];
- buffer[bufferIndex] = 0;
- if (data[0] == expecting[count]) {
- count++;
- if (count == (int)strlen(expecting)) {
- // Found our expect.
+ logWrite("Entering comWaitWithTimeout\n");
+
+ self->args = (ComWaitWithTimeoutT *)data;
+
+ while (self->quarterTicks <= self->args->quarterSeconds) {
+
+ // logWrite("Calling comRead\n");
+ self->r = comRead(self->args->com, self->incoming, 1);
+ // logWrite("Back from comRead with %d\n", self->r);
+
+ if (self->r == 1) {
+ self->args->buffer[self->bufferIndex++] = self->incoming[0];
+ self->args->buffer[self->bufferIndex] = 0;
+ if (self->incoming[0] == self->args->expecting[self->count]) {
+ self->count++;
+ if (self->count == (int)strlen(self->args->expecting)) {
+ // Found our expect.
+ break;
+ }
+ } else {
+ self->count = 0;
+ }
+ if (self->bufferIndex == self->args->len - 1) {
+ // Out of buffer.
break;
}
- } else {
- count = 0;
}
- if (bufferIndex == len - 1) {
- // Out of buffer.
- break;
- }
- } else {
+
+ // logWrite("Yielding from comWaitWithTimeout\n");
taskYield();
- if (__timerQuarterSecondTick) quarterTicks++;
+ // logWrite("Back in comWaitWithTimeout\n");
+
+ if (__timerQuarterSecondTick) {
+ self->quarterTicks++;
+ logWrite("Tick\n");
+ }
}
- }
- if (count == (int)strlen(expecting)) {
- return bufferIndex;
- }
+ logWrite("Exiting comWaitWithTimeout\n");
- return -bufferIndex;
-}
+ if (self->count == (int)strlen(self->args->expecting)) {
+ self->args->result = self->bufferIndex;
+ }
+
+ self->args->result = -self->bufferIndex;
+ });
+TASKEND
+*/
diff --git a/client/src/system/comport.h b/client/src/system/comport.h
index d2b3d00..3441be6 100644
--- a/client/src/system/comport.h
+++ b/client/src/system/comport.h
@@ -26,6 +26,16 @@
#include "packet.h"
+typedef struct ComWaitWithTimeoutS {
+ int32_t result;
+ uint8_t com;
+ char *buffer;
+ int32_t len;
+ uint32_t quarterSeconds;
+ char *expecting;
+} ComWaitWithTimeoutT;
+
+
#ifdef __linux__
#define SER_SUCCESS 0
@@ -35,7 +45,6 @@
#define SER_HANDSHAKING_RTSCTS 2
-
int comClose(int com);
int comOpen(int com, long bps, int dataBits, char parity, int stopBits, int handshaking);
int comRead(int com, char *data, int len);
@@ -55,7 +64,6 @@ int comWrite(int com, const char *data, int len);
void comPacketSender(char *data, uint32_t length, void *userData);
int comReceiveBufferFlush(int com);
-int comWaitWithTimeout(int com, char *buffer, int len, int quarterSeconds, char *expecting);
#endif // COMPORT_H
diff --git a/client/src/system/os.c b/client/src/system/os.c
index a653605..9496230 100644
--- a/client/src/system/os.c
+++ b/client/src/system/os.c
@@ -21,6 +21,16 @@
#include "os.h"
+uint8_t osFileExists(char *filename) {
+ FILE *f = fopen(filename, "rb");
+ if (f) {
+ fclose(f);
+ return 1;
+ }
+ return 0;
+}
+
+
void osShutdown(void) {
#ifdef __linux__
linuxOsShutdown();
diff --git a/client/src/system/os.h b/client/src/system/os.h
index 81cb419..c4908c5 100644
--- a/client/src/system/os.h
+++ b/client/src/system/os.h
@@ -27,6 +27,7 @@
// Common platform includes.
#include
+#include
#include
#include
#include
@@ -37,12 +38,17 @@
#include
+#define SECONDS_IN_DAY 86400
+#define TICKS_PER_SECOND 18.2
+#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
+
+
#ifdef __linux__
#define BITS64
// Linux DOS replacements.
-long biostime(int cmd, long newtime);
+uint32_t rawclock(void);
// Linux support functions.
void linuxOsShutdown(void);
@@ -75,8 +81,8 @@ void linuxOsStartup(void);
// Allocation helpers.
-#define NEW(t,v) (v)=(t*)malloc(sizeof(t))
-#define DEL(v) {free(v); v=NULL;}
+#define NEW(t,v) (v)=(t*)calloc(1, sizeof(t))
+#define DEL(v) { if (v) { free(v); v = NULL; } }
#define SUCCESS 1
#define FAIL 0
@@ -93,8 +99,9 @@ typedef struct PacketThreadDataS PacketThreadDataT;
extern PacketThreadDataT *__packetThreadData; // Declared in main.c
-void osShutdown(void);
-void osStartup(void);
+uint8_t osFileExists(char *filename);
+void osShutdown(void);
+void osStartup(void);
#endif // OS_H
diff --git a/client/src/system/taglist.c b/client/src/system/taglist.c
index f310628..3b026d3 100644
--- a/client/src/system/taglist.c
+++ b/client/src/system/taglist.c
@@ -32,6 +32,7 @@
#include "radio.h"
#include "terminal.h"
#include "textbox.h"
+#include "timer.h"
#include "updown.h"
#include "window.h"
@@ -166,6 +167,7 @@ static void tagListWidgetAttributeHandle(void) {
break;
case T_CLICK:
+ case T_EVENT:
click = (widgetCallback)v;
break;
@@ -331,6 +333,13 @@ static void tagListWidgetAttributeHandle(void) {
textboxPasswordCharacterSet((TextboxT *)widget, mask);
break;
+ case T_TIMER:
+ if (hasValue && click) {
+ widget = W(timerNew(click, (uint32_t)valueInt));
+ if (!enabled) timerStop((TimerT *)widget);
+ }
+ break;
+
case T_UPDOWN:
widget = W(updownNew(pos.x, pos.y, minimum, maximum, step, title));
if (hasValue) updownValueSet((UpdownT *)widget, valueInt);
diff --git a/client/src/system/taglist.h b/client/src/system/taglist.h
index b216ff6..9f2db1f 100644
--- a/client/src/system/taglist.h
+++ b/client/src/system/taglist.h
@@ -54,6 +54,7 @@ enum TagItemsE {
T_RADIOBUTTON,
T_TERMINAL,
T_TEXTBOX,
+ T_TIMER,
T_UPDOWN,
T_WINDOW,
@@ -65,6 +66,7 @@ enum TagItemsE {
T_COLOR_BACKGROUND,
T_COLOR_FOREGROUND,
T_ENABLED,
+ T_EVENT,
T_FILENAME,
T_GROUP,
T_HEIGHT,
diff --git a/client/src/system/task.c b/client/src/system/task.c
deleted file mode 100644
index 5011d2f..0000000
--- a/client/src/system/task.c
+++ /dev/null
@@ -1,121 +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 .
- *
- */
-
-
-#define MINICORO_IMPL
-#define MCO_USE_ASM
-//#define MCO_DEFAULT_STACK_SIZE 114688 // Default is 57344
-#include "thirdparty/minicoro/minicoro.h"
-
-#include "task.h"
-#include "array.h"
-
-
-typedef struct TaskS {
- mco_coro *coroutine;
- void (*function)(void *);
- void *data;
-} TaskT;
-
-
-static TaskT **_taskList = NULL;
-
-
-static void taskHandle(mco_coro* coroutine);
-
-
-uint8_t taskCreate(void (*function)(void *), void *data) {
- mco_desc desc = mco_desc_init(taskHandle, 0);
- mco_result res = 0;
- TaskT *task = (TaskT *)malloc(sizeof(TaskT));
-
- if (task) {
- task->function = function;
- task->data = data;
- desc.user_data = task;
- res = mco_create(&task->coroutine, &desc);
- if (res != MCO_SUCCESS) {
- mco_destroy(task->coroutine);
- free(task);
- return 1; // Failed
- }
- arrput(_taskList, task);
- }
-
- return 1; // Failed
-}
-
-
-static void taskHandle(mco_coro* coroutine) {
- TaskT *task = (TaskT *)mco_get_user_data(coroutine);
- task->function(task->data);
-}
-
-
-void taskProxy(WidgetT *widget) {
- taskFunction task = (taskFunction)guiUserDataGet(widget);
- taskCreate(task, NULL);
-}
-
-
-void taskRun(void) {
- uint16_t taskIndex = 0;
-
- // Run until there are no more tasks.
- while (arrlen(_taskList) > 0) {
-
- // Run each task in order.
- taskIndex = 0;
- while (taskIndex < arrlen(_taskList)) {
-
- // Run task.
- mco_resume(_taskList[taskIndex]->coroutine);
- // Did it finish?
- if (mco_status(_taskList[taskIndex]->coroutine) == MCO_DEAD) {
- // Task ended. Remove it.
- mco_destroy(_taskList[taskIndex]->coroutine);
- free(_taskList[taskIndex]);
- arrdel(_taskList, taskIndex);
- } else {
- // Next task.
- taskIndex++;
- }
-
- } // while each task
-
- } // while tasks exist
-
- arrfree(_taskList);
- _taskList = NULL;
-}
-
-
-void taskShutdown(void) {
- // Nada
-}
-
-
-void taskStartup(void) {
- // Nada
-}
-
-
-void __attribute__ ((noinline)) taskYield(void) {
- mco_yield(mco_running());
-}
diff --git a/client/src/system/timer.c b/client/src/system/timer.c
deleted file mode 100644
index 8711dae..0000000
--- a/client/src/system/timer.c
+++ /dev/null
@@ -1,110 +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 .
- *
- */
-
-
-#include "timer.h"
-#include "task.h"
-#include "gui.h"
-
-
-#define SECONDS_IN_DAY 86400
-#define TICKS_PER_SECOND 18.2
-#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
-
-
-uint8_t __timerQuarterSecondTick = 0;
-uint8_t __timerHalfSecondTick = 0;
-uint8_t __timerSecondTick = 0;
-
-uint8_t __timerQuarterSecondOn = 0;
-uint8_t __timerHalfSecondOn = 0;
-uint8_t __timerSecondOn = 0;
-
-
-static long _timerLast = 0;
-static uint8_t _timerHalfSecond = 2;
-static uint8_t _timerSecond = 2;
-
-
-void timerShutdown(void) {
- // Nothing yet.
-}
-
-
-void timerStartup(void) {
- _timerLast = biostime(0, 0);
-}
-
-
-void timerUpdate(void) {
- long now;
- long delta;
-
- now = biostime(0, 0);
-
- // Reset ticks.
- __timerQuarterSecondTick = 0;
- __timerHalfSecondTick = 0;
- __timerSecondTick = 0;
-
- // Ensure we haven't rolled past midnight between calls.
- if (now >= _timerLast) {
- delta = now - _timerLast;
- } else {
- // Compensate for midnight rollover.
- delta = (now + TICKS_PER_DAY) - _timerLast;
- }
-
- // Everything ticks off the quarter second.
- if (delta > TICKS_PER_SECOND * 0.25) {
- _timerLast = now;
-
- // Quarter Second timer.
- __timerQuarterSecondOn = !__timerQuarterSecondOn;
- __timerQuarterSecondTick = 1;
-
- // Half Second timer.
- if (--_timerHalfSecond == 0) {
- _timerHalfSecond = 2;
- __timerHalfSecondOn = !__timerHalfSecondOn;
- __timerHalfSecondTick = 1;
-
- // Second timer
- if (--_timerSecond == 0) {
- _timerSecond = 2;
- __timerSecondOn = !__timerSecondOn;
- __timerSecondTick = 1;
- } // Second.
-
- } // Half Second.
-
- } // Quarter Second.
-}
-
-
-void timerQuarterSecondsWait(uint8_t quarterSeconds) {
- uint8_t counter = 0;
-
- while (counter <= quarterSeconds && !guiHasStopped()) {
- if (__timerQuarterSecondTick) {
- counter++;
- }
- taskYield();
- }
-}
diff --git a/client/src/welcome.c b/client/src/welcome.c
index 6aa0a98..c2faaf4 100644
--- a/client/src/welcome.c
+++ b/client/src/welcome.c
@@ -23,35 +23,62 @@
#include "login.h"
#include "taglist.h"
-#include "task.h"
#include "config.h"
#include "comport.h"
-#include "timer.h"
#include "network.h"
+#include "runtime.h"
#include "window.h"
#include "picture.h"
#include "button.h"
#include "msgbox.h"
+#include "timer.h"
-static WindowT *_winWelcome = NULL;
-static PictureT *_picLogo = NULL;
-static PictureT *_picInit = NULL;
-static PictureT *_picDialing = NULL;
-static PictureT *_picConnect = NULL;
-static ButtonT *_btnQuit = NULL;
-static ButtonT *_btnSettings = NULL;
-static ButtonT *_btnConnect = NULL;
+typedef enum WelcomeStateE {
+ S_START_CONNECT = 0,
+ S_START_INIT_MODEM,
+ S_INIT_MODEM,
+ S_INIT_RESULT,
+ S_DIAL,
+ S_WAIT_FOR_BANNER,
+ S_WAIT_FOR_ENCRYPTION,
+ S_WAIT_FOR_DATA_TIMEOUT,
+ S_WAIT_FOR_ICON
+} WelcomeStateT;
-static void taskConnectClick(void *data);
+static WindowT *_winWelcome = NULL;
+static PictureT *_picLogo = NULL;
+static PictureT *_picInit = NULL;
+static PictureT *_picDialing = NULL;
+static PictureT *_picConnect = NULL;
+static ButtonT *_btnQuit = NULL;
+static ButtonT *_btnSettings = NULL;
+static ButtonT *_btnConnect = NULL;
+static TimerT *_timProgress = NULL;
+static WelcomeStateT _state = S_START_CONNECT;
+static int16_t _timeoutCounter = 0;
+
+
+static void btnConnectClick(WidgetT *widget);
static void btnMsgBox(MsgBoxButtonT button);
static void btnMsgBoxQuit(MsgBoxButtonT button);
static void btnQuitClick(WidgetT *widget);
static void btnSettingsClick(WidgetT *widget);
+static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled);
static void settingsFinished(WidgetT *widget);
+static void timWelcomeProgress(WidgetT *widget);
+
+
+static void btnConnectClick(WidgetT *widget) {
+ (void)widget;
+
+ _state = S_START_CONNECT;
+ timerQuarterSecondsSet(_timProgress, 0);
+ timerStart(_timProgress);
+}
static void btnMsgBox(MsgBoxButtonT button) {
@@ -79,6 +106,7 @@ static void btnMsgBoxQuit(MsgBoxButtonT button) {
static void btnQuitClick(WidgetT *widget) {
(void)widget;
+
setButtons(0);
msgBoxTwo("Quit?", MSGBOX_ICON_QUESTION, "Exit to DOS?", "Okay", btnMsgBoxQuit, "Cancel", btnMsgBoxQuit);
}
@@ -86,8 +114,69 @@ static void btnQuitClick(WidgetT *widget) {
static void btnSettingsClick(WidgetT *widget) {
(void)widget;
+
setButtons(0);
- taskCreate(taskSettings, settingsFinished);
+ settingsShow(settingsFinished);
+}
+
+
+static void packetHandler(PacketDecodeDataT *packet) {
+ PacketEncodeDataT encoded;
+ char *temp;
+
+ // Reset timeout.
+ timerReset(_timProgress);
+
+ switch (packet->packetType) {
+ case PACKET_TYPE_NUMBER:
+ // Store in number table.
+ shput(__runtimeData.integers, &packet->data[4], (int32_t)packet->data[0]);
+ break;
+
+ case PACKET_TYPE_PROCEED:
+ // Connected! Show icon.
+ widgetVisibleSet(W(_picConnect), 1);
+ // Leave it up about 1.5 seconds.
+ timerQuarterSecondsSet(_timProgress, 6);
+ _state = S_WAIT_FOR_ICON;
+ break;
+
+ case PACKET_TYPE_STRING:
+ // Do we have this string already?
+ temp = shget(__runtimeData.strings, packet->data);
+ if (temp) {
+ DEL(temp);
+ shdel(__runtimeData.strings, packet->data);
+ }
+ // Store in string table.
+ shput(__runtimeData.strings, packet->data, strdup(&packet->data[strlen(packet->data) + 1]));
+ break;
+
+ case PACKET_TYPE_VERSION:
+ packetContentUnpack(packet->data, "i", &__runtimeData.protocolVersion);
+ // Do we need to update?
+ if (PACKET_PROTOCOL_VERSION == __runtimeData.protocolVersion) {
+ // Nope, we're good.
+ encoded.packetType = PACKET_TYPE_VERSION_OKAY;
+ } else {
+ // Version mismatch - upgrade time!
+ encoded.packetType = PACKET_TYPE_VERSION_BAD;
+ // ***TODO***
+ }
+ encoded.control = PACKET_CONTROL_DAT;
+ encoded.channel = 0;
+ encoded.encrypt = 0;
+ packetEncode(__packetThreadData, &encoded, NULL, 0);
+ // Send GOOD or BAD.
+ packetSend(__packetThreadData, &encoded);
+ break;
+
+ default:
+ logWrite("Unexpected packet received: %d\n", packet->packetType);
+ break;
+ }
+
+ packetDecodeDataDestroy(&packet);
}
@@ -104,9 +193,7 @@ static void settingsFinished(WidgetT *widget) {
}
-void taskWelcome(void *data) {
-
- (void)data;
+void welcomeShow(void) {
// 450x128 logo
@@ -150,10 +237,14 @@ void taskWelcome(void *data) {
T_BUTTON, O(_btnConnect),
T_TITLE, P("Connect"),
T_X, 379, T_Y, 157,
- T_CLICK, P(taskProxy),
- T_USER_DATA, P(taskConnectClick),
+ T_CLICK, P(btnConnectClick),
T_ENABLED, (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? T_TRUE : T_FALSE,
T_BUTTON, T_DONE,
+ T_TIMER, O(_timProgress),
+ T_EVENT, P(timWelcomeProgress),
+ T_VALUE, 0,
+ T_ENABLED, 0,
+ T_TIMER, T_DONE,
T_WINDOW, T_DONE,
T_END
@@ -163,59 +254,128 @@ void taskWelcome(void *data) {
}
-static void taskConnectClick(void *data) {
- int32_t r = 0;
- int16_t timeout = 0;
+static void timWelcomeProgress(WidgetT *widget) {
+ TimerT *t = (TimerT *)widget;
+ int32_t r = 0;
+ uint32_t len = 0;
+ static char buffer[1024] = { 0 };
+ static uint16_t offset = 0;
- (void)data;
+ switch (_state) {
+ case S_START_CONNECT:
+ // Ghost all buttons.
+ widgetEnableSet(W(_btnConnect), 0);
+ widgetEnableSet(W(_btnSettings), 0);
+ widgetEnableSet(W(_btnQuit), 0);
+ // Hide welcome banner, show init.
+ widgetVisibleSet(W(_picLogo), 0);
+ widgetVisibleSet(W(_picInit), 1);
+ _state = S_START_INIT_MODEM;
+ break;
- // Ghost all buttons.
- widgetEnableSet(W(_btnConnect), 0);
- widgetEnableSet(W(_btnSettings), 0);
- widgetEnableSet(W(_btnQuit), 0);
+ case S_START_INIT_MODEM:
+ // Open COM port.
+ r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
+ if (r != SER_SUCCESS) {
+ timerStop(t);
+ msgBoxOne("COM Problem", MSGBOX_ICON_ERROR, "Unable to open COM port!\nPlease check settings.", "Okay", btnMsgBox);
+ break;
+ }
+ // Send a CR to clear anything in the modem.
+ snprintf(buffer, 1023, "%c", 13);
+ comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
+ timerQuarterSecondsSet(t, 4);
+ _state = S_INIT_MODEM;
+ break;
- // Hide welcome banner, show init.
- widgetVisibleSet(W(_picLogo), 0);
- widgetVisibleSet(W(_picInit), 1);
- taskYield();
+ case S_INIT_MODEM:
+ // Just read anything to clear the buffer.
+ len = comRead(__configData.serialCom - 1, buffer, 1023);
+ // Send actual init
+ snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
+ comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
+ _state = S_INIT_RESULT;
+ break;
- r = netConnectStep1();
- if (r == NETWORK_CONNECT_OPEN_FAILED) {
- msgBoxOne("COM Problem", MSGBOX_ICON_ERROR, "Unable to open COM port!\nPlease check settings.", "Okay", btnMsgBox);
- return;
+ case S_INIT_RESULT:
+ len = comRead(__configData.serialCom - 1, buffer, 1023);
+ buffer[len] = 0;
+ if (strstr(buffer, "OK") == NULL) {
+ comClose(__configData.serialCom - 1);
+ timerStop(t);
+ msgBoxOne("Modem Problem", MSGBOX_ICON_ERROR, "Modem does not support ENET!\nPlease check settings.", "Okay", btnMsgBox);
+ break;
+ }
+ // Show dialing, dial service.
+ widgetVisibleSet(W(_picDialing), 1);
+ timerQuarterSecondsSet(t, 0);
+ _state = S_DIAL;
+ break;
+
+ case S_DIAL:
+ snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
+ comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
+ timerQuarterSecondsSet(t, 0); // Run as fast as we can so we don't miss any data.
+ offset = 0;
+ _timeoutCounter = 7 * 4; // Seven seconds.
+ _state = S_WAIT_FOR_BANNER;
+ break;
+
+ case S_WAIT_FOR_BANNER:
+ // Process incoming bytes one at a time so we don't accidentally eat the first packet after the banner.
+ len = comRead(__configData.serialCom - 1, &buffer[offset], 1);
+ offset += len;
+ buffer[offset] = 0;
+ // ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
+ if (strstr(buffer, "KPMPGSMKII\rOKAY\r") != NULL) {
+ // Connect! Start packet handler and negotiate encryption.
+ netPacketHandlerStart();
+ packetEncryptionSetup(__packetThreadData);
+ // Watch system channel for packets.
+ netChannelSystemGet(packetHandler);
+ timerQuarterSecondsSet(t, 1);
+ _timeoutCounter = 5 * 4; // Five seconds.
+ _state = S_WAIT_FOR_ENCRYPTION;
+ break;
+ }
+ // Did we time out?
+ if (guiTimerQuarterSecondTick()) _timeoutCounter--;
+ if (_timeoutCounter == 0) {
+ comClose(__configData.serialCom - 1);
+ timerStop(t);
+ msgBoxOne("No Connection", MSGBOX_ICON_INFORMATION, "Unable to connect to server!\nPlease check settings or try later.", "Okay", btnMsgBox);
+ }
+ break;
+
+ case S_WAIT_FOR_ENCRYPTION:
+ if (packetEncryptionReady()) {
+ timerQuarterSecondsSet(t, 5 * 4);
+ _state = S_WAIT_FOR_DATA_TIMEOUT;
+ break;
+ }
+ // Did we time out?
+ _timeoutCounter--;
+ if (_timeoutCounter == 0) {
+ netPacketHandlerStop();
+ comClose(__configData.serialCom - 1);
+ timerStop(t);
+ msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to negotiate encryption settings!", "Okay", btnMsgBox);
+ }
+ break;
+
+ case S_WAIT_FOR_DATA_TIMEOUT:
+ netPacketHandlerStop();
+ comClose(__configData.serialCom - 1);
+ timerStop(t);
+ msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to fetch client settings!", "Okay", btnMsgBox);
+ break;
+
+ case S_WAIT_FOR_ICON:
+ // Switch to Login window.
+ timerStop(t);
+ netChannelSystemRelease(packetHandler);
+ guiDelete(D(_winWelcome));
+ loginShow();
+ break;
}
- if (r == NETWORK_CONNECT_BAD_MODEM) {
- msgBoxOne("Modem Problem", MSGBOX_ICON_ERROR, "Modem does not support ENET!\nPlease check settings.", "Okay", btnMsgBox);
- return;
- }
-
- // Show dialing, dial service.
- widgetVisibleSet(W(_picDialing), 1);
- taskYield();
-
- r = netConnectStep2();
- if (r == NETWORK_CONNECT_NO_CARRIER) {
- msgBoxOne("No Connection", MSGBOX_ICON_INFORMATION, "Unable to connect to server!\nPlease check settings or try later.", "Okay", btnMsgBox);
- return;
- }
- if (r == NETWORK_CONNECT_BAD_ENCRYPTION) {
- msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to negotiate encryption settings!", "Okay", btnMsgBox);
- return;
- }
- if (r == NETWORK_CONNECT_BAD_SETTINGS) {
- msgBoxOne("Negotiation Error", MSGBOX_ICON_INFORMATION, "Unable to fetch client settings!", "Okay", btnMsgBox);
- return;
- }
-
- // Connected! Show icon.
- widgetVisibleSet(W(_picConnect), 1);
- timeout = 6; // Roughly 1.5 seconds.
- while (timeout > 0 && !guiHasStopped()) {
- taskYield();
- if (__timerQuarterSecondTick) timeout--;
- }
-
- // Switch to Login window.
- guiDelete(D(_winWelcome));
- taskCreate(taskLogin, NULL);
}
diff --git a/client/src/welcome.h b/client/src/welcome.h
index bc64762..3abb33d 100644
--- a/client/src/welcome.h
+++ b/client/src/welcome.h
@@ -25,7 +25,7 @@
#include "os.h"
-void taskWelcome(void *data);
+void welcomeShow(void);
#endif // WELCOME_H
diff --git a/kanga.world/content/4_chat/redirect.txt b/kanga.world/content/4_chat/1_discord/redirect.txt
similarity index 75%
rename from kanga.world/content/4_chat/redirect.txt
rename to kanga.world/content/4_chat/1_discord/redirect.txt
index 051a81d..8bedea0 100644
--- a/kanga.world/content/4_chat/redirect.txt
+++ b/kanga.world/content/4_chat/1_discord/redirect.txt
@@ -1,4 +1,4 @@
-Title: Chat
+Title: Discord
----
diff --git a/kanga.world/content/4_chat/2_matrix/redirect.txt b/kanga.world/content/4_chat/2_matrix/redirect.txt
new file mode 100644
index 0000000..92a14e9
--- /dev/null
+++ b/kanga.world/content/4_chat/2_matrix/redirect.txt
@@ -0,0 +1,5 @@
+Title: Matrix
+
+----
+
+Redirect: https://matrix.to/#/#DosGame:matrix.kangaroopunch.com
\ No newline at end of file
diff --git a/kanga.world/content/4_chat/go-home.txt b/kanga.world/content/4_chat/go-home.txt
new file mode 100644
index 0000000..8afa866
--- /dev/null
+++ b/kanga.world/content/4_chat/go-home.txt
@@ -0,0 +1 @@
+Title: Chat
\ No newline at end of file
diff --git a/kanga.world/site/plugins/kangaworld-integration/api/user.php b/kanga.world/site/plugins/kangaworld-integration/api/user.php
index 0b457cf..8046d7e 100644
--- a/kanga.world/site/plugins/kangaworld-integration/api/user.php
+++ b/kanga.world/site/plugins/kangaworld-integration/api/user.php
@@ -57,6 +57,7 @@ function kpApiUserLogin($username, $pass, &$response) {
// Find user by name instead of email.
$user = kirby()->users()->filterBy('name', $username)->first();
if ($user) {
+ // ***TODO*** Must be activated!
// Attempt to sign them in.
kirby()->auth()->login($user->email(), $pass);
// They don't need an actual Kirby session, so log them off.
diff --git a/kanga.world/site/plugins/kangaworld-integration/features/api.php b/kanga.world/site/plugins/kangaworld-integration/features/api.php
index e52e24f..df2949a 100644
--- a/kanga.world/site/plugins/kangaworld-integration/features/api.php
+++ b/kanga.world/site/plugins/kangaworld-integration/features/api.php
@@ -23,6 +23,11 @@ return [
switch (get('command')) {
+ case 'API_AVAILABLE':
+ $response['result'] = 'true';
+ $response['reason'] = 'API Available.';
+ break;
+
case 'API_TEST':
kpApiTest($response);
break;
diff --git a/kanga.world/site/snippets/menu.php b/kanga.world/site/snippets/menu.php
index 526baa1..3578f44 100644
--- a/kanga.world/site/snippets/menu.php
+++ b/kanga.world/site/snippets/menu.php
@@ -12,8 +12,8 @@
= $item->title() ?>
diff --git a/kanga.world/site/templates/go-home.php b/kanga.world/site/templates/go-home.php
new file mode 100644
index 0000000..4b82373
--- /dev/null
+++ b/kanga.world/site/templates/go-home.php
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/server/src/client.c b/server/src/client.c
index da5b584..66cf7c1 100644
--- a/server/src/client.c
+++ b/server/src/client.c
@@ -37,17 +37,10 @@ typedef void (*clientApi)(ClientThreadT *client, PacketDecodeDataT *data);
// Also update enum in packets.h!
-clientApi clientApiMethod[PACKET_END_OF_SERVER_PACKETS - PACKET_END_OF_DUAL_PACKETS] = {
- clientApiClientShutdown,
- clientApiLogin,
- clientApiPong,
- clientApiSignup,
- clientApiVersionBad,
- clientApiVersionOkay
-};
+static clientApi _clientApiMethod[PACKET_TYPE_COUNT];
-static uint8_t clientDequeuePacket(ClientThreadT *client);
+static uint8_t clientDequeuePacket(ClientThreadT *client);
static uint8_t clientDequeuePacket(ClientThreadT *client) {
@@ -68,8 +61,8 @@ static uint8_t clientDequeuePacket(ClientThreadT *client) {
// New data or not, process anything in the queue.
if (packetDecode(client->packetThreadData, &decode, data, length)) {
- if ((decode.packetType > PACKET_END_OF_DUAL_PACKETS) && (decode.packetType < PACKET_END_OF_SERVER_PACKETS)) {
- clientApiMethod[decode.packetType - (PACKET_END_OF_DUAL_PACKETS + 1)](client, &decode);
+ if (_clientApiMethod[decode.packetType]) {
+ _clientApiMethod[decode.packetType](client, &decode);
} else {
consoleMessageQueue("%ld: Channel %d Unknown Packet %d\n", client->threadIndex, decode.channel, decode.packetType);
}
@@ -103,6 +96,23 @@ void clientQueuePacket(ClientThreadT *client, uint8_t *data, uint32_t length) {
}
+void clientShutdown(void) {
+ // Nothing yet.
+}
+
+
+void clientStartup(void) {
+ memset(_clientApiMethod, 0, sizeof(_clientApiMethod));
+
+ _clientApiMethod[PACKET_TYPE_CLIENT_SHUTDOWN] = clientApiClientShutdown;
+ _clientApiMethod[PACKET_TYPE_LOGIN] = clientApiLogin;
+ _clientApiMethod[PACKET_TYPE_PONG] = clientApiPong;
+ _clientApiMethod[PACKET_TYPE_SIGNUP] = clientApiSignup;
+ _clientApiMethod[PACKET_TYPE_VERSION_BAD] = clientApiVersionBad;
+ _clientApiMethod[PACKET_TYPE_VERSION_OKAY] = clientApiVersionOkay;
+}
+
+
void *clientThread(void *data) {
ENetPeer *peer = (ENetPeer *)data;
@@ -134,6 +144,7 @@ void *clientThread(void *data) {
packetSend(client->packetThreadData, &encoded);
DEL(packetData);
versionSent = 1;
+ consoleMessageQueue("PACKET_TYPE_VERSION sent.\n");
}
}
diff --git a/server/src/client.h b/server/src/client.h
index dc34e4f..d0434c0 100644
--- a/server/src/client.h
+++ b/server/src/client.h
@@ -53,6 +53,8 @@ typedef struct ClientThreadS {
void clientQueuePacket(ClientThreadT *client, uint8_t *data, uint32_t length);
+void clientShutdown(void);
+void clientStartup(void);
void *clientThread(void *data);
diff --git a/server/src/client/login.c b/server/src/client/login.c
index 6dc221d..119683c 100644
--- a/server/src/client/login.c
+++ b/server/src/client/login.c
@@ -56,7 +56,7 @@ void clientApiLogin(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_LOGIN_RESULT;
- encoded.channel = 0;
+ encoded.channel = data->channel;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it.
diff --git a/server/src/client/signup.c b/server/src/client/signup.c
index 8d41f3e..957a080 100644
--- a/server/src/client/signup.c
+++ b/server/src/client/signup.c
@@ -59,7 +59,7 @@ void clientApiSignup(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_SIGNUP_RESULT;
- encoded.channel = 0;
+ encoded.channel = data->channel;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it.
diff --git a/server/src/client/version.c b/server/src/client/version.c
index 3558f32..a9d3c04 100644
--- a/server/src/client/version.c
+++ b/server/src/client/version.c
@@ -72,12 +72,13 @@ void clientApiVersionOkay(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_STRING;
- encoded.channel = 0;
+ encoded.channel = data->channel;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, buffer, length);
// Send it.
packetSend(client->packetThreadData, &encoded);
DEL(buffer);
+ consoleMessageQueue("PACKET_TYPE_STRING [%s] sent.\n", strings[i].key);
}
restHelperConfigStringMapRelease(strings);
@@ -111,22 +112,23 @@ void clientApiVersionOkay(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_NUMBER;
- encoded.channel = 0;
+ encoded.channel = data->channel;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, buffer, length);
// Send it.
packetSend(client->packetThreadData, &encoded);
DEL(buffer);
+ consoleMessageQueue("PACKET_TYPE_NUMBER [%s] sent.\n", integers[i].key);
}
restHelperConfigIntegerMapRelease(integers);
// Build PROCEED packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_PROCEED;
- encoded.channel = 0;
+ encoded.channel = data->channel;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, NULL, 0);
// Send it.
packetSend(client->packetThreadData, &encoded);
-
+ consoleMessageQueue("PACKET_TYPE_PROCEED sent.\n");
}
diff --git a/server/src/main.c b/server/src/main.c
index aa6e579..aa92fec 100644
--- a/server/src/main.c
+++ b/server/src/main.c
@@ -109,6 +109,7 @@ int main(int argc, char *argv[]) {
settingsClientVersion = restHelperConfigIntegerGet(response, "clientVersion", 1);
restRelease(response);
+ clientStartup();
serverStartup(settingsPortNumber, settingsMaxClients);
logWrite("Server online.\n");
@@ -121,6 +122,7 @@ int main(int argc, char *argv[]) {
// Wait for all running threads to shut down.
logWrite("Shutting down.\n");
serverShutdown();
+ clientShutdown();
// Shut down.
restShutdown();
diff --git a/server/src/rest.c b/server/src/rest.c
index 0f6aac9..d2f5653 100644
--- a/server/src/rest.c
+++ b/server/src/rest.c
@@ -275,7 +275,8 @@ void restShutdown(void) {
uint8_t restStartup(char *url, char *user, char *password) {
- uint64_t i;
+ uint64_t i;
+ json_object *response;
curl_global_init(CURL_GLOBAL_ALL);
@@ -299,6 +300,11 @@ uint8_t restStartup(char *url, char *user, char *password) {
_restUser = strdup(user);
_restPass = strdup(password);
+ // Is the remote server there?
+ response = restRequest("API_AVAILABLE", NULL);
+ if (!response) return FAIL;
+ restRelease(response);
+
return SUCCESS;
}
diff --git a/server/src/server.c b/server/src/server.c
index f9fca7a..8d6e582 100644
--- a/server/src/server.c
+++ b/server/src/server.c
@@ -134,8 +134,9 @@ void *serverThread(void *data) {
// Tell the console.
enet_address_get_host_ip(&event.peer->address, buffer, 2047);
consoleMessageQueue("%ld: [%s] connected.\n", client->threadIndex, buffer);
+ // ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
// Send banner to client.
- packet = enet_packet_create("KPMPGSMKII\r", 11, ENET_PACKET_FLAG_RELIABLE);
+ packet = enet_packet_create("KPMPGSMKII\rOKAY\r", 16, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 0, packet);
break;
diff --git a/shared/log.c b/shared/log.c
index b50ff30..2b32e56 100644
--- a/shared/log.c
+++ b/shared/log.c
@@ -78,11 +78,11 @@ void logWrite(char *format, ...) {
vsnprintf(_logBuffer, _logBufferSize, format, args2);
}
-#ifdef __linux__
+//#ifdef __linux__
// Also output to stdout on Linux.
fprintf(stdout, "%s", _logBuffer);
fflush(stdout);
-#endif
+//#endif
if (_logCallback) _logCallback(_logBuffer);
diff --git a/shared/packet.c b/shared/packet.c
index 36dbbc8..8c2e332 100644
--- a/shared/packet.c
+++ b/shared/packet.c
@@ -78,7 +78,6 @@ char *packetContentPack(uint16_t *length, char *format, ...) {
static char work[PACKET_MAX] = { 0 };
char *result = NULL;
char *buffer = NULL;
- int8_t value8 = 0;
int32_t value32 = 0;
*length = 0;
@@ -123,7 +122,6 @@ char *packetContentPack(uint16_t *length, char *format, ...) {
void packetContentUnpack(char *buffer, char *format, ...) {
va_list args = { 0 };
char **string = NULL;
- int8_t *value8 = NULL;
int32_t *value32 = NULL;
uint16_t length = 0;
diff --git a/shared/packets.h b/shared/packets.h
index 9bf55db..f83d5bd 100644
--- a/shared/packets.h
+++ b/shared/packets.h
@@ -31,22 +31,19 @@
// This enum is treated as BYTES in the code. Do not go over 255 entries.
// Also update array in client.c!
typedef enum PacketTypeE {
- // Packets that can received by both server and client:
+ // These packets have to be first and in this order! Do not change them!
PACKET_TYPE_NONE = 0, // No packet.
PACKET_TYPE_DH_REQUEST,
PACKET_TYPE_DH_RESPONSE,
-
- PACKET_END_OF_DUAL_PACKETS,
+ PACKET_TYPE_VERSION,
+ PACKET_TYPE_VERSION_BAD,
+ PACKET_TYPE_VERSION_OKAY,
// Packets received by only the server:
PACKET_TYPE_CLIENT_SHUTDOWN,
PACKET_TYPE_LOGIN,
PACKET_TYPE_PONG,
PACKET_TYPE_SIGNUP,
- PACKET_TYPE_VERSION_BAD,
- PACKET_TYPE_VERSION_OKAY,
-
- PACKET_END_OF_SERVER_PACKETS,
// Packets received by only the client:
PACKET_TYPE_LOGIN_RESULT,
@@ -56,7 +53,6 @@ typedef enum PacketTypeE {
PACKET_TYPE_SERVER_SHUTDOWN,
PACKET_TYPE_SIGNUP_RESULT,
PACKET_TYPE_STRING,
- PACKET_TYPE_VERSION,
// How many packet types do we recognize?
PACKET_TYPE_COUNT
diff --git a/test.sh b/test.sh
index bf84970..1fb1ed5 100755
--- a/test.sh
+++ b/test.sh
@@ -1,2 +1,4 @@
#!/bin/bash
-${HOME}/code/dosbox-custom/dosbox-staging/build/dosbox -noprimaryconf -nolocalconf -conf test.conf &
+#${HOME}/code/dosbox-custom/dosbox-staging/build/dosbox -noprimaryconf -nolocalconf -conf test.conf &
+#dosbox -noprimaryconf -nolocalconf -conf test.conf &
+${HOME}/bin/dosbox-staging-linux-v0.78.1/dosbox -noprimaryconf -nolocalconf -conf test.conf &