Completed conversion from task-based code to event-based. Needs testing but now runs on DOS!

This commit is contained in:
Scott Duensing 2022-01-31 19:11:58 -06:00
parent ecf6d1f842
commit 114dd36513
64 changed files with 1928 additions and 1216 deletions

View file

@ -33,10 +33,13 @@ BINDIR = bin
# CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI # CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI
CFLAGS := $(DEBUG) 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)/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)/shared -I$(SRCDIR)/shared/thirdparty
#CFLAGS += -I$(SRCDIR)/client/src/thirdparty/dzcomm -I$(SRCDIR)/client/src/thirdparty/dzcomm/include
CPPFLAGS := CPPFLAGS :=
LDFLAGS := LDFLAGS :=
#LDFLAGS += -L$(SRCDIR)/client/src/thirdparty/dzcomm -ldzcom
PREFIX := /usr/local PREFIX := /usr/local
TARGET_ARCH := TARGET_ARCH :=
@ -61,6 +64,7 @@ DEP := $(OBJ:.o=.d)
BIN := $(BINDIR)/$(TARGET) BIN := $(BINDIR)/$(TARGET)
-include $(DEP) -include $(DEP)
#obj/client/src/thirdparty/dzcomm/src/dos/djirqs.o
#$(info [${SRC}]) #$(info [${SRC}])
#$(info [${OBJ}]) #$(info [${OBJ}])

View file

@ -27,6 +27,7 @@ mkdir -p \
obj/client/src/system \ obj/client/src/system \
obj/client/src/dos \ obj/client/src/dos \
obj/client/src/gui \ obj/client/src/gui \
obj/client/src/embedded \
obj/client/src/thirdparty/serial \ obj/client/src/thirdparty/serial \
obj/shared/thirdparty/memwatch \ obj/shared/thirdparty/memwatch \
obj/shared/thirdparty/blowfish-api \ obj/shared/thirdparty/blowfish-api \

View file

@ -79,8 +79,10 @@ function outputLicense() {
pushd font/data pushd font/data
createEmbeddedBinary vga8x14 dat ../../client/src/embedded createEmbeddedBinary vga8x14 dat ../../client/src/embedded
popd
pushd client/data
createEmbeddedBinary mouse png ../../client/src/embedded
popd popd

View file

@ -29,6 +29,9 @@ QMAKE_CFLAGS += -O0
DEFINES *= CLIENT DEFINES *= CLIENT
UNUSED_CRAP = \
src/thirdparty/dzcomm/include/dzcomm.h
DOS_HEADERS = \ DOS_HEADERS = \
src/thirdparty/serial/serial.h src/thirdparty/serial/serial.h
@ -68,9 +71,10 @@ HEADERS = \
$$SHARED/packets.h \ $$SHARED/packets.h \
src/config.h \ src/config.h \
$$SHARED/util.h \ $$SHARED/util.h \
src/embedded/vga8x14.h \ src/embedded/embedded.h \
src/firstrun.h \
src/gui/msgbox.h \ src/gui/msgbox.h \
src/gui/timer.h \
src/hangup.h \
src/login.h \ src/login.h \
src/menu.h \ src/menu.h \
src/network.h \ src/network.h \
@ -84,13 +88,13 @@ HEADERS = \
src/system/surface.h \ src/system/surface.h \
src/system/taglist.h \ src/system/taglist.h \
src/system/keyboard.h \ src/system/keyboard.h \
src/system/task.h \
src/system/timer.h \
$$SHARED/array.h \ $$SHARED/array.h \
$$SHARED/log.h \ $$SHARED/log.h \
src/system/mouse.h \ src/system/mouse.h \
src/system/vesa.h \ src/system/vesa.h \
src/system/os.h \ src/system/os.h \
src/embedded/vga8x14.h \
src/embedded/mouse.h \
src/gui/listbox.h \ src/gui/listbox.h \
src/gui/terminal.h \ src/gui/terminal.h \
src/gui/updown.h \ src/gui/updown.h \
@ -117,16 +121,11 @@ SOURCES = \
$$SHARED/packet.c \ $$SHARED/packet.c \
$$SHARED/thirdparty/tiny-AES-c/aes.c \ $$SHARED/thirdparty/tiny-AES-c/aes.c \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
src/config.c \
$$SHARED/memory.c \ $$SHARED/memory.c \
src/embedded/embedded.c \ src/embedded/embedded.c \
src/firstrun.c \
src/gui/msgbox.c \ src/gui/msgbox.c \
src/login.c \ src/gui/timer.c \
src/menu.c \ src/hangup.c \
src/network.c \
src/settings.c \
src/signup.c \
src/system/comport.c \ src/system/comport.c \
src/system/os.c \ src/system/os.c \
src/system/surface.c \ src/system/surface.c \
@ -134,8 +133,6 @@ SOURCES = \
$$SHARED/util.c \ $$SHARED/util.c \
$$SHARED/array.c \ $$SHARED/array.c \
$$SHARED/log.c \ $$SHARED/log.c \
src/system/timer.c \
src/system/task.c \
src/gui/listbox.c \ src/gui/listbox.c \
src/gui/terminal.c \ src/gui/terminal.c \
src/gui/updown.c \ src/gui/updown.c \
@ -152,8 +149,14 @@ SOURCES = \
src/gui/button.c \ src/gui/button.c \
src/gui/checkbox.c \ src/gui/checkbox.c \
src/gui/label.c \ src/gui/label.c \
src/config.c \
src/main.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 = \ LIBS = \
-lSDL2 \ -lSDL2 \

View file

@ -19,4 +19,4 @@
#define EMBED_HERE #define EMBED_HERE
#include "vga8x14.h" #include "embedded/embedded.h"

View file

@ -18,23 +18,12 @@
*/ */
#ifndef TASK_H #ifndef EMBEDDED_H
#define TASK_H #define EMBEDDED_H
#include "os.h" #include "mouse.h"
#include "widget.h" #include "vga8x14.h"
typedef void (*taskFunction)(void *data); #endif // EMBEDDED_H
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

457
client/src/embedded/mouse.h Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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

View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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();
}
}

View file

@ -77,7 +77,7 @@ static void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_
// Fire callback on mouse up. // Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) { if (event == MOUSE_EVENT_LEFT_UP) {
if (b->clicked) b->clicked(widget); if (b->clicked) guiPendingEventAdd(widget, b->clicked);
} }
} }

View file

@ -64,7 +64,7 @@ static void checkboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint1
// Toggle value. // Toggle value.
checkboxValueSet(c, !checkboxValueGet(c)); checkboxValueSet(c, !checkboxValueGet(c));
// Fire callback on mouse up. // Fire callback on mouse up.
if (c->clicked) c->clicked(widget); if (c->clicked) guiPendingEventAdd(widget, c->clicked);
} }
} }

View file

@ -22,10 +22,16 @@
#include "gui.h" #include "gui.h"
#include "embedded/vga8x14.h"
#include "widget.h" #include "widget.h"
#include "desktop.h" #include "desktop.h"
#include "window.h" #include "window.h"
#include "embedded/embedded.h"
typedef struct PendingEventsS {
WidgetT *widget;
widgetCallback callback;
} PendingEventsT;
int16_t _guiMetric[METRIC_COUNT]; int16_t _guiMetric[METRIC_COUNT];
@ -37,13 +43,23 @@ uint16_t _guiDragOffsetY = 0;
WindowT *_guiActiveWindow = NULL; WindowT *_guiActiveWindow = NULL;
static DesktopT *_guiDesktop = NULL; static DesktopT *_guiDesktop = NULL;
static WidgetT *_guiLastWidgetLeft = NULL; static WidgetT *_guiLastWidgetLeft = NULL;
static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE; static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
static WidgetT *_guiFocused = NULL; static WidgetT *_guiFocused = NULL;
static uint8_t _guiHasStopped = 0; // This starts as 0 even if the GUI hasn't been started. static uint8_t _guiHasStopped = 0; // This starts as 0 even if the GUI hasn't been started.
static WidgetT ***_guiDeleteList = NULL; 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! // Widget Magic Debug Info. Don't forget to change MagicE!
static char *_magicDebugNames[MAGIC_COUNT] = { 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 // Since deleting happens in widget events, it's not safe to do it
// immediately. Instead, we make a list of what to delete and // immediately. Instead, we make a list of what to delete and
// then process it before painting. // 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); arrput(_guiDeleteList, widget);
} }
@ -249,7 +269,6 @@ static void guiDeleteListItem(WidgetT **widget) {
if (plen == 1) { if (plen == 1) {
// Erase the list. // Erase the list.
arrfree(w->parent->children); arrfree(w->parent->children);
w->parent->children = NULL;
} }
} }
} }
@ -259,7 +278,6 @@ static void guiDeleteListItem(WidgetT **widget) {
if (w == _guiFocused) _guiFocused = NULL; if (w == _guiFocused) _guiFocused = NULL;
// Delete us. // Delete us.
//logWrite("Deleting %s %p\n", _magicDebugNames[w->magic], w);
if (w->delMethod != NULL) w->delMethod(&w); if (w->delMethod != NULL) w->delMethod(&w);
arrfree(w->children); arrfree(w->children);
if (w->surface != NULL) { if (w->surface != NULL) {
@ -455,6 +473,14 @@ void guiMouseProcess(MouseT *mouse) {
void guiPaint(WidgetT *widget) { 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. // Process any pending widget deletions.
guiDeleteList(); 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) { WidgetT *guiRootGet(void) {
return (WidgetT *)_guiDesktop; 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) { void *guiUserDataGet(WidgetT *widget) {
return widget->userData; return widget->userData;
} }

View file

@ -54,6 +54,7 @@ enum MagicE {
MAGIC_UPDOWN, MAGIC_UPDOWN,
MAGIC_LISTBOX, MAGIC_LISTBOX,
MAGIC_TERMINAL, MAGIC_TERMINAL,
MAGIC_TIMER,
//MAGIC_DROPDOWN, //MAGIC_DROPDOWN,
MAGIC_COUNT MAGIC_COUNT
}; };
@ -201,10 +202,19 @@ void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *
void guiMouseProcess(MouseT *mouse); void guiMouseProcess(MouseT *mouse);
void guiPaint(WidgetT *widget); void guiPaint(WidgetT *widget);
void guiParentAndChildrenDirtySet(WidgetT *widget); void guiParentAndChildrenDirtySet(WidgetT *widget);
void guiPendingEventAdd(WidgetT *widget, void *callback);
WidgetT *guiRootGet(void); WidgetT *guiRootGet(void);
void guiShutdown(void); void guiShutdown(void);
DesktopT *guiStartup(void); DesktopT *guiStartup(void);
void guiStop(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 *guiUserDataGet(WidgetT *widget);
void guiUserDataSet(WidgetT *widget, void *userData); void guiUserDataSet(WidgetT *widget, void *userData);
void guiWidgetAndChildrenDirtySet(WidgetT *widget); void guiWidgetAndChildrenDirtySet(WidgetT *widget);

View file

@ -26,6 +26,9 @@
#include "vesa.h" #include "vesa.h"
static ImageT *imageNativeImageGet(unsigned char *raw, uint16_t x, uint16_t y);
ImageT *imageAllocate(uint16_t w, uint16_t h) { ImageT *imageAllocate(uint16_t w, uint16_t h) {
uint16_t x; uint16_t x;
uint16_t y; 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) { uint16_t imageHeightGet(ImageT *image) {
return image->height; return image->height;
} }
@ -104,14 +121,20 @@ ImageT *imageLoad(char *filename) {
uint16_t x; uint16_t x;
uint16_t y; uint16_t y;
uint16_t n; uint16_t n;
uint32_t b;
unsigned char *raw; unsigned char *raw;
ImageT *image;
// Load image from disk // Load image from disk
raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, 3); raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, 3);
if (!raw) return NULL; 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. // Create native image.
image = imageAllocate(x, y); image = imageAllocate(x, y);
if (!image) { if (!image) {

View file

@ -37,6 +37,7 @@ typedef struct ImageS {
ImageT *imageAllocate(uint16_t w, uint16_t h); ImageT *imageAllocate(uint16_t w, uint16_t h);
ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color); ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color);
ImageT *imageFromRAMLoad(uint8_t *buffer, size_t len);
uint16_t imageHeightGet(ImageT *image); uint16_t imageHeightGet(ImageT *image);
uint8_t imageInfoGet(char *filename, uint16_t *width, uint16_t *height); uint8_t imageInfoGet(char *filename, uint16_t *width, uint16_t *height);
ImageT *imageLoad(char *filename); ImageT *imageLoad(char *filename);

View file

@ -95,7 +95,7 @@ static void labelMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t
// Fire callback on mouse up. // Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) { if (event == MOUSE_EVENT_LEFT_UP) {
if (l->clicked) l->clicked(widget); if (l->clicked) guiPendingEventAdd(widget, l->clicked);
} }
} }

View file

@ -67,7 +67,7 @@ static void pictureMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16
// Fire callback on mouse up. // Fire callback on mouse up.
if (event == MOUSE_EVENT_LEFT_UP) { if (event == MOUSE_EVENT_LEFT_UP) {
if (p->clicked) p->clicked(widget); if (p->clicked) guiPendingEventAdd(widget, p->clicked);
} }
} }

View file

@ -70,7 +70,7 @@ static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t
// Select us. // Select us.
radioSelectedSet(r); radioSelectedSet(r);
// Fire callback on mouse up. // Fire callback on mouse up.
if (r->clicked) r->clicked(widget); if (r->clicked) guiPendingEventAdd(widget, r->clicked);
} }
} }

View file

@ -301,7 +301,7 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
free(draw); free(draw);
// Draw cursor. // Draw cursor.
if (guiFocusGet() == widget && __timerQuarterSecondOn) { if (guiFocusGet() == widget && guiTimerQuarterSecondOn()) {
caretPos = textX + fontWidthGet(_guiFont) * t->caret; caretPos = textX + fontWidthGet(_guiFont) * t->caret;
fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], caretPos, textY); fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], caretPos, textY);
} }

109
client/src/gui/timer.c Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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;
}

View file

@ -22,22 +22,26 @@
#define TIMER_H #define TIMER_H
#include "os.h" #include "gui.h"
#include "widget.h"
extern uint8_t __timerQuarterSecondTick; typedef struct TimerS {
extern uint8_t __timerHalfSecondTick; WidgetT base; // Must be first in every widget
extern uint8_t __timerSecondTick; widgetCallback timeout;
uint16_t quarterSeconds;
extern uint8_t __timerQuarterSecondOn; uint16_t counter;
extern uint8_t __timerHalfSecondOn; uint8_t running;
extern uint8_t __timerSecondOn; } TimerT;
void timerShutdown(void); WidgetT *timerInit(WidgetT *widget, widgetCallback timeout, uint16_t quarterSeconds);
void timerStartup(void); TimerT *timerNew(widgetCallback timeout, uint16_t quarterSeconds);
void timerUpdate(void); void timerQuarterSecondsSet(TimerT *timer, uint16_t quarterSeconds);
void timerQuarterSecondsWait(uint8_t quarterSeconds); void timerReset(TimerT *timer);
void timerStart(TimerT *timer);
void timerStop(TimerT *timer);
void timerTimeoutSet(TimerT *timer, widgetCallback timeout);
#endif // TIMER_H #endif // TIMER_H

View file

@ -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); fontRender(_guiFont, draw, _guiColor[COLOR_UPDOWN_TEXT], _guiColor[COLOR_UPDOWN_BACKGROUND], textX, textY);
// Draw cursor. // Draw cursor.
if (guiFocusGet() == widget && __timerQuarterSecondOn) { if (guiFocusGet() == widget && guiTimerQuarterSecondOn()) {
textX += (strlen(draw) - 1) * fontWidthGet(_guiFont); textX += (strlen(draw) - 1) * fontWidthGet(_guiFont);
fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], textX, textY); fontRender(_guiFont, cursor, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], textX, textY);
} }

107
client/src/hangup.c Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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;
}
}

View file

@ -18,14 +18,14 @@
*/ */
#ifndef FIRSTRUN_H #ifndef HANGUP_H
#define FIRSTRUN_H #define HANGUP_H
#include "os.h" #include "os.h"
void firstRunCheckSetup(void); void hangupShow(void *nextFunction);
#endif // FIRSTRUN_H #endif // HANGUP_H

View file

@ -32,9 +32,6 @@
#include "comport.h" #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 TIMER_INTERVAL (1000 / TICKS_PER_SECOND)
#define COM_BUFFER_SIZE 2048 #define COM_BUFFER_SIZE 2048
@ -61,7 +58,7 @@ static uint8_t _ASCIIKeep = 0;
static uint8_t _scanCodeKeep = 0; static uint8_t _scanCodeKeep = 0;
static uint8_t _keyPressed = 0; static uint8_t _keyPressed = 0;
static uint8_t _debounce = 0; static uint8_t _debounce = 0;
static long _timerTicks = 0; static uint32_t _timerTicks = 0;
static SDL_TimerID _timerID = { 0 }; static SDL_TimerID _timerID = { 0 };
static ENetHost *_host = NULL; static ENetHost *_host = NULL;
static ENetPeer *_peer = NULL; static ENetPeer *_peer = NULL;
@ -86,10 +83,7 @@ static uint32_t timerCallback(uint32_t interval, void *param);
static void vbeScreenshot(void); static void vbeScreenshot(void);
long biostime(int cmd, long newtime) { uint32_t rawclock(void) {
(void)cmd;
(void)newtime;
return _timerTicks; return _timerTicks;
} }

View file

@ -21,61 +21,82 @@
#include "textbox.h" #include "textbox.h"
#include "button.h" #include "button.h"
#include "msgbox.h" #include "msgbox.h"
#include "timer.h"
#include "runtime.h" #include "runtime.h"
#include "config.h" #include "config.h"
#include "comport.h" #include "comport.h"
#include "network.h" #include "network.h"
#include "taglist.h" #include "taglist.h"
#include "timer.h"
#include "task.h"
#include "login.h" #include "login.h"
#include "signup.h" #include "signup.h"
#include "welcome.h" #include "welcome.h"
#include "menu.h" #include "menu.h"
#include "hangup.h"
static WindowT *_winLogin = NULL; typedef enum LoginStateE {
static TextboxT *_txtUser = NULL; S_START_LOGIN = 0,
static TextboxT *_txtPass = NULL; S_WAIT_LOGIN
static ButtonT *_btnCancel = NULL; } LoginStateT;
static ButtonT *_btnSignUp = NULL;
static ButtonT *_btnLogin = NULL;
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 btnCancelClick(WidgetT *widget);
static void btnLoginClick(WidgetT *widget);
static void btnSignUpClick(WidgetT *widget); static void btnSignUpClick(WidgetT *widget);
static void btnMsgBoxCancel(MsgBoxButtonT button); static void btnMsgBoxCancel(MsgBoxButtonT button);
static void btnMsgBoxContinue(MsgBoxButtonT button); static void btnMsgBoxContinue(MsgBoxButtonT button);
static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled); static void setButtons(uint8_t enabled);
static void taskDisconnect(void *data); static void timLoginProgress(WidgetT *widget);
static void taskLoginClick(void *data);
static void btnCancelClick(WidgetT *widget) { static void btnCancelClick(WidgetT *widget) {
(void)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); setButtons(0);
msgBoxTwo("Cancel?", MSGBOX_ICON_QUESTION, "Cancel login?\n \nThis will disconnect you from the server.", "Okay", btnMsgBoxCancel, "Cancel", btnMsgBoxCancel); 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) { static void btnSignUpClick(WidgetT *widget) {
(void)widget; (void)widget;
netChannelRelease(_channel);
guiDelete(D(_winLogin)); guiDelete(D(_winLogin));
taskCreate(taskSignUp, NULL); signupShow();
} }
static void btnMsgBoxCancel(MsgBoxButtonT button) { static void btnMsgBoxCancel(MsgBoxButtonT button) {
if (button == MSGBOX_BUTTON_ONE) { if (button == MSGBOX_BUTTON_ONE) {
netChannelRelease(_channel);
guiDelete(D(_winLogin)); guiDelete(D(_winLogin));
taskCreate(taskDisconnect, taskWelcome); hangupShow(welcomeShow);
} else { } else {
setButtons(1); setButtons(1);
} }
@ -89,24 +110,9 @@ static void btnMsgBoxContinue(MsgBoxButtonT button) {
} }
static void setButtons(uint8_t enabled) { void loginShow() {
widgetEnableSet(W(_btnCancel), enabled);
widgetEnableSet(W(_btnSignUp), enabled);
widgetEnableSet(W(_btnLogin), enabled);
}
// ***TODO*** We used to have a FORGOT PASSWORD link here, too.
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.
TagItemT uiLogin[] = { TagItemT uiLogin[] = {
T_START, T_START,
@ -142,70 +148,88 @@ void taskLogin(void *data) {
T_BUTTON, O(_btnLogin), T_BUTTON, O(_btnLogin),
T_TITLE, P("Login"), T_TITLE, P("Login"),
T_X, 199, T_Y, 85, T_X, 199, T_Y, 85,
T_CLICK, P(taskProxy), T_CLICK, P(btnLoginClick),
T_USER_DATA, P(taskLoginClick),
T_BUTTON, T_DONE, 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_WINDOW, T_DONE,
T_END T_END
}; };
tagListRun(uiLogin); tagListRun(uiLogin);
_channel = netChannelGet(packetHandler);
} }
static void taskLoginClick(void *data) { static void packetHandler(PacketDecodeDataT *packet) {
char *packetData = NULL; char *packetData;
int8_t success = 0; int8_t success;
uint16_t length = 0;
int16_t timeout = 10;
PacketEncodeDataT encoded = { 0 };
PacketDecodeDataT *decoded = NULL;
(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. // ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
setButtons(0); widgetEnableSet(W(_btnCancel), enabled);
widgetEnableSet(W(_btnSignUp), enabled);
packetData = packetContentPack(&length, "ss", textboxValueGet(_txtUser), textboxValueGet(_txtPass)); widgetEnableSet(W(_btnLogin), enabled);
// 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);
} }
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;
}
}

View file

@ -25,7 +25,7 @@
#include "os.h" #include "os.h"
void taskLogin(void *data); void loginShow(void);
#endif // LOGIN_H #endif // LOGIN_H

View file

@ -40,71 +40,125 @@
#include "surface.h" #include "surface.h"
#include "mouse.h" #include "mouse.h"
#include "keyboard.h" #include "keyboard.h"
#include "task.h"
#include "image.h" #include "image.h"
#include "font.h" #include "font.h"
#include "timer.h"
#include "gui.h" #include "gui.h"
#include "config.h" #include "config.h"
#include "runtime.h" #include "runtime.h"
#include "comport.h" #include "comport.h"
#include "network.h" #include "network.h"
#include "firstrun.h" #include "timer.h"
#include "embedded/embedded.h"
#include "welcome.h" #include "welcome.h"
#include "signup.h" #include "settings.h"
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
RuntimeDataT __runtimeData; // Exported in runtime.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) { static void checkSettings(void);
MouseT *mouse = NULL; static void eventLoop(void);
ImageT *pointer = NULL; static uint8_t hasValidSettings(void);
ColorT alpha = { 0 }; static void shutdown(void);
static uint8_t startup(int argc, char *argv[]);
(void)data;
pointer = imageLoad("data/mouse.png"); static void checkSettings(void) {
alpha = imagePixelGet(pointer, 5, 0); // 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 { do {
timerUpdate(); netProcess();
mouse = mouseRead(); guiTimerProcess(rawclock());
_mouse = mouseRead();
if (keyHit()) { if (keyHit()) {
guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet()); guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet());
//logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt()); //logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
if (keyASCIIGet() == 27) guiStop(); if (keyASCIIGet() == 27) guiStop();
} }
guiMouseProcess(mouse); guiMouseProcess(_mouse);
guiComposite(); guiComposite();
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha); imageRenderWithAlpha(_pointer, _mouse->x, _mouse->y, _alpha);
vbeVBlankWait(); vbeVBlankWait();
vbePresent(); vbePresent();
taskYield();
} while (!guiHasStopped()); } 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__ #ifndef __linux__
// On DOS, display the contets of the log now that we're back in text mode. // On DOS, display the contets of the log now that we're back in text mode.
char *logName = NULL;
FILE *in = NULL; FILE *in = NULL;
#endif #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]); memoryStartup(argv[0]);
logOpenByHandle(memoryLogHandleGet()); logOpenByHandle(memoryLogHandleGet());
osStartup(); osStartup();
configStartup(argv[0]); configStartup(argv[0]);
#ifndef __linux__
_logName = utilAppNameWithNewExtensionGet(argv[0], "log");
#endif
// 0 1 2 3 4 5 6 7 8 // 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
logWrite("%s", "Kangaroo Punch MultiPlayer DOS Game Client Mark II\n"); logWrite("%s", "Kangaroo Punch MultiPlayer DOS Game Client Mark II\n");
@ -116,16 +170,10 @@ int main(int argc, char *argv[]) {
configShutdown(); configShutdown();
logClose(); logClose();
memoryShutdown(); memoryShutdown();
return 0; return 1;
} }
} }
timerStartup();
taskStartup();
// Perform "first run" setup tasks.
firstRunCheckSetup();
// Do we have the video mode they asked for? // Do we have the video mode they asked for?
if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) { if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) {
configShutdown(); configShutdown();
@ -137,42 +185,29 @@ int main(int argc, char *argv[]) {
surfaceStartup(); surfaceStartup();
mouseStartup(); mouseStartup();
guiStartup(); guiStartup();
// Do not call netStartup() here. It will be started when needed. netStartup();
// taskCreate(taskSignUp, NULL); _pointer = imageFromRAMLoad(mouse_png, mouse_png_len);
taskCreate(taskWelcome, NULL); _alpha = imagePixelGet(_pointer, 5, 0);
taskCreate(taskGuiEventLoop, NULL);
return 0;
taskRun(); }
netShutdown();
guiShutdown(); int main(int argc, char *argv[]) {
mouseShutdown();
surfaceShutdown(); if (startup(argc, argv)) return 1;
vbeShutdown();
taskShutdown(); // Perform "first run" setup tasks or start the client?
timerShutdown(); if (hasValidSettings()) {
configShutdown(); // We have what we need, start the client.
osShutdown(); welcomeShow();
logClose(); } else {
memoryShutdown(); // Run the setup.
settingsShow(checkSettings);
#ifndef __linux__ }
//***TODO*** Why the frack does this not work?!
textmode(C80); eventLoop();
// 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
return 0; return 0;
} }

View file

@ -21,7 +21,6 @@
#include "menu.h" #include "menu.h"
void taskMenu(void *data) { void menuShow(void) {
(void)data;
} }

View file

@ -25,7 +25,7 @@
#include "os.h" #include "os.h"
void taskMenu(void *data); void menuShow(void);
#endif // MENU_H #endif // MENU_H

View file

@ -19,7 +19,6 @@
#include "gui.h" #include "gui.h"
#include "task.h"
#include "comport.h" #include "comport.h"
#include "config.h" #include "config.h"
#include "timer.h" #include "timer.h"
@ -28,174 +27,30 @@
#include "network.h" #include "network.h"
typedef struct NetworkPacketS { typedef struct NetworkChannelsS {
uint8_t key; uint8_t key;
PacketDecodeDataT **value; netPacketHandler value;
} NetworkPacketT; } NetworkChannelsT;
static NetworkPacketT *_packets = NULL; static netPacketHandler *_systemHandlers = NULL;
static uint8_t _netRunning = 0; static NetworkChannelsT *_channels = NULL;
static uint8_t _netStarted = 0; static uint8_t _netRunning = 0;
static uint8_t _netStarted = 0;
int8_t netConnectStep1(void) { uint8_t netChannelGet(netPacketHandler handler) {
int32_t r = 0; uint8_t channel = 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.
uint16_t x = 0; uint16_t x = 0;
for (x=1; x<255; x++) { // We reserve 0 for system stuff.
if (hmgeti(_packets, x) < 0) { // Returning 0 means no channel was found.
// Find first unused channel.
for (x=1; x<255; x++) {
if (hmgeti(_channels, x) < 0) {
channel = x; channel = x;
hmput(_channels, x, handler);
break; break;
} }
} }
@ -204,23 +59,121 @@ uint8_t netGetChannelFree(void) {
} }
PacketDecodeDataT *netGetPacket(uint8_t channel) { void netChannelRelease(uint8_t channel) {
int32_t r = 0; hmdel(_channels, channel);
PacketDecodeDataT *packet = NULL; }
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; x<arrlen(_systemHandlers); /* no increment */) {
if (_systemHandlers[x] == handler) {
arrdel(_systemHandlers, x);
} else {
x++;
}
}
}
void netPacketHandlerStart(void) {
_netRunning = 1;
}
void netPacketHandlerStop(void) {
if (_netRunning) {
_netRunning = 0;
// Return all channels.
while (hmlen(_channels)) hmdel(_channels, _channels[0].key);
hmfree(_channels);
// Return all system channels.
while (arrlen(_systemHandlers)) arrdel(_systemHandlers, 0);
arrfree(_systemHandlers);
}
}
void netProcess(void) {
int32_t r;
char buffer[1024];
PacketDecodeDataT *packet;
PacketDecodeDataT decoded;
PacketEncodeDataT encoded;
// ***TODO*** Detect disconnection. Maybe have callbacks registered that can notify tasks?
if (_netRunning) {
// 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)) {
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);
break;
default:
// Is this the system channel?
if (decoded.channel == 0) {
// Send it to all registered handlers.
for (r=0; r<arrlen(_systemHandlers); r++) {
// 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.
_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) { void netShutdown(void) {
FILE *cache = NULL; FILE *cache = NULL;
netPacketHandlerStop();
if (_netStarted) { if (_netStarted) {
_netStarted = 0; _netStarted = 0;
@ -230,7 +183,7 @@ void netShutdown(void) {
if (__runtimeData.integers) { if (__runtimeData.integers) {
while (shlen(__runtimeData.integers) > 0) { while (shlen(__runtimeData.integers) > 0) {
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value); //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); shdel(__runtimeData.integers, __runtimeData.integers[0].key);
} }
shfree(__runtimeData.integers); shfree(__runtimeData.integers);
@ -255,8 +208,6 @@ void netShutdown(void) {
packetThreadDataDestroy(&__packetThreadData); packetThreadDataDestroy(&__packetThreadData);
} }
_netRunning = 0;
} }
@ -264,131 +215,59 @@ void netStartup(void) {
FILE *cache = NULL; FILE *cache = NULL;
char *line = NULL; char *line = NULL;
char *p = NULL; char *p = NULL;
char *temp = NULL;
_netStarted = 1; if (!_netStarted) {
_netStarted = 1;
__packetThreadData = packetThreadDataCreate(NULL); __packetThreadData = packetThreadDataCreate(NULL);
packetSenderRegister(comPacketSender); packetSenderRegister(comPacketSender);
__runtimeData.integers = NULL; __runtimeData.integers = NULL;
__runtimeData.strings = NULL; __runtimeData.strings = NULL;
__runtimeData.protocolVersion = 0; __runtimeData.protocolVersion = 0;
sh_new_strdup(__runtimeData.integers); sh_new_strdup(__runtimeData.integers);
sh_new_strdup(__runtimeData.strings); sh_new_strdup(__runtimeData.strings);
// ***TODO*** Default initial tables // ***TODO*** Default initial tables
line = (char *)malloc(4096); line = (char *)malloc(4096);
if (line) { if (line) {
// Load string cache. // Load string cache.
cache = fopen("cache/string.dat", "rt"); cache = fopen("cache/string.dat", "rt");
if (cache) { if (cache) {
while (fscanf(cache, "%s\n", line) != EOF) { while (fscanf(cache, "%s\n", line) != EOF) {
p = strstr(line, "="); p = strstr(line, "=");
if (p) { if (p) {
*p = 0; *p = 0;
p++; p++;
shput(__runtimeData.strings, line, strdup(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");
// Load integer cache. if (cache) {
cache = fopen("cache/integer.dat", "rt"); while (fscanf(cache, "%s\n", line) != EOF) {
if (cache) { p = strstr(line, "=");
while (fscanf(cache, "%s\n", line) != EOF) { if (p) {
p = strstr(line, "="); *p = 0;
if (p) { p++;
*p = 0; shput(__runtimeData.integers, line, atol(p));
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);
} }

View file

@ -25,23 +25,18 @@
#include "os.h" #include "os.h"
#define NETWORK_CONNECT_SUCCESS 0 typedef void (*netPacketHandler)(PacketDecodeDataT *packet);
#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
int8_t netConnectStep1(void); uint8_t netChannelGet(netPacketHandler handler);
int8_t netConnectStep2(void); void netChannelRelease(uint8_t channel);
void netDisconnect(void); void netChannelSystemGet(netPacketHandler handler);
uint8_t netGetChannelFree(void); void netChannelSystemRelease(netPacketHandler handler);
PacketDecodeDataT *netGetPacket(uint8_t channel); void netPacketHandlerStart(void);
void netShutdown(void); void netPacketHandlerStop(void);
void netStartup(void); void netProcess(void);
void netShutdown(void);
void taskNetwork(void *data); void netStartup(void);
#endif // NETWORK_H #endif // NETWORK_H

View file

@ -22,9 +22,7 @@
#include "welcome.h" #include "welcome.h"
#include "taglist.h" #include "taglist.h"
#include "task.h"
#include "comport.h" #include "comport.h"
#include "timer.h"
#include "config.h" #include "config.h"
#include "window.h" #include "window.h"
@ -34,6 +32,7 @@
#include "textbox.h" #include "textbox.h"
#include "updown.h" #include "updown.h"
#include "label.h" #include "label.h"
#include "timer.h"
#define GROUP_COM 1 #define GROUP_COM 1
@ -46,6 +45,14 @@
#define TITLE_LEN 80 #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 { typedef struct PortS {
uint8_t status; uint8_t status;
char title[TITLE_LEN]; char title[TITLE_LEN];
@ -55,19 +62,23 @@ typedef struct PortS {
} PortT; } PortT;
static WindowT *_winDetecting; static WindowT *_winDetecting = NULL;
static LabelT *_lblOneMoment; static LabelT *_lblOneMoment = NULL;
static WindowT *_winSettings; static WindowT *_winSettings = NULL;
static FrameT *_frmComPorts; static FrameT *_frmComPorts = NULL;
static FrameT *_frmServer; static FrameT *_frmServer = NULL;
static ButtonT *_btnOkay; static ButtonT *_btnOkay = NULL;
static TextboxT *_txtServer; static TextboxT *_txtServer = NULL;
static UpdownT *_updPort; static TimerT *_timProgress = NULL;
static PortT _port[4]; static UpdownT *_updPort = NULL;
static widgetCallback _done; static PortT _port[4] = { 0 };
static widgetCallback _done = NULL;
static SettingsStateT _state = S_START_SCAN;
static void btnOkayClick(WidgetT *widget); static void btnOkayClick(WidgetT *widget);
static void settingsComShow(void);
static void timSettingsProgress(WidgetT *widget);
static void btnOkayClick(WidgetT *widget) { static void btnOkayClick(WidgetT *widget) {
@ -95,61 +106,9 @@ static void btnOkayClick(WidgetT *widget) {
} }
int8_t settingsScanComPorts(void) { void settingsShow(void *callback) {
char buffer[1024] = { 0 };
uint8_t selected = 1;
int32_t rc = 0;
uint32_t len = 0;
int8_t lastFound = -1;
// Scan the COM ports for a compatable modem. _done = (widgetCallback)callback;
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;
TagItemT uiDetecting[] = { TagItemT uiDetecting[] = {
T_START, T_START,
@ -160,14 +119,27 @@ void taskSettings(void *data) {
T_X, 25, T_Y, 25, T_X, 25, T_Y, 25,
T_TITLE, P("One Moment Please!"), T_TITLE, P("One Moment Please!"),
T_LABEL, T_DONE, T_LABEL, T_DONE,
T_TIMER, O(_timProgress),
T_EVENT, P(timSettingsProgress),
T_VALUE, 0,
T_TIMER, T_DONE,
T_WINDOW, T_DONE, T_WINDOW, T_DONE,
T_END T_END
}; };
tagListRun(uiDetecting); // We can use a module-global variable instead of widget user data
taskYield(); // Cause dialog to paint. // 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)); guiDelete(D(_winDetecting));
@ -222,12 +194,88 @@ void taskSettings(void *data) {
} }
// Add COM discovery to GUI. // Add COM discovery to GUI.
rc = 0; y = 0;
for (len=0; len<4; len++) { 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); if (_port[len].selected) radioSelectedSet(_port[len].rdoCOM);
widgetEnableSet(W(_port[len].rdoCOM), _port[len].enabled); widgetEnableSet(W(_port[len].rdoCOM), _port[len].enabled);
guiAttach(W(_frmComPorts), W(_port[len].rdoCOM)); 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;
} }
} }

View file

@ -25,8 +25,7 @@
#include "os.h" #include "os.h"
int8_t settingsScanComPorts(void); void settingsShow(void *callback);
void taskSettings(void *data);
#endif // SETTINGS_H #endif // SETTINGS_H

View file

@ -22,34 +22,44 @@
#include "button.h" #include "button.h"
#include "label.h" #include "label.h"
#include "msgbox.h" #include "msgbox.h"
#include "timer.h"
#include "network.h" #include "network.h"
#include "runtime.h" #include "runtime.h"
#include "taglist.h" #include "taglist.h"
#include "timer.h"
#include "task.h"
#include "signup.h" #include "signup.h"
#include "login.h" #include "login.h"
static WindowT *_winSignUp = NULL; typedef enum SignUpStateE {
static LabelT *_lblRequired = NULL; S_START_SIGNUP = 0,
static TextboxT *_txtEmail = NULL; S_SIGNUP_WAIT
static TextboxT *_txtFirst = NULL; } SignUpStateT;
static TextboxT *_txtLast = NULL;
static TextboxT *_txtUser = NULL;
static TextboxT *_txtPass1 = NULL; static WindowT *_winSignUp = NULL;
static TextboxT *_txtPass2 = NULL; static LabelT *_lblRequired = NULL;
static ButtonT *_btnCancel = NULL; static TextboxT *_txtEmail = NULL;
static ButtonT *_btnSignUp = 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 btnCancelClick(WidgetT *widget);
static void btnMsgBoxContinue(MsgBoxButtonT button); static void btnMsgBoxContinue(MsgBoxButtonT button);
static void btnMsgBoxFinish(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 setButtons(uint8_t enabled);
static void taskSignUpClick(void *data); static void timSignUpProgress(WidgetT *widget);
static uint8_t validateEmail(char *email); static uint8_t validateEmail(char *email);
static uint8_t validateEmailLetter(char c); static uint8_t validateEmailLetter(char c);
static uint8_t validateName(char *username); static uint8_t validateName(char *username);
@ -61,7 +71,8 @@ static void btnCancelClick(WidgetT *widget) {
(void)widget; (void)widget;
guiDelete(D(_winSignUp)); guiDelete(D(_winSignUp));
taskCreate(taskLogin, NULL); netChannelRelease(_channel);
loginShow();
} }
@ -76,7 +87,73 @@ static void btnMsgBoxFinish(MsgBoxButtonT button) {
(void)button; (void)button;
guiDelete(D(_winSignUp)); 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 signupShow(void) {
(void)data;
TagItemT uiSignUp[] = { TagItemT uiSignUp[] = {
T_START, T_START,
@ -160,101 +235,56 @@ void taskSignUp(void *data) {
T_BUTTON, O(_btnSignUp), T_BUTTON, O(_btnSignUp),
T_TITLE, P("Sign Up"), T_TITLE, P("Sign Up"),
T_X, 291, T_Y, 270, T_X, 291, T_Y, 270,
T_CLICK, P(taskProxy), T_CLICK, P(btnSignUpClick),
T_USER_DATA, P(taskSignUpClick),
T_BUTTON, T_DONE, 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_WINDOW, T_DONE,
T_END T_END
}; };
tagListRun(uiSignUp); tagListRun(uiSignUp);
_channel = netChannelGet(packetHandler);
} }
static void taskSignUpClick(void *data) { static void timSignUpProgress(WidgetT *widget) {
PacketEncodeDataT encoded = { 0 }; PacketEncodeDataT encoded;
PacketDecodeDataT *decoded = NULL; uint16_t length;
int16_t timeout = 10; char *packetData;
uint16_t length = 0; TimerT *t = (TimerT *)widget;
char *packetData = NULL;
(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); case S_SIGNUP_WAIT:
timerStop(t);
// Validate it. ***TODO*** These messages could be a lot better. msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "No response received.", "Okay", btnMsgBoxContinue);
if (!validateEmail(textboxValueGet(_txtEmail))) { break;
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;
}
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);
} }

View file

@ -25,7 +25,7 @@
#include "os.h" #include "os.h"
void taskSignUp(void *data); void signupShow(void);
#endif // SIGNUP_H #endif // SIGNUP_H

View file

@ -17,10 +17,8 @@
* *
*/ */
#include "comport.h" #include "comport.h"
#include "timer.h" #include "timer.h"
#include "task.h"
#include "config.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; TASKBEGIN(comWaitWithTimeout)
int quarterTicks = 0; int32_t r;
int count = 0; uint32_t quarterTicks;
int bufferIndex = 0; int32_t count;
char data[2]; int32_t bufferIndex;
char incoming[2];
ComWaitWithTimeoutT *args;
// Returns number of bytes read into buffer. taskCode({
// Value is positive if "expect" was found. // Returns number of bytes read into buffer.
// Value is negative if not found. // Value is positive if "expect" was found.
// Value is negative if not found.
while (quarterTicks <= quarterSeconds) { logWrite("Entering comWaitWithTimeout\n");
r = comRead(com, data, 1);
if (r == 1) { self->args = (ComWaitWithTimeoutT *)data;
buffer[bufferIndex++] = data[0];
buffer[bufferIndex] = 0; while (self->quarterTicks <= self->args->quarterSeconds) {
if (data[0] == expecting[count]) {
count++; // logWrite("Calling comRead\n");
if (count == (int)strlen(expecting)) { self->r = comRead(self->args->com, self->incoming, 1);
// Found our expect. // 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; break;
} }
} else {
count = 0;
} }
if (bufferIndex == len - 1) {
// Out of buffer. // logWrite("Yielding from comWaitWithTimeout\n");
break;
}
} else {
taskYield(); taskYield();
if (__timerQuarterSecondTick) quarterTicks++; // logWrite("Back in comWaitWithTimeout\n");
if (__timerQuarterSecondTick) {
self->quarterTicks++;
logWrite("Tick\n");
}
} }
}
if (count == (int)strlen(expecting)) { logWrite("Exiting comWaitWithTimeout\n");
return bufferIndex;
}
return -bufferIndex; if (self->count == (int)strlen(self->args->expecting)) {
} self->args->result = self->bufferIndex;
}
self->args->result = -self->bufferIndex;
});
TASKEND
*/

View file

@ -26,6 +26,16 @@
#include "packet.h" #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__ #ifdef __linux__
#define SER_SUCCESS 0 #define SER_SUCCESS 0
@ -35,7 +45,6 @@
#define SER_HANDSHAKING_RTSCTS 2 #define SER_HANDSHAKING_RTSCTS 2
int comClose(int com); int comClose(int com);
int comOpen(int com, long bps, int dataBits, char parity, int stopBits, int handshaking); int comOpen(int com, long bps, int dataBits, char parity, int stopBits, int handshaking);
int comRead(int com, char *data, int len); 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); void comPacketSender(char *data, uint32_t length, void *userData);
int comReceiveBufferFlush(int com); int comReceiveBufferFlush(int com);
int comWaitWithTimeout(int com, char *buffer, int len, int quarterSeconds, char *expecting);
#endif // COMPORT_H #endif // COMPORT_H

View file

@ -21,6 +21,16 @@
#include "os.h" #include "os.h"
uint8_t osFileExists(char *filename) {
FILE *f = fopen(filename, "rb");
if (f) {
fclose(f);
return 1;
}
return 0;
}
void osShutdown(void) { void osShutdown(void) {
#ifdef __linux__ #ifdef __linux__
linuxOsShutdown(); linuxOsShutdown();

View file

@ -27,6 +27,7 @@
// Common platform includes. // Common platform includes.
#include <math.h> #include <math.h>
#include <time.h>
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
@ -37,12 +38,17 @@
#include <sys/stat.h> #include <sys/stat.h>
#define SECONDS_IN_DAY 86400
#define TICKS_PER_SECOND 18.2
#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
#ifdef __linux__ #ifdef __linux__
#define BITS64 #define BITS64
// Linux DOS replacements. // Linux DOS replacements.
long biostime(int cmd, long newtime); uint32_t rawclock(void);
// Linux support functions. // Linux support functions.
void linuxOsShutdown(void); void linuxOsShutdown(void);
@ -75,8 +81,8 @@ void linuxOsStartup(void);
// Allocation helpers. // Allocation helpers.
#define NEW(t,v) (v)=(t*)malloc(sizeof(t)) #define NEW(t,v) (v)=(t*)calloc(1, sizeof(t))
#define DEL(v) {free(v); v=NULL;} #define DEL(v) { if (v) { free(v); v = NULL; } }
#define SUCCESS 1 #define SUCCESS 1
#define FAIL 0 #define FAIL 0
@ -93,8 +99,9 @@ typedef struct PacketThreadDataS PacketThreadDataT;
extern PacketThreadDataT *__packetThreadData; // Declared in main.c extern PacketThreadDataT *__packetThreadData; // Declared in main.c
void osShutdown(void); uint8_t osFileExists(char *filename);
void osStartup(void); void osShutdown(void);
void osStartup(void);
#endif // OS_H #endif // OS_H

View file

@ -32,6 +32,7 @@
#include "radio.h" #include "radio.h"
#include "terminal.h" #include "terminal.h"
#include "textbox.h" #include "textbox.h"
#include "timer.h"
#include "updown.h" #include "updown.h"
#include "window.h" #include "window.h"
@ -166,6 +167,7 @@ static void tagListWidgetAttributeHandle(void) {
break; break;
case T_CLICK: case T_CLICK:
case T_EVENT:
click = (widgetCallback)v; click = (widgetCallback)v;
break; break;
@ -331,6 +333,13 @@ static void tagListWidgetAttributeHandle(void) {
textboxPasswordCharacterSet((TextboxT *)widget, mask); textboxPasswordCharacterSet((TextboxT *)widget, mask);
break; break;
case T_TIMER:
if (hasValue && click) {
widget = W(timerNew(click, (uint32_t)valueInt));
if (!enabled) timerStop((TimerT *)widget);
}
break;
case T_UPDOWN: case T_UPDOWN:
widget = W(updownNew(pos.x, pos.y, minimum, maximum, step, title)); widget = W(updownNew(pos.x, pos.y, minimum, maximum, step, title));
if (hasValue) updownValueSet((UpdownT *)widget, valueInt); if (hasValue) updownValueSet((UpdownT *)widget, valueInt);

View file

@ -54,6 +54,7 @@ enum TagItemsE {
T_RADIOBUTTON, T_RADIOBUTTON,
T_TERMINAL, T_TERMINAL,
T_TEXTBOX, T_TEXTBOX,
T_TIMER,
T_UPDOWN, T_UPDOWN,
T_WINDOW, T_WINDOW,
@ -65,6 +66,7 @@ enum TagItemsE {
T_COLOR_BACKGROUND, T_COLOR_BACKGROUND,
T_COLOR_FOREGROUND, T_COLOR_FOREGROUND,
T_ENABLED, T_ENABLED,
T_EVENT,
T_FILENAME, T_FILENAME,
T_GROUP, T_GROUP,
T_HEIGHT, T_HEIGHT,

View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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());
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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();
}
}

View file

@ -23,35 +23,62 @@
#include "login.h" #include "login.h"
#include "taglist.h" #include "taglist.h"
#include "task.h"
#include "config.h" #include "config.h"
#include "comport.h" #include "comport.h"
#include "timer.h"
#include "network.h" #include "network.h"
#include "runtime.h"
#include "window.h" #include "window.h"
#include "picture.h" #include "picture.h"
#include "button.h" #include "button.h"
#include "msgbox.h" #include "msgbox.h"
#include "timer.h"
static WindowT *_winWelcome = NULL; typedef enum WelcomeStateE {
static PictureT *_picLogo = NULL; S_START_CONNECT = 0,
static PictureT *_picInit = NULL; S_START_INIT_MODEM,
static PictureT *_picDialing = NULL; S_INIT_MODEM,
static PictureT *_picConnect = NULL; S_INIT_RESULT,
static ButtonT *_btnQuit = NULL; S_DIAL,
static ButtonT *_btnSettings = NULL; S_WAIT_FOR_BANNER,
static ButtonT *_btnConnect = NULL; 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 btnMsgBox(MsgBoxButtonT button);
static void btnMsgBoxQuit(MsgBoxButtonT button); static void btnMsgBoxQuit(MsgBoxButtonT button);
static void btnQuitClick(WidgetT *widget); static void btnQuitClick(WidgetT *widget);
static void btnSettingsClick(WidgetT *widget); static void btnSettingsClick(WidgetT *widget);
static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled); static void setButtons(uint8_t enabled);
static void settingsFinished(WidgetT *widget); 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) { static void btnMsgBox(MsgBoxButtonT button) {
@ -79,6 +106,7 @@ static void btnMsgBoxQuit(MsgBoxButtonT button) {
static void btnQuitClick(WidgetT *widget) { static void btnQuitClick(WidgetT *widget) {
(void)widget; (void)widget;
setButtons(0); setButtons(0);
msgBoxTwo("Quit?", MSGBOX_ICON_QUESTION, "Exit to DOS?", "Okay", btnMsgBoxQuit, "Cancel", btnMsgBoxQuit); 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) { static void btnSettingsClick(WidgetT *widget) {
(void)widget; (void)widget;
setButtons(0); 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 welcomeShow(void) {
(void)data;
// 450x128 logo // 450x128 logo
@ -150,10 +237,14 @@ void taskWelcome(void *data) {
T_BUTTON, O(_btnConnect), T_BUTTON, O(_btnConnect),
T_TITLE, P("Connect"), T_TITLE, P("Connect"),
T_X, 379, T_Y, 157, T_X, 379, T_Y, 157,
T_CLICK, P(taskProxy), T_CLICK, P(btnConnectClick),
T_USER_DATA, P(taskConnectClick),
T_ENABLED, (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? T_TRUE : T_FALSE, T_ENABLED, (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? T_TRUE : T_FALSE,
T_BUTTON, T_DONE, 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_WINDOW, T_DONE,
T_END T_END
@ -163,59 +254,128 @@ void taskWelcome(void *data) {
} }
static void taskConnectClick(void *data) { static void timWelcomeProgress(WidgetT *widget) {
int32_t r = 0; TimerT *t = (TimerT *)widget;
int16_t timeout = 0; 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. case S_START_INIT_MODEM:
widgetEnableSet(W(_btnConnect), 0); // Open COM port.
widgetEnableSet(W(_btnSettings), 0); r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
widgetEnableSet(W(_btnQuit), 0); 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. case S_INIT_MODEM:
widgetVisibleSet(W(_picLogo), 0); // Just read anything to clear the buffer.
widgetVisibleSet(W(_picInit), 1); len = comRead(__configData.serialCom - 1, buffer, 1023);
taskYield(); // 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(); case S_INIT_RESULT:
if (r == NETWORK_CONNECT_OPEN_FAILED) { len = comRead(__configData.serialCom - 1, buffer, 1023);
msgBoxOne("COM Problem", MSGBOX_ICON_ERROR, "Unable to open COM port!\nPlease check settings.", "Okay", btnMsgBox); buffer[len] = 0;
return; 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);
} }

View file

@ -25,7 +25,7 @@
#include "os.h" #include "os.h"
void taskWelcome(void *data); void welcomeShow(void);
#endif // WELCOME_H #endif // WELCOME_H

View file

@ -1,4 +1,4 @@
Title: Chat Title: Discord
---- ----

View file

@ -0,0 +1,5 @@
Title: Matrix
----
Redirect: https://matrix.to/#/#DosGame:matrix.kangaroopunch.com

View file

@ -0,0 +1 @@
Title: Chat

View file

@ -57,6 +57,7 @@ function kpApiUserLogin($username, $pass, &$response) {
// Find user by name instead of email. // Find user by name instead of email.
$user = kirby()->users()->filterBy('name', $username)->first(); $user = kirby()->users()->filterBy('name', $username)->first();
if ($user) { if ($user) {
// ***TODO*** Must be activated!
// Attempt to sign them in. // Attempt to sign them in.
kirby()->auth()->login($user->email(), $pass); kirby()->auth()->login($user->email(), $pass);
// They don't need an actual Kirby session, so log them off. // They don't need an actual Kirby session, so log them off.

View file

@ -23,6 +23,11 @@ return [
switch (get('command')) { switch (get('command')) {
case 'API_AVAILABLE':
$response['result'] = 'true';
$response['reason'] = 'API Available.';
break;
case 'API_TEST': case 'API_TEST':
kpApiTest($response); kpApiTest($response);
break; break;

View file

@ -12,8 +12,8 @@
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"><?= $item->title() ?></a> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"><?= $item->title() ?></a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown"> <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<?php foreach($item->children()->listed()->flip() as $child): ?> <?php foreach($item->children()->listed() as $child): ?>
<li><a class="dropdown-item" href="<?= $child->url() ?>"><?= $child->year() ?> - <?= $child->title() ?></a></li> <li><a class="dropdown-item" href="<?= $child->url() ?>"><?= $child->title() ?></a></li>
<?php endforeach ?> <?php endforeach ?>
</ul> </ul>
</li> </li>

View file

@ -0,0 +1,5 @@
<html>
<head>
<meta http-equiv="refresh" content="0; url=/" />
</head>
</html>

View file

@ -37,17 +37,10 @@ typedef void (*clientApi)(ClientThreadT *client, PacketDecodeDataT *data);
// Also update enum in packets.h! // Also update enum in packets.h!
clientApi clientApiMethod[PACKET_END_OF_SERVER_PACKETS - PACKET_END_OF_DUAL_PACKETS] = { static clientApi _clientApiMethod[PACKET_TYPE_COUNT];
clientApiClientShutdown,
clientApiLogin,
clientApiPong,
clientApiSignup,
clientApiVersionBad,
clientApiVersionOkay
};
static uint8_t clientDequeuePacket(ClientThreadT *client); 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. // New data or not, process anything in the queue.
if (packetDecode(client->packetThreadData, &decode, data, length)) { if (packetDecode(client->packetThreadData, &decode, data, length)) {
if ((decode.packetType > PACKET_END_OF_DUAL_PACKETS) && (decode.packetType < PACKET_END_OF_SERVER_PACKETS)) { if (_clientApiMethod[decode.packetType]) {
clientApiMethod[decode.packetType - (PACKET_END_OF_DUAL_PACKETS + 1)](client, &decode); _clientApiMethod[decode.packetType](client, &decode);
} else { } else {
consoleMessageQueue("%ld: Channel %d Unknown Packet %d\n", client->threadIndex, decode.channel, decode.packetType); 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) { void *clientThread(void *data) {
ENetPeer *peer = (ENetPeer *)data; ENetPeer *peer = (ENetPeer *)data;
@ -134,6 +144,7 @@ void *clientThread(void *data) {
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
DEL(packetData); DEL(packetData);
versionSent = 1; versionSent = 1;
consoleMessageQueue("PACKET_TYPE_VERSION sent.\n");
} }
} }

View file

@ -53,6 +53,8 @@ typedef struct ClientThreadS {
void clientQueuePacket(ClientThreadT *client, uint8_t *data, uint32_t length); void clientQueuePacket(ClientThreadT *client, uint8_t *data, uint32_t length);
void clientShutdown(void);
void clientStartup(void);
void *clientThread(void *data); void *clientThread(void *data);

View file

@ -56,7 +56,7 @@ void clientApiLogin(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet. // Build packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_LOGIN_RESULT; encoded.packetType = PACKET_TYPE_LOGIN_RESULT;
encoded.channel = 0; encoded.channel = data->channel;
encoded.encrypt = 0; encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, packetData, length); packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it. // Send it.

View file

@ -59,7 +59,7 @@ void clientApiSignup(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet. // Build packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_SIGNUP_RESULT; encoded.packetType = PACKET_TYPE_SIGNUP_RESULT;
encoded.channel = 0; encoded.channel = data->channel;
encoded.encrypt = 0; encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, packetData, length); packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it. // Send it.

View file

@ -72,12 +72,13 @@ void clientApiVersionOkay(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet. // Build packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_STRING; encoded.packetType = PACKET_TYPE_STRING;
encoded.channel = 0; encoded.channel = data->channel;
encoded.encrypt = 0; encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, buffer, length); packetEncode(client->packetThreadData, &encoded, buffer, length);
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
DEL(buffer); DEL(buffer);
consoleMessageQueue("PACKET_TYPE_STRING [%s] sent.\n", strings[i].key);
} }
restHelperConfigStringMapRelease(strings); restHelperConfigStringMapRelease(strings);
@ -111,22 +112,23 @@ void clientApiVersionOkay(ClientThreadT *client, PacketDecodeDataT *data) {
// Build packet. // Build packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_NUMBER; encoded.packetType = PACKET_TYPE_NUMBER;
encoded.channel = 0; encoded.channel = data->channel;
encoded.encrypt = 0; encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, buffer, length); packetEncode(client->packetThreadData, &encoded, buffer, length);
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
DEL(buffer); DEL(buffer);
consoleMessageQueue("PACKET_TYPE_NUMBER [%s] sent.\n", integers[i].key);
} }
restHelperConfigIntegerMapRelease(integers); restHelperConfigIntegerMapRelease(integers);
// Build PROCEED packet. // Build PROCEED packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_PROCEED; encoded.packetType = PACKET_TYPE_PROCEED;
encoded.channel = 0; encoded.channel = data->channel;
encoded.encrypt = 0; encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, NULL, 0); packetEncode(client->packetThreadData, &encoded, NULL, 0);
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
consoleMessageQueue("PACKET_TYPE_PROCEED sent.\n");
} }

View file

@ -109,6 +109,7 @@ int main(int argc, char *argv[]) {
settingsClientVersion = restHelperConfigIntegerGet(response, "clientVersion", 1); settingsClientVersion = restHelperConfigIntegerGet(response, "clientVersion", 1);
restRelease(response); restRelease(response);
clientStartup();
serverStartup(settingsPortNumber, settingsMaxClients); serverStartup(settingsPortNumber, settingsMaxClients);
logWrite("Server online.\n"); logWrite("Server online.\n");
@ -121,6 +122,7 @@ int main(int argc, char *argv[]) {
// Wait for all running threads to shut down. // Wait for all running threads to shut down.
logWrite("Shutting down.\n"); logWrite("Shutting down.\n");
serverShutdown(); serverShutdown();
clientShutdown();
// Shut down. // Shut down.
restShutdown(); restShutdown();

View file

@ -275,7 +275,8 @@ void restShutdown(void) {
uint8_t restStartup(char *url, char *user, char *password) { uint8_t restStartup(char *url, char *user, char *password) {
uint64_t i; uint64_t i;
json_object *response;
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
@ -299,6 +300,11 @@ uint8_t restStartup(char *url, char *user, char *password) {
_restUser = strdup(user); _restUser = strdup(user);
_restPass = strdup(password); _restPass = strdup(password);
// Is the remote server there?
response = restRequest("API_AVAILABLE", NULL);
if (!response) return FAIL;
restRelease(response);
return SUCCESS; return SUCCESS;
} }

View file

@ -134,8 +134,9 @@ void *serverThread(void *data) {
// Tell the console. // Tell the console.
enet_address_get_host_ip(&event.peer->address, buffer, 2047); enet_address_get_host_ip(&event.peer->address, buffer, 2047);
consoleMessageQueue("%ld: [%s] connected.\n", client->threadIndex, buffer); consoleMessageQueue("%ld: [%s] connected.\n", client->threadIndex, buffer);
// ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
// Send banner to client. // 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); enet_peer_send(event.peer, 0, packet);
break; break;

View file

@ -78,11 +78,11 @@ void logWrite(char *format, ...) {
vsnprintf(_logBuffer, _logBufferSize, format, args2); vsnprintf(_logBuffer, _logBufferSize, format, args2);
} }
#ifdef __linux__ //#ifdef __linux__
// Also output to stdout on Linux. // Also output to stdout on Linux.
fprintf(stdout, "%s", _logBuffer); fprintf(stdout, "%s", _logBuffer);
fflush(stdout); fflush(stdout);
#endif //#endif
if (_logCallback) _logCallback(_logBuffer); if (_logCallback) _logCallback(_logBuffer);

View file

@ -78,7 +78,6 @@ char *packetContentPack(uint16_t *length, char *format, ...) {
static char work[PACKET_MAX] = { 0 }; static char work[PACKET_MAX] = { 0 };
char *result = NULL; char *result = NULL;
char *buffer = NULL; char *buffer = NULL;
int8_t value8 = 0;
int32_t value32 = 0; int32_t value32 = 0;
*length = 0; *length = 0;
@ -123,7 +122,6 @@ char *packetContentPack(uint16_t *length, char *format, ...) {
void packetContentUnpack(char *buffer, char *format, ...) { void packetContentUnpack(char *buffer, char *format, ...) {
va_list args = { 0 }; va_list args = { 0 };
char **string = NULL; char **string = NULL;
int8_t *value8 = NULL;
int32_t *value32 = NULL; int32_t *value32 = NULL;
uint16_t length = 0; uint16_t length = 0;

View file

@ -31,22 +31,19 @@
// This enum is treated as BYTES in the code. Do not go over 255 entries. // This enum is treated as BYTES in the code. Do not go over 255 entries.
// Also update array in client.c! // Also update array in client.c!
typedef enum PacketTypeE { 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_NONE = 0, // No packet.
PACKET_TYPE_DH_REQUEST, PACKET_TYPE_DH_REQUEST,
PACKET_TYPE_DH_RESPONSE, PACKET_TYPE_DH_RESPONSE,
PACKET_TYPE_VERSION,
PACKET_END_OF_DUAL_PACKETS, PACKET_TYPE_VERSION_BAD,
PACKET_TYPE_VERSION_OKAY,
// Packets received by only the server: // Packets received by only the server:
PACKET_TYPE_CLIENT_SHUTDOWN, PACKET_TYPE_CLIENT_SHUTDOWN,
PACKET_TYPE_LOGIN, PACKET_TYPE_LOGIN,
PACKET_TYPE_PONG, PACKET_TYPE_PONG,
PACKET_TYPE_SIGNUP, PACKET_TYPE_SIGNUP,
PACKET_TYPE_VERSION_BAD,
PACKET_TYPE_VERSION_OKAY,
PACKET_END_OF_SERVER_PACKETS,
// Packets received by only the client: // Packets received by only the client:
PACKET_TYPE_LOGIN_RESULT, PACKET_TYPE_LOGIN_RESULT,
@ -56,7 +53,6 @@ typedef enum PacketTypeE {
PACKET_TYPE_SERVER_SHUTDOWN, PACKET_TYPE_SERVER_SHUTDOWN,
PACKET_TYPE_SIGNUP_RESULT, PACKET_TYPE_SIGNUP_RESULT,
PACKET_TYPE_STRING, PACKET_TYPE_STRING,
PACKET_TYPE_VERSION,
// How many packet types do we recognize? // How many packet types do we recognize?
PACKET_TYPE_COUNT PACKET_TYPE_COUNT

View file

@ -1,2 +1,4 @@
#!/bin/bash #!/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 &