Webserver only w/o any other functions, single thread. Running on STM32F013+W5500

Dependencies:   NTPClient W5500Interface Watchdog device_configuration eeprom_flash mbed-rpc-nucleo mbed-rtos mbed

Fork of F103-Serial-to-Ethernet by Chau Vo

main.cpp

Committer:
olympux
Date:
2014-09-26
Revision:
10:4cd965d79de0
Parent:
9:d2534ecf88c6
Child:
11:709f90a3b599

File content as of revision 10:4cd965d79de0:

/*
*
*  Alarm and Monitoring application

*/
#include "mbed.h"
//#include "eeprom.h"
#include "EthernetInterface.h"
#include "NTPClient.h"
#include "rtos.h"


/*
* Hardware defines
*/
#define ST_NUCLEO // hardware pin mapping

#ifdef ST_NUCLEO
// Ethernet
SPI spi(PA_7, PA_6, PA_5); // mosi, miso, sclk
EthernetInterface eth(&spi, PC_8, PC_9); // spi, cs, reset
#endif

// Serial
Serial uart(USBTX,USBRX);

// Digital inputs
// Digital outputs
// Analog inputs
// Analog outputs
//AnalogOut ano0(p18);


// eeprom
#define NumbOfVar         ((uint8_t)0x80) // REMEMBER: update this variable in eeprom.h too
#define IP_ADDRESS_POS         0
#define IP_SUBNET_POS          4
#define IP_GATEWAY_POS         8
#define TCP_SERVER_PORT_POS    12
#define UDP_SERVER_PORT_POS    13
#define FIRST_RUN_FLAG_POS     14
#define MAC_ADDRESS_POS        15
// Virtual address defined by the user: 0xFFFF value is prohibited
uint16_t VirtAddVarTab[NumbOfVar] = {0x1212, 0x1313, 0x1414, 0x1515, // IP_Addr
                                     0x2212, 0x2313, 0x2414, 0x2515, // IP_Subnet
                                     0x3212, 0x3313, 0x3414, 0x3515, // IP_Gateway
                                     0x4212, // TCP server port, not used
                                     0x5212, // UDP server port, not used
                                     0x8888,  // 1st run? 
                                     0x6212, 0x6313, 0x6414 // MAC
                                     };
extern "C" uint16_t EE_Init(void);
extern "C" uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
extern "C" uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);


/*
* Network configuration
*/
#define TCP_SERVER
//#define TCP_CLIENT
#define UDP_SERVER
//#define UDP_CLIENT
#define NTP

#define DEFAULT_IP_ADDRESS      "192.168.0.249"
#define DEFAULT_IP_SUBNET       "255.255.255.0"
#define DEFAULT_IP_GATEWAY      "192.168.0.1"
#define DEFAULT_MAC3            0x00
#define DEFAULT_MAC4            0x00
#define DEFAULT_MAC5            0x01

#define TCP_SERVER_WAIT_CLIENT_TIMEOUT     200
#define TCP_SERVER_RECEIVE_TIMEOUT         3000
#define UDP_SERVER_RECEIVE_TIMEOUT         200

// for static IP setting
uint8_t mac[6];
char * IP_Addr; // pointers to 
char * IP_Subnet;
char * IP_Gateway;

uint16_t u16ip_addr[4], u16ip_subnet[4], u16ip_gateway[4]; // directly loaded from eeprom
uint16_t first_run = 0;  // first run flag
uint16_t u16mac_addr[3]; // loaded from eeprom
char   ip_addr[16], ip_subnet[16], ip_gateway[16]; // chars, converted from u16ip_xxx

const uint16_t tcp_server_port = 10000; // fixed
const uint16_t udp_server_port = 11000; // fixed

char buffer[256]; // socket buffer

NTPClient ntp;

// Commands
#define DEVICE_ID                   "NNIO"
#define DISCOVERY_COMMAND           "NNIODS"
#define TCP_SERVER_PORT_COMAMND     "NNIOTP"
#define UDP_SERVER_PORT_COMAMND     "NNIOUP"
#define QUERY_STATUS_COMMAND        (uint8_t)'Q'


// Positions
#define RECEIVING_PROTOCOL_OP_POS           4
#define RECEIVING_PROTOCOL_EN_DO_POS        RECEIVING_PROTOCOL_OP_POS + 0
#define RECEIVING_PROTOCOL_EN_A0O_POS       RECEIVING_PROTOCOL_OP_POS + 1
#define RECEIVING_PROTOCOL_EN_A1O_POS       RECEIVING_PROTOCOL_OP_POS + 2
#define RECEIVING_PROTOCOL_EN_UART_POS      RECEIVING_PROTOCOL_OP_POS + 3
#define RECEIVING_PROTOCOL_COMMAND_POS      RECEIVING_PROTOCOL_OP_POS + 4
#define RECEIVING_PROTOCOL_ENABLE_OUTPUT    (uint8_t)'O'


#define RECEIVING_PROTOCOL_POS_IP           9
#define RECEIVING_PROTOCOL_POS_DO           13
#define RECEIVING_PROTOCOL_POS_A0O          21
#define RECEIVING_PROTOCOL_POS_A01          23
#define RECEIVING_PROTOCOL_POS_UART         25



/*
* RTOS
*/
struct message_t {
    int len;
    char *msg;
};
Queue<message_t, 16> uart_queue;

Mutex uart_mutex;


/*
* Threads
*/
void uart_thread(void const *args) {
    message_t *p_message;
    
    while (true) {
        osEvent evt = uart_queue.get();
        if (evt.status == osEventMessage) {
            p_message = (message_t*)evt.value.p;
            uart_mutex.lock();
            //uart.printf("len=%d\n", p_message->len);
            uart.printf("%s\n", p_message->msg);
            uart_mutex.unlock();
        }
    }
}


/*
* Ethernet init
*/
int ethernet_init(void) {
    //printf("Start\n");
    int ret = eth.init(mac, IP_Addr, IP_Subnet, IP_Gateway); // static

    if (!ret) {
        uart.printf("Initialized, MAC: %s\n", eth.getMACAddress());
    } else {
        uart.printf("Error eth.init() - ret = %d\n", ret);
        return -1;
    }

    ret = eth.connect();
    if (!ret) {
        uart.printf("IP: %s, MASK: %s, GW: %s\n", eth.getIPAddress(), eth.getNetworkMask(), eth.getGateway());
    } else {
        uart.printf("Error eth.connect() - ret = %d\n", ret);
        return -1;
    }
    
    return 0;
}


/*
* EEPROM functions
*/
void write_eeprom(char *buffer) {
    // Write network configuration
    // 4-byte IP address + 4-byte subnet + 4-byte gateway + 3-byte MAC
    
    // Unlock the Flash Program Erase controller */
    FLASH_Unlock();
    // EEPROM Init
    EE_Init();
    // IP address
    EE_WriteVariable(VirtAddVarTab[IP_ADDRESS_POS+0], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_ADDRESS_POS+1], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_ADDRESS_POS+2], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_ADDRESS_POS+3], *buffer++);
    
    // IP subnet
    EE_WriteVariable(VirtAddVarTab[IP_SUBNET_POS+0], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_SUBNET_POS+1], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_SUBNET_POS+2], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_SUBNET_POS+3], *buffer++);
    
    // IP gateway
    EE_WriteVariable(VirtAddVarTab[IP_GATEWAY_POS+0], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_GATEWAY_POS+1], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_GATEWAY_POS+2], *buffer++);
    EE_WriteVariable(VirtAddVarTab[IP_GATEWAY_POS+3], *buffer++);
    
    //// TCP server port, not used
    //EE_WriteVariable(VirtAddVarTab[TCP_SERVER_PORT_POS], *buffer++);
    //// UDP server port, not used
    //EE_WriteVariable(VirtAddVarTab[UDP_SERVER_PORT_POS], *buffer++);
    
    // erase first_run flag
    EE_WriteVariable(VirtAddVarTab[FIRST_RUN_FLAG_POS], 0xA5A5);
    
    // MAC address
    EE_WriteVariable(VirtAddVarTab[MAC_ADDRESS_POS+0], *buffer++);
    EE_WriteVariable(VirtAddVarTab[MAC_ADDRESS_POS+1], *buffer++);
    EE_WriteVariable(VirtAddVarTab[MAC_ADDRESS_POS+2], *buffer++);
    FLASH_Lock();
}


void load_eeprom(void) {
    mbed_mac_address((char *)mac);
    
    EE_Init();
    
    // check if 1st run
    EE_ReadVariable(VirtAddVarTab[FIRST_RUN_FLAG_POS], &first_run);
    // if not first run, load network config
    if (first_run == 0xA5A5) {
        // IP address
        EE_ReadVariable(VirtAddVarTab[IP_ADDRESS_POS+0], &u16ip_addr[0]);
        EE_ReadVariable(VirtAddVarTab[IP_ADDRESS_POS+1], &u16ip_addr[1]);
        EE_ReadVariable(VirtAddVarTab[IP_ADDRESS_POS+2], &u16ip_addr[2]);
        EE_ReadVariable(VirtAddVarTab[IP_ADDRESS_POS+3], &u16ip_addr[3]);
        
        // IP subnet
        EE_ReadVariable(VirtAddVarTab[IP_SUBNET_POS+0], &u16ip_subnet[0]);
        EE_ReadVariable(VirtAddVarTab[IP_SUBNET_POS+1], &u16ip_subnet[1]);
        EE_ReadVariable(VirtAddVarTab[IP_SUBNET_POS+2], &u16ip_subnet[2]);
        EE_ReadVariable(VirtAddVarTab[IP_SUBNET_POS+3], &u16ip_subnet[3]);
        
        // IP gateway
        EE_ReadVariable(VirtAddVarTab[IP_GATEWAY_POS+0], &u16ip_gateway[0]);
        EE_ReadVariable(VirtAddVarTab[IP_GATEWAY_POS+1], &u16ip_gateway[1]);
        EE_ReadVariable(VirtAddVarTab[IP_GATEWAY_POS+2], &u16ip_gateway[2]);
        EE_ReadVariable(VirtAddVarTab[IP_GATEWAY_POS+3], &u16ip_gateway[3]);
        
        //// TCP server port
        //EE_ReadVariable(VirtAddVarTab[TCP_SERVER_PORT_POS], &tcp_server_port);
        //// UDP server port
        //EE_ReadVariable(VirtAddVarTab[UDP_SERVER_PORT_POS], &udp_server_port);
        
        // First run flag, already read above

        // MAC address
        EE_ReadVariable(VirtAddVarTab[MAC_ADDRESS_POS+0], &u16mac_addr[0]);
        EE_ReadVariable(VirtAddVarTab[MAC_ADDRESS_POS+1], &u16mac_addr[1]);
        EE_ReadVariable(VirtAddVarTab[MAC_ADDRESS_POS+2], &u16mac_addr[2]);
        mac[3] = (uint8_t)(u16mac_addr[0] & 0x00FF);
        mac[4] = (uint8_t)(u16mac_addr[1] & 0x00FF);
        mac[5] = (uint8_t)(u16mac_addr[2] & 0x00FF);
        //FLASH_Lock();
        
        sprintf(ip_addr, "%d.%d.%d.%d", (uint8_t)u16ip_addr[0], (uint8_t)u16ip_addr[1], (uint8_t)u16ip_addr[2], (uint8_t)u16ip_addr[3]);
        sprintf(ip_subnet, "%d.%d.%d.%d", (uint8_t)u16ip_subnet[0], (uint8_t)u16ip_subnet[1], (uint8_t)u16ip_subnet[2], (uint8_t)u16ip_subnet[3]);
        sprintf(ip_gateway, "%d.%d.%d.%d", (uint8_t)u16ip_gateway[0], (uint8_t)u16ip_gateway[1], (uint8_t)u16ip_gateway[2], (uint8_t)u16ip_gateway[3]);
    }
    // if 1st run, use default addresses
    else {
        mac[0] = 0x00; mac[1] = 0x08; mac[2] = 0xDC;
        mac[3] = DEFAULT_MAC3; mac[4] = DEFAULT_MAC4; mac[5] = DEFAULT_MAC5; 
        sprintf(ip_addr, DEFAULT_IP_ADDRESS);
        sprintf(ip_subnet, DEFAULT_IP_SUBNET);
        sprintf(ip_gateway, DEFAULT_IP_GATEWAY);
    }
    //printf("IP: %s\n", ip_addr);
    //printf("MASK: %s\n", ip_subnet);
    //printf("GW: %s\n", ip_gateway);
    //printf("TCP: %d\n", tcp_server_port);
    //printf("UDP: %d\n", udp_server_port);
}



int main()
{
    message_t message;
    int n, ret;
    
    /*
    * Configure
    */
    //uart.baud(115200);
    
  
    /*
    * UI threads
    */
    Thread t1(uart_thread);
    
    
    /*
    * FLASH
    */
    load_eeprom();
    IP_Addr = ip_addr;
    IP_Subnet = ip_subnet;
    IP_Gateway = ip_gateway;
    
        
    /*
    * Ethernet
    */
    ret = ethernet_init();
    if (ret) {
        printf("App halted\n");
        while (true) {};
    }
    
        
#ifdef TCP_SERVER
    TCPSocketServer tcp_server;
    TCPSocketConnection tcp_client;
    
    tcp_server.bind(tcp_server_port);
    tcp_server.listen();
    //uart.printf("\nWait for new connection...\n");
    tcp_server.set_blocking(false, TCP_SERVER_WAIT_CLIENT_TIMEOUT);
#endif
    
#ifdef UDP_SERVER
    UDPSocket udp_server;
    Endpoint ep_udp_client;
    
    ret = udp_server.bind(udp_server_port);
    //printf("sock.bind = %d\n", ret);
    udp_server.set_blocking(false, UDP_SERVER_RECEIVE_TIMEOUT);
#endif


    // Network processor
    while (true) {
// FOR INTERFACING
#ifdef TCP_SERVER
        // no tcp client connected
        if (!tcp_client.is_connected())
        {
            // wait for client within timeout
            ret = tcp_server.accept(tcp_client);
            
            // tcp client connected
            if (ret > -1) {
                //uart.printf("Connection from: %s\n", tcp_client.get_address());
                
                // loop waiting and receiving data within timeout
                tcp_client.set_blocking(false, TCP_SERVER_RECEIVE_TIMEOUT); // Timeout after x seconds
                while (true) {
                    n = tcp_client.receive(buffer, sizeof(buffer));
                    if (n <= 0) break;
                    
                    // got some data, test it
                    //// send to uart
                    //buffer[n] = '\0';
                    //message.len = n;
                    //message.msg = buffer;
                    //uart_queue.put(&message);
                    //// echo to tcp client
                    //tcp_client.send_all(buffer, n);
                    //if (n <= 0) break;
                    
                    // process received data
                    switch (n) {
                        // length 58-bytes, Receiving protocol
                        case 58: {
                            // check device id
                            char* id = strstr(buffer, DEVICE_ID);
                            if (id == NULL)
                                break;
                            else if ((id - buffer) > 0)
                                break;
                            
                            
                            // firstly, update outputs if required
                            // digital outputs
                            if (((uint8_t)buffer[RECEIVING_PROTOCOL_EN_DO_POS] - RECEIVING_PROTOCOL_ENABLE_OUTPUT) == 0) {
                            }
                            // analog output 0
                            if (((uint8_t)buffer[RECEIVING_PROTOCOL_EN_A0O_POS] - RECEIVING_PROTOCOL_ENABLE_OUTPUT) == 0) {
                            }
                            // analog output 0
                            if (((uint8_t)buffer[RECEIVING_PROTOCOL_EN_A1O_POS] - RECEIVING_PROTOCOL_ENABLE_OUTPUT) == 0) {
                            }
                            // UART
                            if (((uint8_t)buffer[RECEIVING_PROTOCOL_EN_UART_POS] - RECEIVING_PROTOCOL_ENABLE_OUTPUT) == 0) {
                            }
                            
                            // then, check query status command and sending protocol if required
                            if (((uint8_t)buffer[RECEIVING_PROTOCOL_COMMAND_POS] - QUERY_STATUS_COMMAND) == 0) {
                                // sending protocol
                            }
                            
                            break;
                        }
                        default:
                            break;
                    }
                    
                } // end loop if no data received within timeout
                tcp_client.close();
            } // if client connected
        } // if no client connected
#endif
    
    
    
// ONLY FOR CONFIGRATION
#ifdef UDP_SERVER
        // wait for udp packet within timeout
        n = udp_server.receiveFrom(ep_udp_client, buffer, sizeof(buffer));
        if (n <= 0) continue;

        // got some data, test it
        //// send to uart
        //buffer[n] = '\0';
        //message.len = n;
        //message.msg = buffer;
        //uart_queue.put(&message);
        //// echo
        //printf("Received packet from: %s\n", client.get_address());
        //udp_server.sendTo(ep_udp_client, buffer, n);
        
        // process received data
        switch (n) {
            // length = 6, a CONFIGURATION command (discovery command, TCP port, or UDP port)
            // Format: NNIODS, NNIOTP or NNIOUP
            case 6:
                // discovery command
                if (strstr(buffer, "NNIODS") != NULL) {
                    udp_server.sendTo(ep_udp_client, ip_addr, strlen(ip_addr));
                } // NNIODS
                // ask for TCP server port
                else if (strstr(buffer, "NNIOTP") != NULL) {
                    char port[5];
                    sprintf(port, "%5d", tcp_server_port);
                    udp_server.sendTo(ep_udp_client, port, strlen(port));
                } // NNIOTP
                // ask for UDP server port
                else if (strstr(buffer, "NNIOUP") != NULL) {
                    char port[5];
                    sprintf(port, "%5d", udp_server_port);
                    udp_server.sendTo(ep_udp_client, port, strlen(port));
                } // NNIOUP
                else if (strstr(buffer, "NNIOTM") != NULL) {
#ifdef NTP
                    char str_time[50];
                    
                    //printf("Trying to update time...\r\n");
                    if (ntp.setTime("0.pool.ntp.org") == 0) {
                        //printf("Set time successfully\r\n");
                        time_t ctTime;
                        ctTime = time(NULL);
                        
                        //printf("Time is set to (UTC): %s\r\n", ctime(&ctTime));
                        sprintf(str_time, "%s", ctime(&ctTime));
                        udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
                    }
                    else {
                        //printf("Error\r\n");
                        sprintf(str_time, "ERR");
                        udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
                    }
#elif
                    //printf("NTP disabled\r\n");
                    sprintf(str_time, "DIS");
                    udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
#endif
                } // NNIOTM

                break;
            // length = 19, SET NETWORK CONFIGURATION
            // Format: 4E 4E 49 4F      C0 A8 00 78        FF FF FF 00            C0 A8 00 01      00 00 01
            //        (NNIO;            IP: 192.168.0.120; Subnet: 255.255.255.0; GW: 192.168.0.1; MAC: 0 0 1)
            case 19:{
                // check device id
                char* id = strstr(buffer, DEVICE_ID);
                if (id == NULL)
                    break;
                else if ((id - buffer) > 0)
                    break;

                //printf("Received new network configuration\n");
                write_eeprom(&buffer[4]); // parameters from 3rd char, 15-bytes
                break;
            }
            default:
                break;
        }
#endif
    } // network processor
}