diff --git a/project/Core/Inc/modbus_tcp.h b/project/Core/Inc/modbus_tcp.h new file mode 100644 index 0000000..2812d7c --- /dev/null +++ b/project/Core/Inc/modbus_tcp.h @@ -0,0 +1,29 @@ +/** + * @file modbus_tcp.h + * + * @brief TCP Modbus handler + * @date Nov 6, 2023 + * @author Obe + */ + +#ifndef INC_MODBUS_H_ +#define INC_MODBUS_H_ + +#define MODBUSPORT 502 // 502 is the default + + +#include +#include +#include +#include +#include "lcd_api.h" +#include "llfs.h" + + +/** + * @fn void modbus_init + * @brief Initializes the modbus tcp + */ +void modbus_init(void); + +#endif /* INC_MODBUS_H_ */ diff --git a/project/Core/Src/main.c b/project/Core/Src/main.c index f564c3d..b5f6500 100644 --- a/project/Core/Src/main.c +++ b/project/Core/Src/main.c @@ -30,6 +30,7 @@ #include "lcd_api.h" #include "mqtt_application.h" #include "tftp.h" +#include "modbus_tcp.h" #include "UDP_broadcast.h" /* USER CODE END Includes */ @@ -134,7 +135,9 @@ int main(void) /* Initialize the tftp server */ tftp_server_init(); - + + /* Initialize Modbus*/ + modbus_init(); /* Initialize the MQTT application */ mqtt_application_init(); diff --git a/project/Core/Src/modbus_tcp.c b/project/Core/Src/modbus_tcp.c new file mode 100644 index 0000000..8b49558 --- /dev/null +++ b/project/Core/Src/modbus_tcp.c @@ -0,0 +1,162 @@ +/** + * @file modbus_tcp.c + * + * @brief TCP Modbus handler + * @date Nov 6, 2023 + * @author Obe + */ + +// Includes +#include "modbus_tcp.h" +#include "log.h" + +// Defines +#define MAX_REG REG_LENGTH +#define EXTENSION_LENGTH 4 +#define TEXT_LENGTH 200 +#define MULTIPLE_REG 0x10 +#define REG_LENGTH 428 +#define START_DATA 28 +#define MODBUS_MODE 7 + +#define REG_COLOR_B_RED 14 +#define REG_COLOR_B_GREEN 16 +#define REG_COLOR_B_BLUE 18 + +#define REG_COLOR_F_RED 20 +#define REG_COLOR_F_GREEN 22 +#define REG_COLOR_F_BLUE 24 + +#define REG_IMAGE_NR 26 + +// Global variables +static char* TAG = "Modbus_TCP"; // Tag used in logs + +static struct tcp_pcb* modbus_pcb; +uint8_t registers[MAX_REG]; + +// Functions +static err_t modbus_incoming_data(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); +static err_t modbus_accept(void* arg, struct tcp_pcb* pcb, err_t err); + +/** + * @fn static err_t modbus_incoming_data(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) + * @brief Function that's called when there is a new request on port 502. + * It handles the incoming data from QModMaster + */ +static err_t modbus_incoming_data(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) { + uint8_t counter; + char text[TEXT_LENGTH]; + uint32_t result_background = 0xff000000; + uint32_t text_foreground_color = 0xff000000; + LWIP_UNUSED_ARG(arg); + + // Putting underscores in the whole array + memset(text, '_', TEXT_LENGTH); + text[TEXT_LENGTH - 1] = '\0'; + + if (p != NULL) { + LOG_INFO(TAG, "data is valid\n"); + // Process the modbus data + tcp_recved(pcb, p->tot_len); + + // Putting the buffer in the register array + for (uint16_t i = 0; i < p->tot_len && i < MAX_REG; i++) { + registers[i] = ((uint*)p->payload)[i]; + } + + if (registers[MODBUS_MODE] == MULTIPLE_REG) { + // Check if it's a Modbus Write Multiple Registers request (0x10) + LOG_INFO(TAG, "in writing multiple register mode\n"); + + LOG_INFO(TAG, "Background R:%d G:%d B:%d\nForeground: R:%d G:%d B:%d\nImage Nr: %d", + registers[REG_COLOR_B_RED], registers[REG_COLOR_B_GREEN], registers[REG_COLOR_B_BLUE], + registers[REG_COLOR_F_RED], registers[REG_COLOR_F_GREEN], registers[REG_COLOR_F_BLUE], + registers[REG_IMAGE_NR]); + + counter = 0; + for (int i = START_DATA; i < REG_LENGTH; i++) { + if (i % 2 == 0) { + text[counter] = registers[i]; + counter++; + } + } + + result_background |= ((uint32_t)registers[REG_COLOR_B_RED]) << 16; + result_background |= ((uint32_t)registers[REG_COLOR_B_GREEN]) << 8; + result_background |= (uint32_t)registers[REG_COLOR_B_BLUE]; + + text_foreground_color |= ((uint32_t)registers[REG_COLOR_F_RED]) << 16; + text_foreground_color |= ((uint32_t)registers[REG_COLOR_F_GREEN]) << 8; + text_foreground_color |= (uint32_t)registers[REG_COLOR_F_BLUE]; + + // Processing the image index + size_t number_of_files = llfs_file_count(); // How many files that there are + + if (number_of_files > 0) { + llfs_file_t file_list[number_of_files]; + number_of_files = llfs_file_list(file_list, number_of_files, NULL); + + lcd_clear_text(); + lcd_clear_images(); + lcd_stop_all_gifs(); + + lcd_display_text(text, 10, 10, text_foreground_color, result_background, LCD_FONT24); + + if (number_of_files < registers[REG_IMAGE_NR]) { + lcd_display_text("FILE NOT IN FILESYSTEM", 10, 75, LCD_RED, LCD_BLACK, LCD_FONT24); + } else { + const char* ext = strrchr(file_list[registers[REG_IMAGE_NR] - 1].name, '.'); + if (ext == NULL) { + LOG_CRIT(TAG, "No valid extension found"); + } else if (strcmp(ext, ".gif") == 0) { + lcd_draw_gif_from_fs(file_list[registers[REG_IMAGE_NR] - 1].name, 0, 75); + } else if (strcmp(ext, ".bmp") == 0) { + lcd_draw_img_from_fs(file_list[registers[REG_IMAGE_NR] - 1].name, 0, 75); + } + } + } + + } else { + LOG_INFO(TAG, "not in writing multiple register mode!!!\n"); + } + } else if (err == ERR_OK) { + tcp_close(pcb); // When everything was ok close the TCP connection + } + return ERR_OK; +} + +/** + * @fn static err_t modbus_accept(void *arg, struct tcp_pcb *pcb, err_t err) + * @brief Sets the function that's being called when theirs incoming data + */ +static err_t modbus_accept(void* arg, struct tcp_pcb* pcb, err_t err) { + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + // Sets the priority of a connection. + tcp_setprio(pcb, TCP_PRIO_MIN); + + // Sets which function is being called when new data arrives + tcp_recv(pcb, modbus_incoming_data); + + return ERR_OK; +} + +/** + * @fn void modbus_init + * @brief Initializes the modbus tcp + */ +void modbus_init(void) { + LOG_INFO(TAG, "Initializing\n"); + // Creating a new tcp pcb + modbus_pcb = tcp_new(); + + // Bind the modbus_pcb to port 502 + tcp_bind(modbus_pcb, IP_ADDR_ANY, MODBUSPORT); + + modbus_pcb = tcp_listen(modbus_pcb); + // Set callback function for incoming connections + tcp_accept(modbus_pcb, modbus_accept); + LOG_INFO(TAG, "initialized\n"); +}