Skip to content

Instantly share code, notes, and snippets.

@MRtecno98
Created November 12, 2021 20:45
Show Gist options
  • Save MRtecno98/6f7b8e80c335ba5f9ac8169932ddbead to your computer and use it in GitHub Desktop.
Save MRtecno98/6f7b8e80c335ba5f9ac8169932ddbead to your computer and use it in GitHub Desktop.
Arduino serial panel
#ifndef LCDMENU
#define LCDMENU
void setCursor(int, int);
void incrementSelected();
void decrementSelected();
void print_options(boolean);
void print_options(boolean, int);
void print_options_fullscreen();
void allocate_options();
int *options;
int options_n = 0;
int selected_option = 0;
void (*active_handler)(boolean, boolean, boolean, boolean);
void nothing_handler(boolean, boolean, boolean, boolean);
int cursor_column = 0;
int cursor_line = 0;
void nothing_handler(boolean up, boolean down, boolean back, boolean enter) {}
void print_options_fullscreen() {
lcd.clear();
setCursor(0, 0);
print_options(true, (selected_option % 2) == 0 ? selected_option : selected_option - 1);
}
void print_options(boolean double_l) {
print_options(double_l, 0);
}
void setCursor(int col, int line) {
cursor_column = col;
cursor_line = line;
lcd.setCursor(col, line);
}
void incrementSelected() {
selected_option = selected_option == options_n-1 ? selected_option : selected_option+1;
}
void decrementSelected() {
selected_option = selected_option == 0 ? selected_option : selected_option-1;
}
void print_options(boolean double_l, int offset) {
for(int i = offset; i < (double_l ? offset+2 : offset+1); i++) {
lcd.print((selected_option == i ? "> " : ""));
int index = (options)[i];
lcd.print(strings[index]);
setCursor(0, cursor_line == 0 ? 1 : 0);
}
}
void allocate_options() {
free(options);
options = malloc(sizeof(int *) * options_n);
}
#endif
#ifndef MENUS
#define MENUS
#include <errno.h>
#include <MemoryFree.h>
#include "framework.h"
void main_menu();
void main_menu_handler(boolean, boolean, boolean, boolean);
void actions_menu();
void actions_menu_handler(boolean, boolean, boolean, boolean);
void serial_screen(String, void(*)(void));
void comingsoon_menu();
void comingsoon_menu_handler(boolean, boolean, boolean, boolean);
void stats_menu();
void print_stats();
void stats_menu_handler(boolean, boolean, boolean, boolean);
void errno_menu();
void restart_menu();
void message_menu(String, String);
void message_menu(String, String, int);
void main_menu() {
active_handler = &main_menu_handler;
options_n = 1;
selected_option = 0;
allocate_options();
options[0] = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Servers CPanel");
setCursor(0, 1);
print_options(false);
}
void main_menu_handler(boolean down, boolean up, boolean back, boolean enter) {
if(enter) actions_menu();
}
void actions_menu() {
active_handler = &actions_menu_handler;
options_n = 4;
selected_option = 0;
allocate_options();
options[0] = 1;
options[1] = 2;
options[2] = 3;
options[3] = 4;
lcd.clear();
setCursor(0, 0);
print_options(true);
}
void actions_menu_handler(boolean down, boolean up, boolean back, boolean enter) {
if(back) main_menu();
if(down) incrementSelected();
if(up) decrementSelected();
if(down || up) print_options_fullscreen();
if(enter) {
switch(selected_option) {
case 0 :
serial_screen("Serial message", &actions_menu);
break;
case 1 :
errno = 1;
break;
case 2 :
restart_menu();
break;
case 3 :
stats_menu();
break;
default :
comingsoon_menu();
}
}
}
void errno_menu() {
active_handler = &nothing_handler;
options_n = 0;
selected_option = 0;
allocate_options();
lcd.clear();
setCursor(0, 1);
lcd.print("RESTARTING SYS.");
boolean active = false;
for(int i = 0; i < 10; i++) {
active = !active;
setCursor(0, 0);
lcd.print(active ? "ERROR DETECTED"
: " ");
digitalWrite(13, active ? HIGH : LOW);
delay(500);
}
lcd.clear();
restart();
}
#define STATS_UPDATE 1000
void stats_menu() {
active_handler = &stats_menu_handler;
options_n = 0;
selected_option = 0;
allocate_options();
print_stats();
}
void print_stats() {
int freemem = freeMemory();
int usedmem = MAX_MEM - freemem;
lcd.clear();
setCursor(0, 0);
lcd.print("Free mem: ");
lcd.print(freemem);
setCursor(0, 1);
lcd.print("Used mem: ");
lcd.print(usedmem);
}
int last_millis;
void stats_menu_handler(boolean down, boolean up, boolean back, boolean enter) {
if(millis() - last_millis >= STATS_UPDATE) {
print_stats();
last_millis = millis();
}
if(back) actions_menu();
}
void restart_menu() {
message_menu("Restarting", "system...");
restart();
}
void message_menu(String linea, String lineb, int fading) {
active_handler = &nothing_handler;
options_n = 0;
selected_option = 0;
allocate_options();
lcd.clear();
setCursor(0, 0);
lcd.print(linea);
setCursor(0, 1);
lcd.print(lineb);
delay(fading);
}
void message_menu(String linea, String lineb) {
message_menu(linea, lineb, 0);
}
void serial_screen(String tosend, void (*prev_menu)(void)) {
active_handler = &nothing_handler;
options_n = 0;
selected_option = 0;
allocate_options();
lcd.clear();
setCursor(0, 0);
lcd.print("Sending");
for(int i = 0; i < 3; i++) {
delay(500);
lcd.print(".");
}
proxy->send_packet(new PrintPacket(tosend));
setCursor(0, 1);
lcd.print("Done");
delay(1000);
(*prev_menu)();
}
void comingsoon_menu() {
active_handler = &comingsoon_menu_handler;
options_n = 1;
selected_option = 0;
allocate_options();
options[0] = 5;
lcd.clear();
setCursor(0, 0);
lcd.print("Coming soon...");
setCursor(0, 1);
print_options(false);
}
void comingsoon_menu_handler(boolean down, boolean up, boolean back, boolean enter) {
if(enter) main_menu();
if(back) actions_menu();
}
#endif
#ifndef PACKETS
#define PACKETS
class Packet {
public:
virtual byte Packet::getIdentifier() = 0;
virtual const byte* Packet::getPayload() = 0;
virtual int Packet::getPayloadSize() = 0;
};
class BasePacket : public Packet {
protected:
byte identifier;
int packetsize;
byte* payload;
public:
BasePacket(byte, int, const byte*);
~BasePacket();
byte getIdentifier();
const byte* getPayload();
int getPayloadSize();
};
BasePacket::BasePacket(byte identifier, int payloadsize, const byte* payload) {
this->identifier = identifier;
this->packetsize = payloadsize;
this->payload = payload;
}
byte BasePacket::getIdentifier() {
return this->identifier;
}
int BasePacket::getPayloadSize() {
return this->packetsize;
}
const byte* BasePacket::getPayload() {
return this->payload;
}
BasePacket::~BasePacket() {
delete (*this).payload;
}
class PrintPacket : public BasePacket {
public:
PrintPacket(String message);
private:
String message;
static int getPacketSizeFor(String);
static byte* constructPacket(String);
};
PrintPacket::PrintPacket(String message) : BasePacket(PRINT_PACKET, PrintPacket::getPacketSizeFor(message), PrintPacket::constructPacket(message)) {
this->message = message;
}
static int PrintPacket::getPacketSizeFor(String s) {
return s.length() + 1;
}
static byte* PrintPacket::constructPacket(String s) {
int payloadsize = PrintPacket::getPacketSizeFor(s);
byte* payload = new byte[payloadsize];
payload[0] = s.length();
for(int i = 0; i < s.length(); i++) payload[i+1] = s[i];
return payload;
}
class RestartPacket : public BasePacket {
public:
RestartPacket() : BasePacket(RESTART_PACKET, 0, NULL) {}
};
class ServerListPacket : public BasePacket {
public:
ServerListPacket() : BasePacket(LIST_PACKET, 0, NULL) {}
};
#endif
#include <LiquidCrystal.h>
#include <errno.h>
#include <avr/wdt.h>
#define awr_reset() wdt_enable(WDTO_30MS); wdt_reset()
#define MAX_MEM 2048
void restart();
String strings[] = {
"View actions",
"Send serial",
"Emulate Error",
"Restart System",
"System stats",
"Main menu",
};
#include "protocol.h"
Proxy* proxy;
LiquidCrystal lcd(2, 3, 4, //Reg.Sel., R/W, E
5, 6, 7, 8, //D0-D3
9, 10, 11, 12); //D4-D7
#include "lcdmenu.h"
#define BUTTONS_N 4
boolean precedent_pulsant[] = {false, false, false, false};
int buttons[] = {A5, A4, A3, A2};
void setup() {
lcd.begin(16, 2);
Serial.begin(9600);
pinMode(13, OUTPUT);
for(int i = 0; i < BUTTONS_N; i++) pinMode(buttons[i], INPUT);
proxy = new Proxy();
if(!proxy->establish_connection()) {
message_menu("Waiting for", "connection...");
proxy->start_connection();
}
message_menu("Connection", "established", 1500);
main_menu();
}
void loop() {
if(errno) errno_menu();
tickHandlers();
delay(100);
}
void restart() {
proxy->send_packet(new RestartPacket());
awr_reset();
}
void tickHandlers() {
boolean states[] = {false, false, false, false};
for(int i = 0; i < BUTTONS_N; i++) {
bool actual_state = digitalRead(buttons[i]);
if(actual_state != precedent_pulsant[i]) {
states[i] = actual_state;
precedent_pulsant[i] = actual_state;
}else states[i] = false;
}
(*active_handler)(states[0], states[1], states[2], states[3]);
}
import serial, traceback, sys
ENABLE_BYTE = b'\xab'
START_BYTE = b'\xff'
class Processor() :
def restart(self) :
pass
def is_processable(self, identifier) :
return True
def process(self, controller) :
pass
class PrintProcessor(Processor) :
def is_processable(self, identifier) :
return identifier == b'\x00'
def process(self, controller) :
size = int.from_bytes(controller._ser.read(1), 'little')
text = controller._ser.read(size)
print("[PrintPacket] " + text.decode())
class RestartProcessor(Processor) :
def is_processable(self, identifier) :
return identifier == b'\xfe'
def process(self, controller) :
print("Received connection restart request")
controller.restart_connection()
print("Connection restarted")
class Controller() :
def __start_connection(self) :
self._ser = serial.Serial(self.port, 9600)
while not self._ser.in_waiting :
pass
assert self._ser.read(1) == START_BYTE
self._ser.write(ENABLE_BYTE)
assert self._ser.read(1) == ENABLE_BYTE
def __init__(self, port, *processors) :
self.port = port
self.processors = []
self.add_processors(*processors)
self.__start_connection()
def add_processors(self, *processors) :
self.processors += [proc if isinstance(proc, Processor) else \
proc() if issubclass(proc, Processor) else None \
for proc in processors]
self.processors = [p for p in self.processors if p != None]
def select_processors(self, identifier) :
return [proc.process(self) for proc in self.processors \
if proc.is_processable(identifier)]
def restart_connection(self) :
self.close()
self.__start_connection()
def stop_loop(self) :
self.ongoing = False
def main_loop(self) :
self.ongoing = True
while self.ongoing :
if self._ser.in_waiting :
# print(self._ser.read(self._ser.in_waiting))
identifier = self._ser.read(1)
self.select_processors(identifier)
def close(self) :
self._ser.close()
def __del__(self) :
self.close()
def main() :
port = input("Select port(Default: COM4): ")
port = port if port else "COM4"
contr = Controller(port, PrintProcessor, RestartProcessor)
print("Connection establised")
while True :
try :
contr.main_loop()
except KeyboardInterrupt :
act = input("Try to reconnect or close server?(r/c): ").lower().strip()
if act == "r" :
contr.restart_connection()
print("Connection restarted")
continue
elif act == "c" :
contr.ongoing = False
break
except Exception as e:
raise Exception("Error while processing packet") from e
break
if __name__ == "__main__" :
main()
#ifndef PROCESSORS
#define PROCESSORS
#include "protocol.h"
#include "packets.h"
class Response {
protected:
Response();
};
class Processor {
public:
virtual boolean is_processable(byte identifier) = 0;
virtual Response* process(Proxy* proxy) = 0;
};
class ServerListProcessor : public Processor {
public:
boolean is_processable(byte identifier);
Response* process(Proxy* proxy);
class ServerListResponse : public Response {
private:
String* servers;
int len;
public:
ServerListResponse(const String*, int);
~ServerListResponse();
String* getServerList();
int getServersCount();
};
};
boolean ServerListProcessor::is_processable(byte identifier) {
return identifier == LIST_PACKET;
}
Response* ServerListProcessor::process(Proxy* proxy) {
byte servlen = Serial.read();
String* names = new String[servlen];
for(int i = 0; i < servlen; i++) {
byte strlength = Serial.read();
char* str = new char[strlength];
for(int j = 0; j < strlength; j++) {
str[j] = Serial.read();
}
String s(str);
names[i] = s;
}
ServerListProcessor::ServerListResponse response(names, servlen);
return &response;
}
ServerListProcessor::ServerListResponse::ServerListResponse(const String* servers, int len) {
this->servers = servers;
this->len = len;
}
ServerListProcessor::ServerListResponse::~ServerListResponse() {
delete this->servers;
}
String* ServerListProcessor::ServerListResponse::getServerList() {
return this->servers;
}
int ServerListProcessor::ServerListResponse::getServersCount() {
return this->len;
}
#endif
#ifndef PROTOCOL
#define PROTOCOL
#define START_PACKET 0xff
#define ENABLE_PACKET 0xab
#define RESTART_PACKET 0xfe
#define PRINT_PACKET 0x00
#define LIST_PACKET 0x01
#include <HardwareSerial.h>
#include "packets.h"
class Proxy {
public:
Proxy::start_connection();
Proxy::send_packet(byte identifier, int payload_size, byte* payload);
Proxy::send_packet(Packet* p);
bool Proxy::establish_connection();
};
#include "processors.h"
Proxy::start_connection() {
Serial.write(START_PACKET);
while(!this->establish_connection()) {}
}
bool Proxy::establish_connection() {
if(!Serial.available()) return false;
uint8_t control = Serial.read();
if(control == 0xab) {
Serial.write(control);
return true;
}else return false;
}
Proxy::send_packet(byte identifier, int payload_size, byte* payload) {
Serial.write(identifier);
for(int i = 0; i < payload_size; i++) Serial.write(payload[i]);
}
Proxy::send_packet(Packet* p) {
this->send_packet(p->getIdentifier(), p->getPayloadSize(), p->getPayload());
delete p;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment