diff --git a/.vscode/settings.json b/.vscode/settings.json index 73aca1d..44acc89 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -87,7 +87,10 @@ "functional": "c", "variant": "c", "*.def": "c", - "unistd.h": "c" + "unistd.h": "c", + "string.h": "c", + "ftdi485.h": "c", + "logger.h": "c" }, "C_Cpp.errorSquiggles": "enabled" } \ No newline at end of file diff --git a/software/pc_client/src/console.c b/software/pc_client/src/console.c index 8c1a479..06ad3f2 100644 --- a/software/pc_client/src/console.c +++ b/software/pc_client/src/console.c @@ -60,8 +60,6 @@ void cmd_dm_register(json_object *req, json_object *res) x = json_object_get_int(jx); y = json_object_get_int(jy); - printf("[INFO][console] register new device wit addr %i at (%i,%i)", address, x, y); - int newId = devicemgr_register(fd, address, x, y, -1); json_object_object_add(res, "id", json_object_new_int(newId)); } diff --git a/software/pc_client/src/devicemgr.c b/software/pc_client/src/devicemgr.c index c9256c1..c3a3285 100644 --- a/software/pc_client/src/devicemgr.c +++ b/software/pc_client/src/devicemgr.c @@ -10,6 +10,7 @@ */ #include "devicemgr.h" +#include "logging/logger.h" #include #include #include @@ -127,7 +128,7 @@ int devicemgr_readCalib(int device_id) } else { - printf("Error reading eeprom from %i\n", device_id); + log_message(LOG_ERROR, "Error reading eeprom from %i", device_id); free(buffer_r); return -1; } @@ -246,12 +247,12 @@ void setSingle(int id, char flap) { // first convert char to flap id char test_char = toupper(flap); - printf("find char %c\n", test_char); + // printf("find char %c\n", test_char); for (int ix = 0; ix < 45; ix++) { if (*symbols[ix] == test_char) { - printf("match char %i %i %i\n", test_char, *symbols[ix], ix); + // printf("match char %i %i %i\n", test_char, *symbols[ix], ix); sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, ix); devices[id].current_flap = ix; break; @@ -272,7 +273,7 @@ void devicemgr_printText(const char *text, int x, int y) int this_id = deviceMap[x + i][y]; if (this_id >= 0) { - printf("print char %c to %i\n", *(text + i), devices[this_id].address); + log_message(LOG_DEBUG, "print char '%c' to id:%i", *(text + i), devices[this_id].address); setSingle(this_id, *(text + i)); } @@ -310,6 +311,7 @@ int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y, in nextFreeSlot++; nid = nextFreeSlot; } + log_message(LOG_INFO, "Register new device with addr %i at (%i,%i) with id %i", address, x, y, nid); devices[nid].pos_x = x; devices[nid].pos_y = y; @@ -380,7 +382,7 @@ int devicemgr_save(char *file) json_object_object_add(root, "devices", device_array); const char *data = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY); - printf("[INFO][console] store data to %s\n", file); + log_message(LOG_INFO, "store config data to %s\n", file); FILE *fptr; fptr = fopen(file, "w"); @@ -392,6 +394,9 @@ int devicemgr_load(char *file) { FILE *fptr; char *line_in_file = malloc(JSON_MAX_LINE_LEN); // maximum of 256 bytes per line; + + log_message(LOG_INFO, "load config data from %s\n", file); + fptr = fopen(file, "r"); json_tokener *tok = json_tokener_new(); json_object *jobj = NULL; @@ -412,7 +417,7 @@ int devicemgr_load(char *file) if (jerr != json_tokener_success) { free(fptr); //free file pointer - fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); + log_message(LOG_ERROR, "%s", json_tokener_error_desc(jerr)); // Handle errors, as appropriate for your application. return -1; } @@ -429,7 +434,7 @@ int devicemgr_load(char *file) json_object *next_free; if (!json_object_object_get_ex(jobj, "nextFreeSlot", &next_free)) { - fprintf(stderr, "Error: %s\n", "Key 'nextFreeSlot' not found."); + log_message(LOG_ERROR, "%s", "Key 'nextFreeSlot' not found."); return -1; } else @@ -445,7 +450,7 @@ int devicemgr_load(char *file) json_object *devices; if (!json_object_object_get_ex(jobj, "devices", &devices)) { - fprintf(stderr, "Error: %s\n", "Key 'devices' not found."); + log_message(LOG_ERROR, "%s", "Key 'devices' not found."); return -1; } else @@ -470,22 +475,22 @@ int devicemgr_load_single(json_object *device_obj) // verify values are present if (jid == NULL) { - fprintf(stderr, "Error: Key 'device.%s' not found\n", "id"); + log_message(LOG_ERROR, "Key 'device.%s' not found", "id"); return -1; } if (jaddr == NULL) { - fprintf(stderr, "Error: Key 'address.%s' not found\n", "id"); + log_message(LOG_ERROR, "Error: Key 'address.%s' not found", "id"); return -1; } if (jposx == NULL) { - fprintf(stderr, "Error: Key 'device.%s' not found\n", "position.x"); + log_message(LOG_ERROR, "Error: Key 'device.%s' not found", "position.x"); return -1; } if (jposy == NULL) { - fprintf(stderr, "Error: Key 'device.%s' not found\n", "position.y"); + log_message(LOG_ERROR, "Error: Key 'device.%s' not found", "position.y"); return -1; } diff --git a/software/pc_client/src/ftdi485.c b/software/pc_client/src/ftdi485.c index 29429aa..bfea5f4 100644 --- a/software/pc_client/src/ftdi485.c +++ b/software/pc_client/src/ftdi485.c @@ -8,50 +8,56 @@ */ #include "ftdi485.h" +#include "logging/logger.h" /* * Open RS485 Interface (FT232RL) */ -int rs485_init(char *device, int baud) { - int rs485_fd = open(device, O_RDWR); - if (rs485_fd < 0) { - printf("Error %i from open: %s\n", errno, strerror(errno)); - return -1; - } - // Flush all data - int result = tcflush(rs485_fd, TCIOFLUSH); - if (result) { - perror("tcflush failed"); // just a warning, not a fatal error - return -1; - } - // Set port config and baud - struct termios options; - result = tcgetattr(rs485_fd, &options); - if (result) { - perror("tcgetattr failed"); - close(rs485_fd); - return -1; - } +int rs485_init(char *device, int baud) +{ + int rs485_fd = open(device, O_RDWR); + if (rs485_fd < 0) + { + log_message(LOG_CRITICAL, "Error %i from open: %s", errno, strerror(errno)); + return -1; + } + // Flush all data + int result = tcflush(rs485_fd, TCIOFLUSH); + if (result) + { + log_message(LOG_WARNING, "RS485 tcflush failed"); // just a warning, not a fatal error + return -1; + } + // Set port config and baud + struct termios options; + result = tcgetattr(rs485_fd, &options); + if (result) + { + log_message(LOG_CRITICAL, "tcgetattr failed"); + close(rs485_fd); + return -1; + } - // Turn off any options that might interfere with our ability to send and - // receive raw binary bytes. - options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF); - options.c_oflag &= ~(ONLCR | OCRNL); - options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + // Turn off any options that might interfere with our ability to send and + // receive raw binary bytes. + options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF); + options.c_oflag &= ~(ONLCR | OCRNL); + options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - // Set up timeouts: Calls to read() will return as soon as there is - // at least one byte available or when 100 ms has passed. - options.c_cc[VTIME] = 1; - options.c_cc[VMIN] = 0; + // Set up timeouts: Calls to read() will return as soon as there is + // at least one byte available or when 100 ms has passed. + options.c_cc[VTIME] = 1; + options.c_cc[VMIN] = 0; - cfsetospeed(&options, baud); - cfsetispeed(&options, baud); - result = tcsetattr(rs485_fd, TCSANOW, &options); - if (result) { - perror("tcsetattr failed"); - close(rs485_fd); - return -1; - } + cfsetospeed(&options, baud); + cfsetispeed(&options, baud); + result = tcsetattr(rs485_fd, TCSANOW, &options); + if (result) + { + log_message(LOG_CRITICAL, "tcsetattr failed"); + close(rs485_fd); + return -1; + } - return rs485_fd; + return rs485_fd; } diff --git a/software/pc_client/src/logging/logger.c b/software/pc_client/src/logging/logger.c new file mode 100644 index 0000000..3123a9a --- /dev/null +++ b/software/pc_client/src/logging/logger.c @@ -0,0 +1,43 @@ +#include "logger.h" +#include +#include +#include +#include +#include + +int log_level_global = 4; + +const char *loglevel[] = {"TRACE","DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}; + +void init_logger(int log_level) +{ + log_level_global = log_level; +} + +void log_message(int level, const char *message, ...) +{ + if (level >= log_level_global) + { + va_list args; // get arguments + va_start(args, message); + time_t now; // prepare time + time(&now); + char *ctime_no_newline = strtok(ctime(&now), "\n"); + printf("%s [%s]: ", ctime_no_newline, loglevel[level]); // print message + vprintf(message, args); + printf("\n"); + } +} + +int log_message_header(int level) +{ + if (level >= log_level_global) + { + time_t now; // prepare time + time(&now); + char *ctime_no_newline = strtok(ctime(&now), "\n"); + printf("%s [%s]: ", ctime_no_newline, loglevel[level]); // print message + return 1; + } + return 0; +} \ No newline at end of file diff --git a/software/pc_client/src/logging/logger.h b/software/pc_client/src/logging/logger.h new file mode 100644 index 0000000..fa883ea --- /dev/null +++ b/software/pc_client/src/logging/logger.h @@ -0,0 +1,17 @@ +#ifndef LOGGER_H +#define LOGGER_H + +void log_message(int level, const char *message, ...); +int log_message_header(int level); +void init_logger(int log_level); + +enum logLevelEnum +{ + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR, + LOG_CRITICAL +}; +#endif /* LOG_H */ diff --git a/software/pc_client/src/main.c b/software/pc_client/src/main.c index 9c03f34..e66a2ce 100644 --- a/software/pc_client/src/main.c +++ b/software/pc_client/src/main.c @@ -19,6 +19,7 @@ #include "console.h" #include "devicemgr.h" #include "ftdi485.h" +#include "logging/logger.h" #include "sfbus.h" extern char *optarg; @@ -31,6 +32,9 @@ void printUsage(char *argv[]) int main(int argc, char *argv[]) { + init_logger(LOG_TRACE); + log_message(LOG_INFO, "Starting split-flap pc client %s", "v1.0.0"); + log_message(LOG_INFO, "(c) 2024-2025 GuniaLabs (www.dennisgunia.de)"); int opt = ' '; u_int16_t addr_int = 0; char *port = malloc(256); @@ -62,13 +66,13 @@ int main(int argc, char *argv[]) } if (access(port, F_OK) != 0) { - fprintf(stderr, "Filedescriptor: %s does not exist or cannot be opened\n", port); + log_message(LOG_CRITICAL, "Filedescriptor: %s does not exist or cannot be opened\n", port); printUsage(argv); } // parse address if (strlen(addr) == 0) { - fprintf(stderr, "Please specify address\n"); + log_message(LOG_CRITICAL, "Please specify address\n"); printUsage(argv); } else @@ -79,7 +83,7 @@ int main(int argc, char *argv[]) // start program setvbuf(stdout, NULL, _IONBF, 0); // do not buffer stdout!!!! - printf("Open device at %s\n", port); + log_message(LOG_INFO,"Open device at %s @ 57600 Baud", port); int fd = rs485_init(port, B57600); // setup rs485 if (strcmp(command, "ping") == 0) diff --git a/software/pc_client/src/sfbus-util.c b/software/pc_client/src/sfbus-util.c index 547c502..804bdf0 100644 --- a/software/pc_client/src/sfbus-util.c +++ b/software/pc_client/src/sfbus-util.c @@ -8,11 +8,14 @@ */ #include "sfbus-util.h" +#include "logging/logger.h" + int sfbusu_write_address(int fd, u_int16_t current, u_int16_t new) { + log_message(LOG_INFO, "Writing new address 0x%04X to device with current address 0x%04X", new, current); if (new < 1) { - printf("Please specify new address > 0 with -d\n"); + log_message(LOG_ERROR, "Cannot write address: Please specify new address > 0 with -d"); return -1; } // read current eeprom status @@ -20,7 +23,7 @@ int sfbusu_write_address(int fd, u_int16_t current, u_int16_t new) char *buffer_r = malloc(64); if (sfbus_read_eeprom(fd, current, buffer_w) < 0) { - fprintf(stderr, "Error reading eeprom\n"); + log_message(LOG_ERROR, "Cannot write address: Error reading eeprom"); return 1; } // modify current addr @@ -28,28 +31,28 @@ int sfbusu_write_address(int fd, u_int16_t current, u_int16_t new) memcpy(buffer_w, &n_addr_16, 2); if (sfbus_write_eeprom(fd, current, buffer_w, buffer_r) < 0) { - fprintf(stderr, "Error writing eeprom\n"); + log_message(LOG_ERROR, "Cannot write address: Error writing eeprom"); return 1; } - return 0; } int sfbusu_write_calibration(int fd, u_int16_t address, u_int16_t data) { + log_message(LOG_INFO, "Writing new calibration 0x%04X to device at address 0x%04X", data, address); // read current eeprom status char *buffer_w = malloc(64); char *buffer_r = malloc(64); if (sfbus_read_eeprom(fd, address, buffer_w) < 0) { - fprintf(stderr, "Error reading eeprom\n"); + log_message(LOG_ERROR, "Cannot write calibration: Error reading eeprom"); return 1; } // modify current calibration memcpy(buffer_w + 2, &data, 2); if (sfbus_write_eeprom(fd, address, buffer_w, buffer_r) < 0) { - fprintf(stderr, "Error writing eeprom\n"); + log_message(LOG_ERROR, "Cannot write address: Error writing eeprom"); return 1; } diff --git a/software/pc_client/src/sfbus.c b/software/pc_client/src/sfbus.c index e84c919..0877f65 100644 --- a/software/pc_client/src/sfbus.c +++ b/software/pc_client/src/sfbus.c @@ -8,10 +8,12 @@ */ #include "sfbus.h" +#include "logging/logger.h" #include #include #include + void print_charHex(char *buffer, int length) { int _tlength = length; @@ -25,16 +27,22 @@ void print_charHex(char *buffer, int length) void print_bufferHexRx(char *buffer, int length, u_int16_t address) { - printf("Rx (0x%04X): ", address); - print_charHex(buffer, length); - printf("| %i bytes received\n", length); + if (log_message_header(LOG_TRACE) > 0) + { + printf("Rx (0x%04X): ", address); + print_charHex(buffer, length); + printf("| %i bytes received\n", length); + } } void print_bufferHexTx(char *buffer, int length, u_int16_t address) { - printf("Tx (0x%04X): ", address); - print_charHex(buffer, length); - printf("| %i bytes sent\n", length); + if (log_message_header(LOG_TRACE) > 0) + { + printf("Tx (0x%04X): ", address); + print_charHex(buffer, length); + printf("| %i bytes sent\n", length); + } } ssize_t sfbus_recv_frame_wait(int fd, u_int16_t address, char *buffer) @@ -47,7 +55,7 @@ ssize_t sfbus_recv_frame_wait(int fd, u_int16_t address, char *buffer) retryCount--; if (retryCount == 0) { - fprintf(stderr, "Rx timeout\n"); + log_message(LOG_WARNING, "RX timeout waiting for data at 0x%04X", address); return -1; } } while (len <= 0); @@ -99,13 +107,16 @@ ssize_t sfbus_recv_frame_v2(int fd, u_int16_t address, char *buffer) if (frm_crc == calc_crc) { - printf("crc check okay! expected: %04X received: %04X\n", calc_crc, frm_crc); + log_message(LOG_DEBUG, "crc check okay! expected: %04X received: %04X", calc_crc, frm_crc); return frm_length; } else { - print_bufferHexRx(buffer, frm_length - 4, address); - printf("crc check failed! expected: %04X received: %04X\n", calc_crc, frm_crc); + if (log_message_header(LOG_TRACE) > 0) + { + print_bufferHexRx(buffer, frm_length - 4, address); + } + log_message(LOG_DEBUG,"crc check failed! expected: %04X received: %04X", calc_crc, frm_crc); return -1; } @@ -150,13 +161,13 @@ int sfbus_ping(int fd, u_int16_t address) int len = sfbus_recv_frame_wait(fd, 0xFFFF, buffer); if (len == 5 && *buffer == (char)0xFF) // expect 0xFF on successful ping { - printf("Ping okay!\n"); + log_message(LOG_DEBUG, "Ping to 0x%04X okay!", address); free(buffer); return 0; } else { - printf("Ping invalid response!\n"); + log_message(LOG_WARNING, "Ping to 0x%04X failed! Invalid or no response.", address); free(buffer); return 1; } @@ -170,12 +181,12 @@ int sfbus_read_eeprom(int fd, u_int16_t address, char *buffer) int len = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer); if (len != 10) { - printf("Invalid data!\n"); + log_message(LOG_WARNING, "Invalid data received from 0x%04X! Unexpected package length.", address); return -1; } if (*(_buffer + 5) != (char)0xAA || *(_buffer) != (char)0xAA) { - printf("Invalid data!\n"); + log_message(LOG_WARNING, "Invalid data received from 0x%04X! No ACK byte received.", address); return -1; } memcpy(buffer, _buffer + 1, len - 4); @@ -196,12 +207,12 @@ int sfbus_write_eeprom(int fd, u_int16_t address, char *wbuffer, char *rbuffer) int len = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer); if (len != 10) { - printf("Invalid data!\n"); + log_message(LOG_WARNING, "Invalid data received from 0x%04X! Unexpected package length.", address); return -1; } if (*(_buffer + 5) != (char)0xAA || *(_buffer) != (char)0xAA) { - printf("Invalid data!\n"); + log_message(LOG_WARNING, "Invalid data received from 0x%04X! No ACK byte received.", address); return -1; } memcpy(rbuffer, _buffer + 1, len - 4); @@ -236,7 +247,7 @@ u_int8_t sfbus_read_status(int fd, u_int16_t address, double *voltage, u_int32_t char *_buffer = malloc(256); sfbus_send_frame_v2(fd, address, strlen(cmd), cmd); - int res = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer); + int res = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer); if (res < 0) { return 0xFF; diff --git a/software/pc_client/src/wsserver.c b/software/pc_client/src/wsserver.c index d72870e..9ff10b1 100644 --- a/software/pc_client/src/wsserver.c +++ b/software/pc_client/src/wsserver.c @@ -8,7 +8,7 @@ */ #include "wsserver.h" - +#include "logging/logger.h" /* * This section provides a web server to controll the * device manager through web sockets @@ -22,7 +22,7 @@ void ws_opencon(ws_cli_conn_t client) { char *cli; cli = ws_getaddress(client); - printf("Connection opened, addr: %s\n", cli); + log_message(LOG_DEBUG, "WebSocket connection opened, addr: %s", cli); } // called on closing websocket client @@ -30,14 +30,14 @@ void ws_closecon(ws_cli_conn_t client) { char *cli; cli = ws_getaddress(client); - printf("Connection closed, addr: %s\n", cli); + log_message(LOG_DEBUG, "WebSocket connection closed, addr: %s", cli); } // called on receiving websocket message void ws_messagehandler(ws_cli_conn_t client, const unsigned char *msg, uint64_t size, int type) { char *cli = ws_getaddress(client); - printf("received message: %s (%zu), from: %s\n", msg, size, cli); + log_message(LOG_DEBUG, "WebSocket received message: %s (%zu), from: %s", msg, size, cli); json_tokener *tok = json_tokener_new(); json_object *req = json_tokener_parse_ex(tok, msg, size); @@ -46,13 +46,12 @@ void ws_messagehandler(ws_cli_conn_t client, const unsigned char *msg, uint64_t if (jerr != json_tokener_success) { // check if request can be parsed, if not retrun error - send_json_error(client, "parsing error", json_tokener_error_desc(jerr)); + send_json_error(client, "WebSocket JSON parsing error", json_tokener_error_desc(jerr)); } else { // if it can be parsed, get command. json_object *commandObj = json_object_object_get(req, "command"); - printf("test"); if (commandObj != NULL) { const char *command = json_object_to_json_string(commandObj); @@ -95,6 +94,8 @@ void send_json_error(ws_cli_conn_t client, char *error, const char *detail) int start_webserver(json_object *(*commandparser_func_ptr)(json_object *)) { commandparser_func = commandparser_func_ptr; + log_message(LOG_INFO, "Websocket server started at ws://%s:%d", WS_SERVER_ADDR, WS_SERVER_PORT); + ws_socket(&(struct ws_server){/* * Bind host, such as: * localhost -> localhost/127.0.0.1