/**
 * @file modbus_tcp.c
 *
 * @brief TCP Modbus handler
 *  Created on: Nov 6, 2023
 *      Author: Obe
 */

// Includes
#include "modbus_tcp.h"
#include "log.h"

// Defines
#define MAX_REG 250
#define EXTENSION_LENGHT 4
#define TEXT_LENGHT 200
#define MULTIPLE_REG 0x10


// Global variables
char registers[MAX_REG];
//const char* TAG = "Modbus_TCP"; // Tag used in logs

// Functions
static err_t modbus_incomming_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_incomming_data(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
 * @brief Function thats called when theris a new request on port 502.
 * It handles the incomming data from Qmodmaster
 */

static err_t modbus_incomming_data(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err){
    uint8_t counter;
    char *pc;
    char text[TEXT_LENGHT];
    uint8_t background_red = 0;
    uint8_t background_green = 0;
    uint8_t background_blue = 0;
    uint8_t text_color_red = 0;
    uint8_t text_color_green = 0;
    uint8_t text_color_blue = 0;
    uint8_t nr_img = 0;
    uint32_t result_background = 0;
    uint32_t result_txt = 0;

    memcpy(text,'_',TEXT_LENGHT);                    // Putting underscores in the whole array
    text[TEXT_LENGHT-1] = '\0';

    if (p != NULL){
        //LOG_INFO(TAG, "data not null\n");
                                                     // here im going to procces the modbusdata
        tcp_recved( pcb, p->tot_len );
        pc = (char*)p->payload;

        for(uint16_t i = 0; i < p->tot_len; i++) {   // putting the bufer in the register array
            registers[i] = pc[i];                    // getting the error "void value not ignored as it ought to be" on this line
        }

        if(registers[7] == MULTIPLE_REG){            // Check if it's a Modbus Write Multiple Registers request (0x10)
            //LOG_INFO(TAG, "in writing multiple register mode\n");
            background_red = (uint8_t)(registers[14]);       // 01
            background_green = (uint8_t)(registers[16]);     // 02
            background_blue = (uint8_t)(registers[18]);      // 03
            text_color_red = (uint8_t)(registers[20]);      // 04
            text_color_green = (uint8_t)(registers[22]);    // 05
            text_color_blue = (uint8_t)(registers[24]);     // 06
            nr_img = (uint8_t)(registers[26]);       // 07

            //LOG_INFO(TAG, "%d %d %d %d %d %d %d ",background_red,background_green,background_blue,text_color_red,text_color_green,text_color_blue,nr_img);

            counter = 0;
            for(int i = 28; i < 428; i++){
                if(i % 2 == 0){
                    text[counter] = registers[i];
                    counter++;
                }
            }

            result_background = 0xff000000;
            result_background |= ((uint32_t)background_red) << 16;
            result_background |= ((uint32_t)background_green) << 8;
            result_background |= background_blue;

            result_txt = 0xff000000;
            result_txt |= ((uint32_t)text_color_red) << 16;
            result_txt |= ((uint32_t)text_color_green) << 8;
            result_txt |= text_color_blue;
                                                                                                 // proccesing the image index
            size_t number_of_files = llfs_file_count();                                          // How many files that there are

            llfs_file_t file_list[number_of_files];                                              // reserving memory for the list

            number_of_files = llfs_file_list(file_list, number_of_files, NULL);                  // freeed memory filled with the list

            if(number_of_files < nr_img){
                lcd_clear_text();
                lcd_clear_images();
                lcd_stop_all_gifs();
                lcd_display_text(text, 10, 10, result_txt, result_background, LCD_FONT24);       //When no image
                lcd_display_text("FILE NOT IN FILESYSTEM", 10, 75, LCD_RED, LCD_BLACK, LCD_FONT24);
            }
            else{
                const char * ext = strrchr(file_list[nr_img - 1].name, '.');
                if (ext == NULL) {
                      // No valid extension found
                }
                if (strcmp(ext,".gif") == 0) {
                    lcd_clear_text();
                    lcd_clear_images();
                    lcd_stop_all_gifs();
                    lcd_display_text(text, 10, 10, result_txt, result_background, LCD_FONT24);
                    lcd_gif_t* gif = lcd_draw_gif_from_fs(file_list[nr_img - 1].name, 0, 75);    //GIF on screen
                } else if (strcmp(ext,".bmp") == 0) {
                    lcd_clear_text();
                    lcd_clear_images();
                    lcd_stop_all_gifs();
                    lcd_display_text(text, 10, 10, result_txt, result_background, LCD_FONT24);
                    lcd_draw_img_from_fs(file_list[nr_img - 1].name, 0, 75);                     //BMP on screen
                }
            }
        }
        else{
            //LOG_INFO(TAG, "not in writing multiple register mode!!!\n");
        }
    } else if (err == ERR_OK){
        tcp_close(pcb);    // when everithing was ok close the tcpconnection
    }
    return ERR_OK;
}


/**
 * @fn static err_t modbus_accept(void *arg, struct tcp_pcb *pcb, err_t err)
 * @brief Sets the function thats being called when theirs incoming data
 */

static err_t modbus_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
    LWIP_UNUSED_ARG(arg);                    // Eliminates compiler warning about unused arguments
    LWIP_UNUSED_ARG(err);                    // Eliminates compiler warning about unused arguments
    tcp_setprio(pcb, TCP_PRIO_MIN);          // Sets the priority of a connection.
    tcp_recv(pcb, modbus_incomming_data);    // sets which function is being called when new data arives

    return ERR_OK;
}


/**
 * @fn void modbus_init
 * @brief Initiallises the modbus tcp
 */

void modbus_init(void)
{
    struct tcp_pcb *modbus_pcb;
    modbus_pcb = tcp_new();                           // creating a new tcp pcb
    tcp_bind(modbus_pcb, IP_ADDR_ANY, MODBUSPORT);   // bind the modbus_pcb to port 502

    modbus_pcb = tcp_listen(modbus_pcb);              // listen
    tcp_accept(modbus_pcb, modbus_accept);            // set callback function
}



