Library 52- Ethernet peripheral on STM32F4xx
One of the greatest features on STM32F4xx for me was to get ethernet to work properly as server and client. I got it working pretty quickly and I was investigating how to make a library to be very useful and easy to use.
Ethernet library is built on LwIP TCP/IP stack version 1.4.1.
Library is pretty hard to “install” for first time, so I decided to provide you source files (on my Github) for Keil uVision and Coocox.
Examples for Keil uVision and Coocox are finally available on my Github.
Library
Features
- Supports RMII or MII interface with PHY and STM32F4 ETH interface
- Built on LwIP TCP/IP stack
- Support for TCP client and TCP server
- 4 TCP client connections at a time
- Built-in support for opening files from SD card or any other source
- Support to disable server access to IP address
- DNS support for receive IP from domain
- DHCP support for receive IP in your network
- Support for custom device name on router
- Support for callbacks with full control on your work
- Callbacks for client (when connected, disconnected, data available, create headers)
- Callbacks for server (new client connected to server, disconnected)
- Callbacks for DNS (DNS has started, DNS has found IP)
- Callbacks for DHCP (DHCP has IP for us, DHCP error)
- Callbacks for link status (Link down, link up)
- Callbacks for POST requests
- Support for dynamic MAC address
- Support for STATIC/DYNAMIC IP address
- Support for monitoring how many bytes we sent/received over client/server mode
- Enable/Disable server mode
- User selectable PORT for server
- Support for SSI tags and CGI handlers
- SSI: You can display variables from MCU (RTC clock for example, LEDs status, etc)
- CGI: You can control MCU from web (control leds)
- Support for POST request
- Support for TCP communication between 2 STM devices without router using crossover cable
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx ETH (included in library)
- STM32F4xx SYSCFG
- TM
- DELAY
- GPIO
- defines.h
- attributes.h
- DELAY
- LwIP TCP/IP stack (Included in library)
Pinout
Ethernet works with ETH peripheral. For this purpose, you can’t use any STM32F4xx device (F401, F405, F411, F415 don’t have ethernet). As of version 1.1, MII or RMII connection is supported. In table below is RMII pinout with 2 possible pinspacks. Look a little bit below to see table for MII connection.
ETHERNET PHY | STM32F4xx | Description | |
---|---|---|---|
PINSPACK 1 | PINSPACK 2 | ||
MDIO | PA2 | PA2 | Management Data I/O pin |
MDC | PC1 | PC1 | Management Interface clock input |
REF_CLK | PA1 | PA1 | 50 MHz reference clock from PHY to STM32F4xx |
CRS | PA7 | PA7 | Carrier Receive/Sense Data Valid |
RX0 | PC4 | PC4 | Receive data line 0 |
RX1 | PC5 | PC5 | Receive data line 1 |
TX_EN | PB11 | PG11 | Enable transmitted |
TX0 | PB12 | PG13 | Transmit data line 0 |
TX1 | PB13 | PG14 | Transmit data line 1 |
PA8 | PA8 | Possible bug, check below |
Default pinout is the left one (PINSPACK1) but if you want for some reason right one, use define below:
1 2 3 |
/* defines.h file */ /* Enable PinsPack 2 for RMII ethernet */ #define ETHERNET_RMII_PINSPACK_2 |
Example works without problems on STM32F4-Discovery with pinspack1. To get it working on STM32F429-Discovery, you must “damage” your board. You must remove gyro and so on. Not nice to try it there. I have 2 boards F429, so I take apart one to get it working.
I believe, this is a bug, but if you can ensure me that is not, please report that to me:
- PA8 HAVE to be declared as MCO alternate function, even if not used for ethernet, or ETHERNET will not work.
- So keep in mind that if you don’t use this pin for ethernet source clock you shouldn’t connect anything to this pin.
- Some devices (like KSZ8081RNA can acceps 25MHz input clock and with internal PLL convert to 50MHz which is needed for RMII)
MII table
ETHERNET PHY | STM32F4xx | Description |
---|---|---|
MDIO | PA2 | Management Data I/O |
MDC | PC1 | Management Interface clock input |
REF_CLK | PA1 | 25 MHz reference clock from PHY to STM32F4xx |
CRS | PH2 | Carrier Receive/Sense Data Valid |
COL | PH3 | Collision |
PPS_OUT | PB5 | |
RXD0 | PC4 | Receive data 0 |
RXD1 | PC5 | Receive data 1 |
RXD2 | PH6 | Receive data 2 |
RXD3 | PH7 | Receive data 3 |
RX_ERR | PI10 | Receive error |
RX_DV | PA7 | RX Data valid |
RX_CLK | PC3 | RX clock |
TX_EN | PG11 | Transmit enable |
TXD0 | PG13 | Transmit data 0 |
TXD1 | PG14 | Transmit data 1 |
TXD2 | PC2 | Transmit data 2 |
TXD3 | PB8 | Transmit data 3 |
PA8 | Possible bug, check above |
After you design your board for MII mode, you have to enable it with my lib. Open defines.h file and add define:
1 2 |
/* Enable MII connection mode */ #define ETHERNET_MII_MODE |
ETHERNET PHY
Library was built in using DP83848 Ethernet PHY. I have 2 DP modules for testing on both discovery boards at the same time and works well on both.
You can get DP83848 module here.
PHY is connected to STM using RMII mode. Basically, every PHY should work with this configuration because they have standard registers locations inside. Of course, every PHY has something different but they should work from start.
According to the datasheet, I’ve made 3 supported PHY-s. To select your PHY, open defines.h file and make a define below:
1 2 3 4 5 6 7 |
/* * 0: DP83848 * 1: LAN8720A * 2: KSZ8081RNA */ /* If you want to use LAN8720A PHY, do this in defines.h file: */ #define ETHERNET_PHY 1 |
I also have some functions for ethernet PHYs, which can be used for set custom pinouts, which will overwrite default pinouts and function for setting custom PHY settings. In example below, LEDs configuration in DP83848 will be changed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * Called when ethernet peripheral is ready. * In this function, user can do other stuff, depending on PHY which is used in project. * * Example: * - Set LED mode for DP83848 PHY, or something else * * Parameters: * - uint32_t PHYAddress: * Phy address when using ETH_ReadPHYRegister and ETH_WritePHYRegister functions * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETPHY_CustomOptions(uint32_t PHYAddress); /** * Called on ethernet GPIO initialization * In this function, user can initialize custom pins, which will be used for communication with PHY. * Don't implement this function in case you want default pinout * * With __weak parameter to prevent link errors if not defined by user * * Must return 1 in case user has made own pins, or 0 in case we want default pins */ extern __weak uint8_t TM_ETHERNET_InitPinsCallback(void); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* PHY based callbacks */ void TM_ETHERNETPHY_CustomOptions(uint32_t PHYAddress) { /* Called when initialization for ethernet is done */ /* User can here do custom initialization settings, based on custom PHY */ /* Change LED mode on DP83848 for example */ uint32_t Reg_Val; //Read register 0x19 on DP83848 Reg_Val = ETH_ReadPHYRegister(PHYAddress, 0x19); //Clear both LED bits, SET led mode to 2, read DP83848 datasheet for more info Reg_Val &= ~(1 << 5 | 1 << 6); //Write new value to register ETH_WritePHYRegister(PHYAddress, 0x19, Reg_Val); } |
COMMON LIBRARY SETTINGS
In common I will set things which HAVE to be used, no matter which configuration you use. One of them is Initialize function, which is used to initialize LwIP TCP/IP stack and prepare Ethernet PHY in working state.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * Initialize ethernet device and prepare device to work. * * This function prepares LwIP stack to work and DP83848 PHY, * but does not enable server functionality. You have separate * function which enables server functionality in case you need it. * * Parameters: * - uint8_t* mac_addr: * Pointer to 6 bytes long array, if you want to select custom * MAC address, instead of one in in defines. * Useful if you have more than one device in one network * and you want to separate them by custom MAC (with their unique ID number) * Set to NULL for default value * - uint8_t* ip_addr: * Pointer to 4 bytes long array, if you want to select custom * IP address in case STATIC is used. This will also be used, * if DHCP can't get IP address * Set to NULL for default value * - uint8_t* gateway: * Pointer to 4 bytes long array, if you want to select custom gateway. * Set to NULL for default value * - uint8_t* netmask: * Pointer to 4 bytes long array, if you want to select custom netmask * Set to NULL for default value * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_Init(uint8_t* mac_addr, uint8_t* ip_addr, uint8_t* gateway, uint8_t* netmask); |
Function will return something from result enumeration. It’s structure is below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/** * Result enumeration used in ethernet library. * * Parameters: * - TM_ETHERNET_Result_Ok: * Everything is OK * - TM_ETHERNET_Result_Error: * An error occured * - TM_ETHERNET_Result_IPIsNotSetYet: * We don't have set IP * - TM_ETHERNET_Result_LinkIsDown: * Link is down * - TM_ETHERNET_Result_NeedHardReset: * We need hardware reset * - TM_ETHERNET_Result_LibraryNotInitialized: * Library is not initialized */ typedef enum { TM_ETHERNET_Result_Ok = 0, TM_ETHERNET_Result_Error, TM_ETHERNET_Result_IPIsNotSetYet, TM_ETHERNET_Result_LinkIsDown, TM_ETHERNET_Result_NeedHardReset, TM_ETHERNET_Result_LibraryNotInitialized } TM_ETHERNET_Result_t; |
To be able to get ethernet properly in working state, you also have several functions which HAVE TO be called.
First function is Ethernet update which is used to update LwIP stack, and second is Time update which is used to update “local time” for LwIP stack. They are below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * Update ethernet LwIP stack * * This function should be called periodically, as fast as possible. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_Update(void); /** * This function should be called in specific time period for LwIP stack * * Parameters: * - uint16_t millis: * Number of milliseconds, that will be added to LwIP stack. * This value should be the same as period for your interrupt (Systick) timer is * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_TimeUpdate(uint16_t millis); |
Both function must be called periodically. Time update must be called in specific time. According to periodic time you call it, you have parameter for millis. If you call this function every 10ms, then pass into function parameter “10” which will increase local time for 10ms.
Update function should be called as fast as possible. It’s not necessary to call it at specific time intervals.
You might also use other common functions, which are described below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
/** * This function can be used to test if you are ready to work as server or client. * * Returns: * - TM_ETHERNET_Result_Ok: In case link is up and ip is set (static or DHCP) * - TM_ETHERNET_Result_Error: On other cases */ extern TM_ETHERNET_Result_t TM_ETHERNET_TestReady(void); /** * Check if device has static IP * * Returns 1 if it is static or 0 if not (DHCP) */ #define TM_ETHERNET_IsIPStatic() (TM_ETHERNET.staticip) /** * Check if device has 100Mbit network connection * * Returns 1 if it has, or 0 if not */ #define TM_ETHERNET_Is100M() (TM_ETHERNET.speed_100m) /** * Check if device is in full duplex mode * * Returns 1 if it is or 0 if not */ #define TM_ETHERNET_IsFullDuplex() (TM_ETHERNET.full_duplex) /** * Get local IP address * * Parameters: * - uint8_t x: * IP section, 0 to 3 are allowed. 0 is MSB and 3 is LSB * * IP address is returned */ #define TM_ETHERNET_GetLocalIP(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.ip_addr[(x)] : 0) /** * Get MAC address * * Parameters: * - uint8_t x: * MAC section, 0 to 5 are allowed. 0 is MSB and 5 is LSB * * MAC address is returned */ #define TM_ETHERNET_GetMACAddr(x) (((x) >= 0 && (x) < 6) ? TM_ETHERNET.mac_addr[(x)] : 0) /** * Get gateway address * * Parameters: * - uint8_t x: * Gateway section, 0 to 3 are allowed. 0 is MSB and 3 is LSB * * Gateway is returned */ #define TM_ETHERNET_GetGateway(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.gateway[(x)] : 0) /** * Get netmask address * * Parameters: * - uint8_t x: * Netmask section, 0 to 4 are allowed. 0 is MSB and 3 is LSB * * Net mask is returned */ #define TM_ETHERNET_GetNetmask(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.netmask[(x)] : 0) |
DEFAULT NETWORK SETTINGS
Each device in your network has own MAC address and IP address, default gateway and netmask address.
My library allows you to set “dynamic” or “static” MAC address and IP.
Dynamic MAC means, that you apply MAC address when you initialize library (useful in case you have more than just one device in one network and you need different MAC addresses, you can use unique ID inside STM32F4). In case of STATIC MAC, you can set it using defines which are in my lib. In case you want to overwrite it, you can do this (defines.h file):
1 2 3 4 5 6 7 8 9 10 |
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ /* In case you want to use custom MAC, use parameter in init function */ #ifndef MAC_ADDR0 #define MAC_ADDR0 0x06 #define MAC_ADDR1 0x05 #define MAC_ADDR2 0x04 #define MAC_ADDR3 0x03 #define MAC_ADDR4 0x02 #define MAC_ADDR5 0x01 #endif |
So, the same thing you can apply for other 3 settings too. All settings are below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */ /* Used in case DHCP is not used or response failed */ /* In case you want to use custom IP, use parameter in init function */ #ifndef IP_ADDR0 #define IP_ADDR0 192 #define IP_ADDR1 168 #define IP_ADDR2 0 #define IP_ADDR3 120 #endif /* NETMASK */ /* In case you want to use custom netmask, use parameter in init function */ #ifndef NETMASK_ADDR0 #define NETMASK_ADDR0 255 #define NETMASK_ADDR1 255 #define NETMASK_ADDR2 255 #define NETMASK_ADDR3 0 #endif /* Gateway Address */ /* In case you want to use custom gateway, use parameter in init function */ #ifndef GW_ADDR0 #define GW_ADDR0 192 #define GW_ADDR1 168 #define GW_ADDR2 0 #define GW_ADDR3 1 #endif |
DHCP
DHCP is a great protocol, which can be used to assign device IP from your router. This basically means, that you (STM device) sends packet to router with “I want IP address” and then router sends you IP address and question “Is this IP OK?”. If it is OK, STM returns “Ok” and IP is assigned.
By default, DHCP assignment is disabled in my library, so IP which is set on defines (chapter above) or passed on initialization function is used. If you want to activate DHCP features, open defines.h file and add line below:
1 2 |
/* Enable DHCP IP assignment */ #define ETHERNET_USE_DHCP |
One feature, you can use with DHCP, is that when you request a IP with DHCP, then you are displayed in control panel of your router. You can see device name and it’s IP and MAC address.
My library allows you, that you choose device name, which will be displayed in your router DHCP client list:
1 2 |
/* Device name which will be seen in router when requesting IP via DHCP */ #define ETHERNET_HOSTNAME_DHCP "F4-Discovery" |
DHCP is also a part of my callback functions.
If DHCP is enabled, when it will start with IP assignment, callback will be called.
1 2 3 4 5 6 7 8 9 10 |
/** * DHCP start callback * * This function is called when DHCP starts with IP address assigning for device. * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_DHCPStartCallback(void); |
DHCP makes 4 tries to get IP. If it fails, or not, a IP is set callback is called, which can be defined by user.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * IP is set callback * This function is called when IP is assigned to device. * * It is called in case DHCP is used or static ip is used. * It can be used to store IP address, if you use DHCP dynamic IP address. * * Parameters: * - uint8_t ip_addr1: * - uint8_t ip_addr2: * - uint8_t ip_addr3: * - uint8_t ip_addr4: * IP addresses. ip_addr1 is MSB, ip_addr4 is LSB * - uint8_t dhcp: * This is set to 1 in case DHCP has been used for IP assign or 0 if static is used in case of user select or error * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_IPIsSetCallback(uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4, uint8_t dhcp); |
DNS
Another great feature in my lib is DNS. Domain Name Server allows you to get IP address from given doman name. For example, if you want to get IP address for “stm32f4-discovery.net” domain, you call DNS function and packet will be sent to DNS servers, with IP response (84.255.255.84).
To start DNS request, call my function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** * DNS Get host by name * * This function can be used to get IP address by passing it's domain name to it. * * Different DNS callback functions will be called, depending on what will happen with DNS. * * Parameters: * - char* host_name: * Domain name for which you need IP address. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETDNS_GetHostByName(char* host_name); |
Function uses 2 callbacks in case DNS status. One callback is called when DNS found IP address, second is to told user that we have error:
- IP address is not found
- Invalid data passed to DNS function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/** * DNS Found callback * * This function will be called when DNS server has valid IP address for your domain request. * It can be useful to make first connection in this function when you know your IP address where you must connect to. * * Parameters: * - char* host_name: * The same host name as you use for DNS requesting, can't be larger than ETHERNET_MAX_CONNECTION_NAME define * - uint8_t ip_addr1: * IP address 1st byte, MSB * - uint8_t ip_addr2: * IP address 2nd byte * - uint8_t ip_addr3: * IP address 3rd byte * - uint8_t ip_addr4: * IP address 4th byte, LSB * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETDNS_FoundCallback(char* host_name, uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4); /** * DNS error callback * * This function will be called when DNS error occured. * Possible errors are: * - Requested domain does not exists, * - You have bad parameters in DNS function call * * Parameters: * - char* host_name: * Host name where an error occured * * No return */ extern __weak void TM_ETHERNETDNS_ErrorCallback(char* host_name); |
CLIENT
Client mode is one of 2 main features of ethernet. With client mode, you can request and receive data from another server, for example, you can make “data logger” which will make GET request method to another server where you want to collect and store your data.
So when you are ready (IP is set) you can start with connection to another server at desired IP and port. Library allows you to make 4 connections at the same time. So you can call Connect function 4 times before any connection is closed.
To connect, call function below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** * Make TCP CLIENT Connection to external server. * * After this call, different client callbacks will be called depending on what will happen. * * Parameters: * - char* conn_name: * Connection name. This value will be then passed to all client based handlers * - uint8_t ip1: * - uint8_t ip2: * - uint8_t ip3: * - uint8_t ip4: * IP addresses. ip1 is MSB, ip4 is LSB * - uint16_t port: * Port to which we want connect to server * - void* user_parameters: * Pointer to user data to be passed to this function. * This data will be used in all client based callbacks inside TM_TCPCLIENT_t pointer variable * Use NULL in case you don't want to pass any data. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETCLIENT_Connect(char* conn_name, uint8_t ip1, uint8_t ip2, uint8_t ip3, uint8_t ip4, uint16_t port, void* user_parameters); |
Function will start a TCP connection to specific IP address and PORT. Remember, this function must return TM_ETHERNET_Result_Ok which means that function succedded. In case it returns anything else, connect won’t work.
Another thing here are client callbacks. Because connecting to some server may take a while, but STM is too fast for waiting callbacks are used here. I’ve made several callbacks. Here are just defines, how to use it you will see on examples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
/** * Create headers callback * This function is called when connection is prepared to send some headers data to server which is waiting for response. * * If function is not implemented, then default headers are sent. * * Default headers: * GET / HTTP/1.1\r\n * Host: TM_ETHERNETClient\r\n * Connection: close\r\n * \r\n * * Parameters for function: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contains current connection specifications. * - char* buffer: * Char memory buffer where to store your header data * - uint16_t buffer_length: * Maximal memory length for your header data * * With __weak parameter to prevent link errors if not defined by user * * Function must return number of characters written in buffer. * If you return 0 (zero) then connection will be closed. * Buffer length can't be larger than ETHERNET_MAX_HEADER_SIZE define */ extern __weak uint16_t TM_ETHERNETCLIENT_CreateHeadersCallback(TM_TCPCLIENT_t* connection, char* buffer, uint16_t buffer_length); /** * Receive data callback * * This function is called when we have data available to be received. * It might happen that it will be called multiple times for one request, depends on server's response and length of data. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection's specifications. * - uint8_t* buffer: * Memory buffer * - uint16_t buffer_length: * Number of characters in buffer * - uint16_t total_length * Number of unread data. If this value is the same as buffer_length, then no remaining data is available in packet * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ReceiveDataCallback(TM_TCPCLIENT_t* connection, uint8_t* buffer, uint16_t buffer_length, uint16_t total_length); /** * Connected callback * * This function is called when device is connected to specific server. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contains current connection's specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectedCallback(TM_TCPCLIENT_t* connection); /** * Connection closed callback * * This function is called when connection is closed and you are ready to make a new one. * You can also detect, if connection was closed after success or error. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * - uint8_t success: * It is set to 1 if connection was closed after successfull transmission * or 0 if because of failure * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectionClosedCallback(TM_TCPCLIENT_t* connection, uint8_t success); /** * Error callback * * This function is called when an error occured. * It will be called in case when IP address is not available * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ErrorCallback(TM_TCPCLIENT_t* connection); /** * Connection started callback * * This function will be called when connection to server has started * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectionStartedCallback(TM_TCPCLIENT_t* connection); |
Every client callback, has first parameter TM_TCPCLIENT_t* connection. This is special structure, which is used for client to easily work with multiple connections at a time. It’s structure is below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/** * Client structure, passed as first parameter in all client based callback functions * * Parameters: * - char name[ETHERNET_MAX_CONNECTION_NAME]: * Connection name, we choose it when we call TM_ETHERNETCLIENT_Connect function * - uint8_t active: * Connection is active * - uint8_t ip_addr[4]: * IP address for our external connection * - uint16_t port: * Port for our external connection * - uint8_t headers_done: * This is user defined option. * When you connect to some website and receive data back, you will also get HTTP headers and your data. * When receive data handler will be first called, this parameter will be set to 0. * If you detect when headers are done ("\r\n\r\n" string) then you can set this parameter to 1, * and it will stay 1 until connection is closed. This can be used, if you don't want to print headers to user. * - uint8_t* active_connections_count: * Pointer to number of active connections this time. * - void* user_parameters: * Pointer to user parameters for connection which are passed on "Connect" function * This can be used to pass special data for your connection, which you can then easily be used in headers callback * to format proper request string. */ typedef struct { char name[ETHERNET_MAX_CONNECTION_NAME]; uint8_t active; uint8_t ip_addr[4]; uint16_t port; uint8_t headers_done; uint8_t* active_connections_count; void* user_parameters; /* Private use */ struct tcp_pcb* pcb; client_states state; struct pbuf *p_tx; } TM_TCPCLIENT_t; |
You might want to know some time how many data you sent/receive as a client over ethernet and how many connections you’ve made as a client. I’ve made some macro functions, which can be used in your project:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * Get total number of sent bytes when you are client * * Returns number of transmitted bytes as a client */ #define TM_ETHERNETCLIENT_GetTXBytes() (TM_ETHERNET.Client_TX_Bytes) /** * Get total number of received bytes when you are client * * Returns number of received bytes as a client */ #define TM_ETHERNETCLIENT_GetRXBytes() (TM_ETHERNET.Client_RX_Bytes) /** * Get number of all connections done as a client * * Returns number of all connections done as a client */ #define TM_ETHERNETCLIENT_GetConnectionsCount() (TM_ETHERNET.ClientConnections) /** * Get number of all successfull connections done as a client * * Returns number of all successfull connections done as a client */ #define TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount() (TM_ETHERNET.ClientSuccessfullConnections) |
SERVER
Server mode is a little bit difficult for explain it’s configuration, but I will try to be clear.
First, when you initialize library, server is disabled. Because, you don’t want that someone just come to your device if you don’t want. if you want to use server mode, then you have to enable it and tell on which PORT you will use your server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * Enable and prepare LwIP stack for server functionality. * Before you can use this function, you have to initialize LwIP stack * with TM_ETHERNET_Init() function. * * Parameters: * - uint16_t server_port: * Select your port on which you want to operate. * Set this variable to 0 and last used PORT will be selected * If you call this function multiple times, only first time will work this parameter * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_Enable(uint16_t server_port); /** * Disable and stop LwIP stack from server functionality. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_Disable(void); |
Enable function is a little bit weird I would say. So only first time parameter will work. It means, that if you call this function multiple times, PORT will be used the one, which was used on first function call. Future calls don’t have affect of this parameter.
Ok, our server is enabled, and is accessible on our local IP. You can get local IP address using TM_ETHERNET_GetLocalIP function. But, it has no effect, if we don’t show anything to user.
In file fsdata.c are 3 files, which are displayed to user in case you don’t make your own. They are just for demonstration and I suggest you to remove them, or at least short data to minimum to free memory in flash.
The useful feature become when you are able to open custom files (from SD card or USB flash). This library allows you this also. It is designed to allow 10 opened files at a time by default. If you want to change this, open defines.h file and change:
1 2 |
/* Maximal number of opened files at a time as server */ #define ETHERNET_MAX_OPEN_FILES 10 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/** * Called when user based file should be open when new client is connected * If you want to use server on your SDcard or USB flash or whatever, * here you can open file and do the stuff. * * Note: You must set file->len parameter to your file size number! * * If You don't open file (return 0) then default file in flash will be used, * that will say "Hello world from default server file", stored in fsdata.c. * * Only one file at a time will be opened, so if you need to mount card, * you can mount it in this function also. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * - const char *name: * File name that should be opened * * With __weak parameter to prevent link errors if not defined by user * * Return 0 in case you can't/don't want to open file, or 1 if file is successfully opened */ extern __weak int TM_ETHERNETSERVER_OpenFileCallback(struct fs_file* file, const char *name); /** * Called when reading file is finished and file can be closed. * * If you need to unmount your SD card, you can do it here. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETSERVER_CloseFileCallback(struct fs_file* file); /** * Called when file should be read. * This function may be called more than just one time, depends on file length. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * - char *buffer: * Pointer to buffer, where you should save your data * - int count: * Number of data that should be read. * You can read less than this number. This is max number you can read this time. * * With __weak parameter to prevent link errors if not defined by user * * Returns number of read data, or -1 (EOF) if file has end. */ extern __weak int TM_ETHERNETSERVER_ReadFileCallback(struct fs_file* file, char* buffer, int count); |
In the examples below, you will see how to implement server with FatFs library from Chan. Which file should be opened will LwIP tell to you, you just have to make sure that you open file (if existing) that is in parameter.
All 3 functions have special file pointer parameter. It’s structure is below:
1 2 3 4 5 6 7 8 9 10 11 |
struct fs_file { const char *data; int len; int index; void* pextension; uint8_t id; uint16_t* opened_files_count; u8_t http_header_included; u8_t is_custom_file; char file_name[ETHERNET_SERVER_MAX_CUSTOM_FILENAME]; }; |
Like client, server has also some other callbacks to work with connected clients. One of them is to know, when client is connected or disconnected. It allows you to block access to client if you detect bad remote IP address. Callbacks below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/** * Called when new client is connected to server * This function can be used, to block IP address. * IP address, from where user access to your server is stored in *pcb variable * * remote_ip = pcb->remote_ip.addr * * You can check here for your blocked IP addresses * * Parameters: * - struct tcp_pcb *pcb: * Pointer to active LwIP PCB structure * * With __weak parameter to prevent link errors if not defined by user * * This function must return 1 if you want to allow connection, * or 0 if you want to deny access to your web. */ extern __weak uint8_t TM_ETHERNETSERVER_ClientConnectedCallback(struct tcp_pcb *pcb); /** * Called when new client is diconnected from server (Or connection closed) * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETSERVER_ClientDisconnectedCallback(void); |
Other statistical functions which correspond to server are below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/** * Check if server mode is enabled. * * Returns 1 if active, or 0 if not */ #define TM_ETHERNETSERVER_Enabled() (TM_ETHERNET.server_active) /** * Get port number on which server is active * * Returns port number on which server is active */ #define TM_ETHERNETSERVER_GetPortNumber() (TM_ETHERNET.server_port) /** * Get number of all sent bytes from server to client * * Returns number of sent bytes from server to client */ #define TM_ETHERNETSERVER_GetTXBytes() (TM_ETHERNET.Server_TX_Bytes) /** * Get number of all received bytes from client to server * * Returns number of received bytes from client to server */ #define TM_ETHERNETSERVER_GetRXBytes() (TM_ETHERNET.Server_RX_Bytes) /** * Get number of all connections that have been made to server * * Returns number of connections made to server */ #define TM_ETHERNETSERVER_GetConnectionsCount() (TM_ETHERNET.Server_Connections) |
Our server works, web site is displayed to user.
Two most asked questions now probably are:
- How to display useful data to user?
- How to control device over ethernet?
Answers:
- To display useful data to user (temperature, whatever…) you SSI tags
- To control device (leds, PWM, whatever…), use CGI handlers
SSI TAGS
Let’s say, that you have website and when user access to your server, you want to display current temperature to him. You will have to assign new SSI tag and pass it into SetSSITags function, which will be described below.
Then, in your HTML code, you need to add SSI tag also, which will then be replaced by LwIP to useful data.
For example, you define SSI tag in your code, named “temperature“.
Then, in your HTML code, where you want to display it, you have to do this: <p><!–#temperature–></p>
Important is part in bold text. Other is just normal HTML which you wanna use.
Note:
- SSI tags only works if your file name ends with .shtml, .shtm or .ssi
- SSI tags can’t be unlimited long
- SSI response text can’t be unlimited long
1 2 3 4 5 6 7 8 9 10 |
/* Maximal length for SSI tag used in HTML */ #ifndef ETHERNET_SSI_MAX_TAG_LEN #define ETHERNET_SSI_MAX_TAG_LEN 32 #endif /* Maximal buffer length for SSI tag insert text */ /* Content of buffer will be replaced with SSI tag */ #ifndef ETHERNET_SSI_MAX_TAG_INSERT_LEN #define ETHERNET_SSI_MAX_TAG_INSERT_LEN 512 #endif |
Now, you have tags defines and place into code. Next step is to set some data when this tag is found by LwIP in code. When SSI tag should be placed into code, my function for SSI will be called. This is fixed name function and is only one function for all SSI tags in your code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/** * Set SSI tags, which will be used in your HTML files for displaying variables on website. * * For more about SSI tags, you can check chapter 4.2 on link below: * http://www.state-machine.com/lwip/AN_QP_and_lwIP.pdf * * Note: SSI tags only work if your file name ends with .shtm, .shtml, or .ssi! * * This function can be called only once, future calls will be denied! * * Parameters: * - TM_ETHERNET_SSI_t* tags: * Pointer to array of pointers for tags that are used in your html files * - uint16_t number_of_tags: * Number of tags in your array * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_SetSSITags(TM_ETHERNET_SSI_t* tags, uint16_t number_of_tags); /** * SSI callbacks for ethernet server * * This function is called, when ethernet server wants to serve tag you pass in TM_ETHERNETSERVER_SetSSITags() function. * * Parameters: * - int iIndex: * Tag index number. They are specified in order you pass to TM_ETHERNETSERVER_SetSSITags function * - char *pcInsert: * Pointer where you should set your content that will be displayed where your tag is specified in files * - int iInsertLen: * Max string length * * With __weak parameter to prevent link errors if not defined by user * * Must return number of characters in your pcInsert pointer. */ extern __weak uint16_t TM_ETHERNETSERVER_SSICallback(int iIndex, char *pcInsert, int iInsertLen); |
In examples below, you will see how to use tags in practise.
CGI HANDLERS
CGI handlers are a simple way to control your STM device over ethernet. They are a way on how to handle GET method with url link this: /my_url.cgi?ledon=1&ledoff=3&ledtoggle=4
You can use more than just one CGI handler. CGI handler is called when you access to a URL which ends with .cgi. In our case we have “my_url.cgi” and let’s assign function which will be called on CGI call.
It will look something like that:
1 2 3 4 5 6 7 8 9 |
/* LED/RELAY CGI handlers */ const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); const char * RELAY_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); /* CGI call table, 2 CGIs used */ TM_ETHERNET_CGI_t CGI_Handlers[] = { {"/ledaction.cgi", LEDS_CGI_Handler}, /* LEDS_CGI_Handler will be called when user connects to "/ledaction.cgi" URL */ {"/relayaction.cgi", LEDS_CGI_Handler}, /* RELAY_CGI_Handler will be called when user connects to "/relayaction.cgi" URL */ }; |
More about that will be clear when I show you an example
POST HANDLER
My library can also handle POST requests but I don’t suggest to use this. It is not 100% stable for now, and I will not describe how to use it yet.
Functions and enumerations
Here are described all functions and enumerations. It’s long part so they are hidden by default.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
/* Ethernet PHY used in your project */ /* Default value is DP83848 */ #ifndef ETHERNET_PHY #define ETHERNET_PHY 0 #endif /* Check for link status every 1000ms */ #ifndef LINK_TIMER_INTERVAL #define LINK_TIMER_INTERVAL 1000 #endif /* Default server PORT used */ #ifndef ETHERNET_SERVER_PORT #define ETHERNET_SERVER_PORT 80 #endif /* Include server based options */ #include "httpd.h" #include "fs.h" /* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ /* In case you want to use custom MAC, use parameter in init function */ #ifndef MAC_ADDR0 #define MAC_ADDR0 0x06 #define MAC_ADDR1 0x05 #define MAC_ADDR2 0x04 #define MAC_ADDR3 0x03 #define MAC_ADDR4 0x02 #define MAC_ADDR5 0x01 #endif /* Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */ /* Used in case DHCP is not used or response failed */ /* In case you want to use custom IP, use parameter in init function */ #ifndef IP_ADDR0 #define IP_ADDR0 192 #define IP_ADDR1 168 #define IP_ADDR2 0 #define IP_ADDR3 120 #endif /* NETMASK */ /* In case you want to use custom netmask, use parameter in init function */ #ifndef NETMASK_ADDR0 #define NETMASK_ADDR0 255 #define NETMASK_ADDR1 255 #define NETMASK_ADDR2 255 #define NETMASK_ADDR3 0 #endif /* Gateway Address */ /* In case you want to use custom gateway, use parameter in init function */ #ifndef GW_ADDR0 #define GW_ADDR0 192 #define GW_ADDR1 168 #define GW_ADDR2 0 #define GW_ADDR3 1 #endif /* Device name which will be seen in router when requesting IP via DHCP */ #ifndef ETHERNET_HOSTNAME_DHCP #define ETHERNET_HOSTNAME_DHCP "TM-ETH-Device" #endif /* RMII mode by default */ #if !defined(ETHERNET_MII_MODE) && !defined(ETHERNET_RMII_MODE) #define ETHERNET_RMII_MODE #endif /* Buffer size for ethernet headers when requesting as client */ /* Used for headers after you are connected to server, HTTP headers */ /* Ex: GET / HTTP/1.1\r\n...etc */ #ifndef ETHERNET_MAX_HEADER_SIZE #define ETHERNET_MAX_HEADER_SIZE 1024 #endif /* Max connection string name when connection as client */ /* This is also max domain name when using DNS request */ #ifndef ETHERNET_MAX_CONNECTION_NAME #define ETHERNET_MAX_CONNECTION_NAME 100 #endif /* Maximal number of opened files at a time as server */ #ifndef ETHERNET_MAX_OPEN_FILES #define ETHERNET_MAX_OPEN_FILES 10 #endif /* Maximal length for SSI tag used in HTML */ #ifndef ETHERNET_SSI_MAX_TAG_LEN #define ETHERNET_SSI_MAX_TAG_LEN 32 #endif /* Maximal buffer length for SSI tag insert text */ /* Content of buffer will be replaced with SSI tag */ #ifndef ETHERNET_SSI_MAX_TAG_INSERT_LEN #define ETHERNET_SSI_MAX_TAG_INSERT_LEN 512 #endif /* Internal struct which should not be used by user */ typedef struct { uint8_t ip_addr[4]; uint8_t mac_addr[6]; uint8_t netmask[4]; uint8_t gateway[4]; uint8_t staticip; uint8_t ip_is_set; uint8_t link_is_up; uint32_t ClientSuccessfullConnections, ClientConnections; uint64_t Client_TX_Bytes, Client_RX_Bytes; uint32_t Server_Connections; uint64_t Server_TX_Bytes, Server_RX_Bytes; uint8_t server_active; uint16_t server_port; uint8_t speed_100m; uint8_t full_duplex; } TM_ETHERNET_t; extern TM_ETHERNET_t TM_ETHERNET; /* Client protocol states */ /* For private use */ typedef enum { CLIENT_NOT_CONNECTED = 0, CLIENT_CONNECTED, CLIENT_RECEIVED, CLIENT_CLOSING, } client_states; /** * Client structure, passed as first parameter in all client based callback functions * * Parameters: * - char name[ETHERNET_MAX_CONNECTION_NAME]: * Connection name, we choose it when we call TM_ETHERNETCLIENT_Connect function * - uint8_t active: * Connection is active * - uint8_t ip_addr[4]: * IP address for our external connection * - uint16_t port: * Port for our external connection * - uint8_t headers_done: * This is user defined option. * When you connect to some website and receive data back, you will also get HTTP headers and your data. * When receive data handler will be first called, this parameter will be set to 0. * If you detect when headers are done ("\r\n\r\n" string) then you can set this parameter to 1, * and it will stay 1 until connection is closed. This can be used, if you don't want to print headers to user. * - uint8_t* active_connections_count: * Pointer to number of active connections this time. * - void* user_parameters: * Pointer to user parameters for connection which are passed on "Connect" function * This can be used to pass special data for your connection, which you can then easily be used in headers callback * to format proper request string. */ typedef struct { char name[ETHERNET_MAX_CONNECTION_NAME]; uint8_t active; uint8_t ip_addr[4]; uint16_t port; uint8_t headers_done; uint8_t* active_connections_count; void* user_parameters; /* Private use */ struct tcp_pcb* pcb; client_states state; struct pbuf *p_tx; } TM_TCPCLIENT_t; /** * POST request structure * Used in POST request callbacks * * Parameters: * - void *connection: * Pointer to connection, it is type of struct http_state * * - const char* uri: * URL which is used in POST request * URL user use with POST request * - const char* http_request: * Pointer to HTTP request buffer. * Here are stored entire HTTP request headers * - uint16_t http_request_len: * Length of HTTP request buffer * - int content_len: * Length of content (data) in bytes * - char* response_uri: * Pointer to address (file address, "/index.html" for example) which will be used to show url to user. * This parameter must be filled by user * - uint16_t response_uri_len: * Length of buffer for response uri */ typedef struct { void* connection; const char* uri; const char* http_request; uint16_t http_request_len; int content_len; char* response_uri; uint16_t response_uri_len; } TM_ETHERNETPOST_t; /** * Result enumeration used in ethernet library. * * Parameters: * - TM_ETHERNET_Result_Ok: * Everything is OK * - TM_ETHERNET_Result_Error: * An error occured * - TM_ETHERNET_Result_IPIsNotSetYet: * We don't have set IP * - TM_ETHERNET_Result_LinkIsDown: * Link is down * - TM_ETHERNET_Result_NeedHardReset: * We need hardware reset * - TM_ETHERNET_Result_LibraryNotInitialized: * Library is not initialized */ typedef enum { TM_ETHERNET_Result_Ok = 0, TM_ETHERNET_Result_Error, TM_ETHERNET_Result_IPIsNotSetYet, TM_ETHERNET_Result_LinkIsDown, TM_ETHERNET_Result_NeedHardReset, TM_ETHERNET_Result_LibraryNotInitialized } TM_ETHERNET_Result_t; /* Additional typedefs */ /* User friendly typedef for SSI tags */ typedef const char * TM_ETHERNET_SSI_t; /* User friendly typedef for CGI tags */ /** * Structure is as following: * * Parameters: * - const char *pcCGIName: * Link, when handler function will be called, "/leds.cgi" for example * - tCGIHandler pfnCGIHandler: * Function handler, which will be called when user access to some link * * Handler function looks like this: * const char * HandlerFunctionName(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) * * Function must return "URL" which will be displayed to user, for example "/index.html" to show first site */ typedef tCGI TM_ETHERNET_CGI_t; /* Ethernet */ /** * Initialize ethernet device and prepare device to work. * * This function prepares LwIP stack to work and DP83848 PHY, * but does not enable server functionality. You have separate * function which enables server functionality in case you need it. * * Parameters: * - uint8_t* mac_addr: * Pointer to 6 bytes long array, if you want to select custom * MAC address, instead of one in in defines. * Useful if you have more than one device in one network * and you want to separate them by custom MAC (with their unique ID number) * Set to NULL for default value * - uint8_t* ip_addr: * Pointer to 4 bytes long array, if you want to select custom * IP address in case STATIC is used. This will also be used, * if DHCP can't get IP address * Set to NULL for default value * - uint8_t* gateway: * Pointer to 4 bytes long array, if you want to select custom gateway. * Set to NULL for default value * - uint8_t* netmask: * Pointer to 4 bytes long array, if you want to select custom netmask * Set to NULL for default value * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_Init(uint8_t* mac_addr, uint8_t* ip_addr, uint8_t* gateway, uint8_t* netmask); /** * Update ethernet LwIP stack * * This function should be called periodically, as fast as possible. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_Update(void); /** * This function should be called in specific time period for LwIP stack * * Parameters: * - uint16_t millis: * Number of milliseconds, that will be added to LwIP stack. * This value should be the same as period for your interrupt (Systick) timer is * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNET_TimeUpdate(uint16_t millis); /** * This function can be used to test if you are ready to work as server or client. * * Returns: * - TM_ETHERNET_Result_Ok: In case link is up and ip is set (static or DHCP) * - TM_ETHERNET_Result_Error: On other cases */ extern TM_ETHERNET_Result_t TM_ETHERNET_TestReady(void); /** * Check if device has static IP * * Returns 1 if it is static or 0 if not (DHCP) */ #define TM_ETHERNET_IsIPStatic() (TM_ETHERNET.staticip) /** * Check if device has 100Mbit network connection * * Returns 1 if it has, or 0 if not */ #define TM_ETHERNET_Is100M() (TM_ETHERNET.speed_100m) /** * Check if device is in full duplex mode * * Returns 1 if it is or 0 if not */ #define TM_ETHERNET_IsFullDuplex() (TM_ETHERNET.full_duplex) /** * Get local IP address * * Parameters: * - uint8_t x: * IP section, 0 to 3 are allowed. 0 is MSB and 3 is LSB * * IP address is returned */ #define TM_ETHERNET_GetLocalIP(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.ip_addr[(x)] : 0) /** * Get MAC address * * Parameters: * - uint8_t x: * MAC section, 0 to 5 are allowed. 0 is MSB and 5 is LSB * * MAC address is returned */ #define TM_ETHERNET_GetMACAddr(x) (((x) >= 0 && (x) < 6) ? TM_ETHERNET.mac_addr[(x)] : 0) /** * Get gateway address * * Parameters: * - uint8_t x: * Gateway section, 0 to 3 are allowed. 0 is MSB and 3 is LSB * * Gateway is returned */ #define TM_ETHERNET_GetGateway(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.gateway[(x)] : 0) /** * Get netmask address * * Parameters: * - uint8_t x: * Netmask section, 0 to 4 are allowed. 0 is MSB and 3 is LSB * * Net mask is returned */ #define TM_ETHERNET_GetNetmask(x) (((x) >= 0 && (x) < 4) ? TM_ETHERNET.netmask[(x)] : 0) /* Server based functions */ /** * Enable and prepare LwIP stack for server functionality. * Before you can use this function, you have to initialize LwIP stack * with TM_ETHERNET_Init() function. * * Parameters: * - uint16_t server_port: * Select your port on which you want to operate. * Set this variable to 0 and last used PORT will be selected * If you call this function multiple times, only first time will work this parameter * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_Enable(uint16_t server_port); /** * Disable and stop LwIP stack from server functionality. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_Disable(void); /** * Check if server mode is enabled. * * Returns 1 if active, or 0 if not */ #define TM_ETHERNETSERVER_Enabled() (TM_ETHERNET.server_active) /** * Get port number on which server is active * * Returns port number on which server is active */ #define TM_ETHERNETSERVER_GetPortNumber() (TM_ETHERNET.server_port) /** * Get number of all sent bytes from server to client * * Returns number of sent bytes from server to client */ #define TM_ETHERNETSERVER_GetTXBytes() (TM_ETHERNET.Server_TX_Bytes) /** * Get number of all received bytes from client to server * * Returns number of received bytes from client to server */ #define TM_ETHERNETSERVER_GetRXBytes() (TM_ETHERNET.Server_RX_Bytes) /** * Get number of all connections that have been made to server * * Returns number of connections made to server */ #define TM_ETHERNETSERVER_GetConnectionsCount() (TM_ETHERNET.Server_Connections) /** * Set SSI tags, which will be used in your HTML files for displaying variables on website. * * For more about SSI tags, you can check chapter 4.2 on link below: * http://www.state-machine.com/lwip/AN_QP_and_lwIP.pdf * * Note: SSI tags only work if your file name ends with .shtm, .shtml, or .ssi! * * This function can be called only once, future calls will be denied! * * Parameters: * - TM_ETHERNET_SSI_t* tags: * Pointer to array of pointers for tags that are used in your html files * - uint16_t number_of_tags: * Number of tags in your array * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_SetSSITags(TM_ETHERNET_SSI_t* tags, uint16_t number_of_tags); /** * Set GCI handlers which will be used when you want to control something over ethernet configured as server, * for example, turn on/off leds. * * For more about CGI tags, you can check chapter 4.3 on link below: * http://www.state-machine.com/lwip/AN_QP_and_lwIP.pdf * * Note: CGI tags only work if your file name ends with .cgi! * * This function can be called only once, future calls will be denied! * * Parameters: * - const TM_ETHERNET_CGI_t *cgis: * Pointer to TM_ETHERNET_CGI_t structure with link/function pair combination. * It can be array of structures * - uint16_t number_of_handlers: * Number of pairs for .cgi and handler combination * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETSERVER_SetCGIHandlers(const TM_ETHERNET_CGI_t* cgis, uint16_t number_of_handlers); /* Client based functions */ /** * Make TCP CLIENT Connection to external server. * * After this call, different client callbacks will be called depending on what will happen. * * Parameters: * - char* conn_name: * Connection name. This value will be then passed to all client based handlers * - uint8_t ip1: * - uint8_t ip2: * - uint8_t ip3: * - uint8_t ip4: * IP addresses. ip1 is MSB, ip4 is LSB * - uint16_t port: * Port to which we want connect to server * - void* user_parameters: * Pointer to user data to be passed to this function. * This data will be used in all client based callbacks inside TM_TCPCLIENT_t pointer variable * Use NULL in case you don't want to pass any data. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETCLIENT_Connect(char* conn_name, uint8_t ip1, uint8_t ip2, uint8_t ip3, uint8_t ip4, uint16_t port, void* user_parameters); /** * Get total number of sent bytes when you are client * * Returns number of transmitted bytes as a client */ #define TM_ETHERNETCLIENT_GetTXBytes() (TM_ETHERNET.Client_TX_Bytes) /** * Get total number of received bytes when you are client * * Returns number of received bytes as a client */ #define TM_ETHERNETCLIENT_GetRXBytes() (TM_ETHERNET.Client_RX_Bytes) /** * Get number of all connections done as a client * * Returns number of all connections done as a client */ #define TM_ETHERNETCLIENT_GetConnectionsCount() (TM_ETHERNET.ClientConnections) /** * Get number of all successfull connections done as a client * * Returns number of all successfull connections done as a client */ #define TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount() (TM_ETHERNET.ClientSuccessfullConnections) /* DNS */ /** * DNS Get host by name * * This function can be used to get IP address by passing it's domain name to it. * * Different DNS callback functions will be called, depending on what will happen with DNS. * * Parameters: * - char* host_name: * Domain name for which you need IP address. * * Member of TM_ETHERNET_Result_t is returned */ extern TM_ETHERNET_Result_t TM_ETHERNETDNS_GetHostByName(char* host_name); /* Ethernet based callbacks */ /** * IP is set callback * This function is called when IP is assigned to device. * * It is called in case DHCP is used or static ip is used. * It can be used to store IP address, if you use DHCP dynamic IP address. * * Parameters: * - uint8_t ip_addr1: * - uint8_t ip_addr2: * - uint8_t ip_addr3: * - uint8_t ip_addr4: * IP addresses. ip_addr1 is MSB, ip_addr4 is LSB * - uint8_t dhcp: * This is set to 1 in case DHCP has been used for IP assign or 0 if static is used in case of user select or error * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_IPIsSetCallback(uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4, uint8_t dhcp); /** * DHCP start callback * * This function is called when DHCP starts with IP address assigning for device. * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_DHCPStartCallback(void); /** * Link is down callback * * This function will be called when link is down. * This can happen, if your router is down, or you unplug cable * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_LinkIsDownCallback(void); /** * Link is up callback * * This function will be called when link is up again. * It is not called in case that link is up already on initialization at the begin * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_LinkIsUpCallback(void); /* System reset callback */ /** * System reset callback * * If client connection is opened and link become down in this time, after link is up back, * then before new connection can be made, system MUST be restarted for security purposes. * Before you call NVIC_SystemReset() in function to reset system, you can do important stuff here. * * Note: if you don't reset your sistem, then function which is used to connect as a client, * will always refuse your try to connect to your specific IP * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNET_SystemResetCallback(void); /* Ethernet client based callbacks */ /* Callbacks for ethernet client */ /** * Create headers callback * This function is called when connection is prepared to send some headers data to server which is waiting for response. * * If function is not implemented, then default headers are sent. * * Default headers: * GET / HTTP/1.1\r\n * Host: TM_ETHERNETClient\r\n * Connection: close\r\n * \r\n * * Parameters for function: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contains current connection specifications. * - char* buffer: * Char memory buffer where to store your header data * - uint16_t buffer_length: * Maximal memory length for your header data * * With __weak parameter to prevent link errors if not defined by user * * Function must return number of characters written in buffer. * If you return 0 (zero) then connection will be closed. * Buffer length can't be larger than ETHERNET_MAX_HEADER_SIZE define */ extern __weak uint16_t TM_ETHERNETCLIENT_CreateHeadersCallback(TM_TCPCLIENT_t* connection, char* buffer, uint16_t buffer_length); /** * Receive data callback * * This function is called when we have data available to be received. * It might happen that it will be called multiple times for one request, depends on server's response and length of data. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection's specifications. * - uint8_t* buffer: * Memory buffer * - uint16_t buffer_length: * Number of characters in buffer * - uint16_t total_length * Number of unread data. If this value is the same as buffer_length, then no remaining data is available in packet * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ReceiveDataCallback(TM_TCPCLIENT_t* connection, uint8_t* buffer, uint16_t buffer_length, uint16_t total_length); /** * Connected callback * * This function is called when device is connected to specific server. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contains current connection's specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectedCallback(TM_TCPCLIENT_t* connection); /** * Connection closed callback * * This function is called when connection is closed and you are ready to make a new one. * You can also detect, if connection was closed after success or error. * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * - uint8_t success: * It is set to 1 if connection was closed after successfull transmission * or 0 if because of failure * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectionClosedCallback(TM_TCPCLIENT_t* connection, uint8_t success); /** * Error callback * * This function is called when an error occured. * It will be called in case when IP address is not available * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ErrorCallback(TM_TCPCLIENT_t* connection); /** * Connection started callback * * This function will be called when connection to server has started * * Parameters: * - TM_TCPCLIENT_t* connection: * Pointer to TM_TCPCLIENT_t which contanins current connection specifications * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETCLIENT_ConnectionStartedCallback(TM_TCPCLIENT_t* connection); /* DNS based callbacks */ /** * DNS Found callback * * This function will be called when DNS server has valid IP address for your domain request. * It can be useful to make first connection in this function when you know your IP address where you must connect to. * * Parameters: * - char* host_name: * The same host name as you use for DNS requesting, can't be larger than ETHERNET_MAX_CONNECTION_NAME define * - uint8_t ip_addr1: * IP address 1st byte, MSB * - uint8_t ip_addr2: * IP address 2nd byte * - uint8_t ip_addr3: * IP address 3rd byte * - uint8_t ip_addr4: * IP address 4th byte, LSB * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETDNS_FoundCallback(char* host_name, uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4); /** * DNS error callback * * This function will be called when DNS error occured. * Possible errors are: * - Requested domain does not exists, * - You have bad parameters in DNS function call * * Parameters: * - char* host_name: * Host name where an error occured * * No return */ extern __weak void TM_ETHERNETDNS_ErrorCallback(char* host_name); /* Server based callbacks */ /** * SSI callbacks for ethernet server * * This function is called, when ethernet server wants to serve tag you pass in TM_ETHERNETSERVER_SetSSITags() function. * * Parameters: * - int iIndex: * Tag index number. They are specified in order you pass to TM_ETHERNETSERVER_SetSSITags function * - char *pcInsert: * Pointer where you should set your content that will be displayed where your tag is specified in files * - int iInsertLen: * Max string length * * With __weak parameter to prevent link errors if not defined by user * * Must return number of characters in your pcInsert pointer. */ extern __weak uint16_t TM_ETHERNETSERVER_SSICallback(int iIndex, char *pcInsert, int iInsertLen); /** * Called when new client is connected to server * This function can be used, to block IP address. * IP address, from where user access to your server is stored in *pcb variable * * remote_ip = pcb->remote_ip.addr * * You can check here for your blocked IP addresses * * Parameters: * - struct tcp_pcb *pcb: * Pointer to active LwIP PCB structure * * With __weak parameter to prevent link errors if not defined by user * * This function must return 1 if you want to allow connection, * or 0 if you want to deny access to your web. */ extern __weak uint8_t TM_ETHERNETSERVER_ClientConnectedCallback(struct tcp_pcb *pcb); /** * Called when new client is diconnected from server (Or connection closed) * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETSERVER_ClientDisconnectedCallback(void); /** * Called when user based file should be open when new client is connected * If you want to use server on your SDcard or USB flash or whatever, * here you can open file and do the stuff. * * Note: You must set file->len parameter to your file size number! * * If You don't open file (return 0) then default file in flash will be used, * that will say "Hello world from default server file", stored in fsdata.c. * * Only one file at a time will be opened, so if you need to mount card, * you can mount it in this function also. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * - const char *name: * File name that should be opened * * With __weak parameter to prevent link errors if not defined by user * * Return 0 in case you can't/don't want to open file, or 1 if file is successfully opened */ extern __weak int TM_ETHERNETSERVER_OpenFileCallback(struct fs_file* file, const char *name); /** * Called when reading file is finished and file can be closed. * * If you need to unmount your SD card, you can do it here. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETSERVER_CloseFileCallback(struct fs_file* file); /** * Called when file should be read. * This function may be called more than just one time, depends on file length. * * Parameters: * - struct fs_file *file: * Pointer to fs_file struct * - char *buffer: * Pointer to buffer, where you should save your data * - int count: * Number of data that should be read. * You can read less than this number. This is max number you can read this time. * * With __weak parameter to prevent link errors if not defined by user * * Returns number of read data, or -1 (EOF) if file has end. */ extern __weak int TM_ETHERNETSERVER_ReadFileCallback(struct fs_file* file, char* buffer, int count); /** * Post request begin callback * * This function is called, when POST request is trying to be started to our server. * * With this function, you can accept/decline POST request, depending on parameters you receive * * Note: * After POST request finish, you have to choose one file, which will be used to displayed to user after successfull POST end. * If you don't set it by yourself, then "/index.html" file will be used. * You can do that to set your custom file: * * strcpy(params->response_uri, "/yourfile.html"); * * In this structure are also other variables, which one, you should look at TM_ETHERNETPOST_t struct declaration. * * Parameters: * - TM_ETHERNETPOST_t* params: * Pointer to TM_ETHERNETPOST_t structure which contains everything about POST connection. * Look for TM_ETHERNETPOST_t struct comments what you can use in this function. * * With __weak parameter to prevent link errors if not defined by user * * This function must return 1 in case you want to accept POST request, or return 0 in case you want to deny it. * In params structure you have also HTTP headers, so you can look at them and deny access in some cases. */ extern __weak uint8_t TM_ETHERNETSERVER_PostRequestBeginCallback(TM_ETHERNETPOST_t* params); /** * Post request receive data available callback * * This function is called, when we have "Content-Length" statement. * Function might be called multiple times, depends on how many data you try to sent over POST method. * Data are stored inside p->payload variable pointer, which is void pointer. Make a cast to char* variable. * In pbuf struct is also length of this packet, so you have a little control about that. * * To know when you have last time called this function, you can make a compare of params variables. * * Parameters: * - TM_ETHERNETPOST_t* params: * Pointer to TM_ETHERNETPOST_t structure which contains everything about POST connection. * Look for TM_ETHERNETPOST_t struct comments what you can use in this function. * - struct pbuf* p: * Pointer to pbuf structure where data are stored. * * With __weak parameter to prevent link errors if not defined by user * * This function must return 1 if you want to receive more data, or return 0 in case you want to stop POST request at some time. */ extern __weak uint8_t TM_ETHERNETSERVER_PostRequestReceiveDataCallback(TM_ETHERNETPOST_t* params, struct pbuf* p); /** * Post request end callback * * This function is called when POST request is done. * * This function must set response_uri variable to set response URL, which will be used to show to user. * If you don't set it, then default will be used. * * Parameters: * - void* connection: * Pointer to connection parameters, it is type of struct http_state * * - char* response_uri: * Pointer to buffer for response uri set * - u16_t response_uri_len: * Length of response uri buffer length * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETSERVER_PostRequestEndCallback(void* connection, char* response_uri, u16_t response_uri_len); /** * Called when ethernet peripheral is ready. * In this function, user can do other stuff, depending on PHY which is used in project. * * Example: * - Set LED mode for DP83848 PHY, or something else * * Parameters: * - uint32_t PHYAddress: * Phy address when using ETH_ReadPHYRegister and ETH_WritePHYRegister functions * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_ETHERNETPHY_CustomOptions(uint32_t PHYAddress); /** * Called on ethernet GPIO initialization * In this function, user can initialize custom pins, which will be used for communication with PHY. * Don't implement this function in case you want default pinout * * With __weak parameter to prevent link errors if not defined by user * * Must return 1 in case user has made own pins, or 0 in case we want default pins */ extern __weak uint8_t TM_ETHERNET_InitPinsCallback(void); |
Example 1
- STM configured as server mode on port 80.
- For debug purpose is used PC6 (USART6) @ 115200baud where you will be able to see initialization settings.
- How it works:
- Data for user are stored in fsdata.c file,
- There are SSI tags which are replaced with some settings
- There is one CGI handlers which handles LEDs actions
- DHCP is disabled, 192.168.0.120 IP is used
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
/** * Keil project template for ethernet server. * Data to be shown to user by default is stored in file fsdata.c where you can edit it if you want * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx Keil packs version 2.2.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.4.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_disco.h" #include "tm_stm32f4_usart.h" #include "tm_stm32f4_ethernet.h" #include "tm_stm32f4_rtc.h" #include "tm_stm32f4_watchdog.h" #include <stdio.h> #include <stdlib.h> /* RTC data variable */ TM_RTC_t RTC_Data; /* Set SSI tags for handling variables */ static TM_ETHERNET_SSI_t SSI_Tags[] = { "led1_s", /* Tag 0 = led1 status */ "led2_s", /* Tag 1 = led2 status */ "led3_s", /* Tag 2 = led3 status */ "led4_s", /* Tag 3 = led4 status */ "srv_adr",/* Tag 4 = server address */ "clt_a_c",/* Tag 5 = client all connections */ "clt_s_c",/* Tag 6 = client successfull connections */ "clt_per",/* Tag 7 = client percentage */ "clt_tx", /* Tag 8 = client TX bytes */ "clt_rx", /* Tag 9 = client RX bytes */ "srv_c", /* Tag 10 = server all connections */ "srv_tx", /* Tag 11 = server TX bytes */ "srv_rx", /* Tag 12 = server RX bytes */ "mac_adr",/* Tag 13 = MAC address */ "gateway",/* Tag 14 = gateway */ "netmask",/* Tag 15 = netmask */ "link", /* Tag 16 = link status */ "duplex", /* Tag 17 = duplex status */ "hardware",/* Tag 18 = hardware where code is running */ "rtc_time",/* Tag 19 = current RTC time */ "compiled",/* Tag 20 = compiled date and time */ }; /* LED CGI handler */ const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); /* CGI call table, only one CGI used */ TM_ETHERNET_CGI_t CGI_Handlers[] = { {"/ledaction.cgi", LEDS_CGI_Handler}, /* LEDS_CGI_Handler will be called when user connects to "/ledaction.cgi" URL */ }; int main(void) { /* Initialize system */ SystemInit(); /* Init USART6, TX: PC6 for debug */ TM_USART_Init(USART6, TM_USART_PinsPack_1, 115200); /* Enable watchdog, 4 seconds before timeout */ if (TM_WATCHDOG_Init(TM_WATCHDOG_Timeout_4s)) { /* Report to user */ printf("Reset occured because of Watchdog\n"); } /* Initialize delay */ TM_DELAY_Init(); /* Initialize leds on board */ TM_DISCO_LedInit(); /* Initialize button */ TM_DISCO_ButtonInit(); /* Display to user */ printf("Program starting..\n"); /* Initialize RTC with internal clock if not already */ if (!TM_RTC_Init(TM_RTC_ClockSource_Internal)) { /* Set default time for RTC */ /* Set date and time if RTC is not initialized already */ TM_RTC_SetDateTimeString("28.02.15.6;23:35:30"); }; /* Initialize ethernet peripheral */ /* All parameters NULL, default options for MAC, static IP, gateway and netmask will be used */ /* They are defined in tm_stm32f4_ethernet.h file */ if (TM_ETHERNET_Init(NULL, NULL, NULL, NULL) == TM_ETHERNET_Result_Ok) { /* Successfully initialized */ TM_DISCO_LedOn(LED_GREEN); } else { /* Unsuccessfull communication */ TM_DISCO_LedOn(LED_RED); } /* Reset watchdog */ TM_WATCHDOG_Reset(); /* Initialize ethernet server if you want use it, server port 80 */ TM_ETHERNETSERVER_Enable(80); /* Set SSI tags, we have 21 SSI tags */ TM_ETHERNETSERVER_SetSSITags(SSI_Tags, 21); /* Set CGI tags, we have 1 CGI handler, for leds only */ TM_ETHERNETSERVER_SetCGIHandlers(CGI_Handlers, 1); /* Read RTC clock */ TM_RTC_GetDateTime(&RTC_Data, TM_RTC_Format_BIN); /* Print current time to USART */ printf("Current date: %02d:%02d:%02d\n", RTC_Data.hours, RTC_Data.minutes, RTC_Data.seconds); /* Reset watchdog */ TM_WATCHDOG_Reset(); while (1) { /* Update ethernet, call this as fast as possible */ TM_ETHERNET_Update(); /* Reset watchdog */ TM_WATCHDOG_Reset(); } } /* Delay 1ms handler */ void TM_DELAY_1msHandler(void) { /* Time update for ethernet, 1ms */ /* Add 1ms time for ethernet */ TM_ETHERNET_TimeUpdate(1); } /* Handle CGI request for LEDS */ const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { uint8_t i; /* This function handles request like one below: */ /* /ledaction.cgi?ledtoggle=1&ledoff=2 */ /* This will toggle LED 1 and turn off LED 2 */ /* Callback */ if (iIndex == 0) { /* Go through all params */ for (i = 0; i < iNumParams; i++) { /* If current pair = ledtoggle=someled */ if (strstr(pcParam[i], "ledtoggle")) { /* Switch first character */ switch (pcValue[i][0]) { case '1': TM_DISCO_LedToggle(LED_GREEN); break; case '2': TM_DISCO_LedToggle(LED_ORANGE); break; case '3': TM_DISCO_LedToggle(LED_RED); break; case '4': TM_DISCO_LedToggle(LED_BLUE); break; default: break; } } else if (strstr(pcParam[i], "ledon")) { switch (pcValue[i][0]) { case '1': TM_DISCO_LedOn(LED_GREEN); break; case '2': TM_DISCO_LedOn(LED_ORANGE); break; case '3': TM_DISCO_LedOn(LED_RED); break; case '4': TM_DISCO_LedOn(LED_BLUE); break; default: break; } } else if (strstr(pcParam[i], "ledoff")) { switch (pcValue[i][0]) { case '1': TM_DISCO_LedOff(LED_GREEN); break; case '2': TM_DISCO_LedOff(LED_ORANGE); break; case '3': TM_DISCO_LedOff(LED_RED); break; case '4': TM_DISCO_LedOff(LED_BLUE); break; default: break; } } } } /* Return URL to be used after call */ return "/index.shtml"; } /* SSI server callback, always is called this callback */ uint16_t TM_ETHERNETSERVER_SSICallback(int iIndex, char *pcInsert, int iInsertLen) { uint8_t status; /* Return number of characters written */ if (iIndex < 4) { /* First 4 tags are leds */ /* Get led status */ switch (iIndex) { case 0: /* Green LED */ status = TM_DISCO_LedIsOn(LED_GREEN); break; case 1: /* Orange LED */ status = TM_DISCO_LedIsOn(LED_ORANGE); break; case 2: /* Red LED */ status = TM_DISCO_LedIsOn(LED_RED); break; case 3: /* Blue LED */ status = TM_DISCO_LedIsOn(LED_BLUE); break; default: return 0; } /* Set string according to status */ if (status) { /* Led is ON */ sprintf(pcInsert, "<span class=\"green\">On</span>"); } else { /* Led is OFF */ sprintf(pcInsert, "<span class=\"red\">Off</span>"); } } else if (iIndex == 4) { /* #serv_adr tag is requested */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetLocalIP(0), TM_ETHERNET_GetLocalIP(1), TM_ETHERNET_GetLocalIP(2), TM_ETHERNET_GetLocalIP(3)); } else if (iIndex == 5) { /* #clt_a_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETCLIENT_GetConnectionsCount()); } else if (iIndex == 6) { /* #clt_s_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount()); } else if (iIndex == 7) { /* #clt_per tag */ if (TM_ETHERNETCLIENT_GetConnectionsCount() == 0) { strcpy(pcInsert, "0 %"); } else { sprintf(pcInsert, "%f %%", (float)TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount() / (float)TM_ETHERNETCLIENT_GetConnectionsCount() * 100); } } else if (iIndex == 8) { /* #clt_tx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETCLIENT_GetTXBytes()); } else if (iIndex == 9) { /* #clt_rx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETCLIENT_GetRXBytes()); } else if (iIndex == 10) { /* #srv_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETSERVER_GetConnectionsCount()); } else if (iIndex == 11) { /* #srv_tx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETSERVER_GetTXBytes()); } else if (iIndex == 12) { /* #srv_rx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETSERVER_GetRXBytes()); } else if (iIndex == 13) { /* #mac_adr */ sprintf(pcInsert, "%02X-%02X-%02X-%02X-%02X-%02X", TM_ETHERNET_GetMACAddr(0), TM_ETHERNET_GetMACAddr(1), TM_ETHERNET_GetMACAddr(2), TM_ETHERNET_GetMACAddr(3), TM_ETHERNET_GetMACAddr(4), TM_ETHERNET_GetMACAddr(5) ); } else if (iIndex == 14) { /* #gateway */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetGateway(0), TM_ETHERNET_GetGateway(1), TM_ETHERNET_GetGateway(2), TM_ETHERNET_GetGateway(3) ); } else if (iIndex == 15) { /* #netmask */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetNetmask(0), TM_ETHERNET_GetNetmask(1), TM_ETHERNET_GetNetmask(2), TM_ETHERNET_GetNetmask(3) ); } else if (iIndex == 16) { /* #link */ if (TM_ETHERNET_Is100M()) { strcpy(pcInsert, "100Mbit"); } else { strcpy(pcInsert, "10Mbit"); } } else if (iIndex == 17) { /* #duplex */ if (TM_ETHERNET_IsFullDuplex()) { strcpy(pcInsert, "Full"); } else { strcpy(pcInsert, "Half"); } } else if (iIndex == 18) { /* #hardware */ strcpy(pcInsert, "STM32F4-Discovery"); } else if (iIndex == 19) { /* #rtc_time */ TM_RTC_GetDateTime(&RTC_Data, TM_RTC_Format_BIN); sprintf(pcInsert, "%04d-%02d-%02d %02d:%02d:%02d", RTC_Data.year + 2000, RTC_Data.month, RTC_Data.date, RTC_Data.hours, RTC_Data.minutes, RTC_Data.seconds ); } else if (iIndex == 20) { /* #compiled */ strcpy(pcInsert, __DATE__ " at " __TIME__); } else { /* No valid tag */ return 0; } /* Return number of characters written in buffer */ return strlen(pcInsert); } void TM_ETHERNET_IPIsSetCallback(uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4, uint8_t dhcp) { /* Called when we have valid IP, it might be static or DHCP */ if (dhcp) { /* IP set with DHCP */ printf("IP: %d.%d.%d.%d assigned by DHCP server\n", ip_addr1, ip_addr2, ip_addr3, ip_addr4); } else { /* Static IP */ printf("IP: %d.%d.%d.%d; STATIC IP used\n", ip_addr1, ip_addr2, ip_addr3, ip_addr4); } /* Print MAC address to user */ printf("MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", TM_ETHERNET_GetMACAddr(0), TM_ETHERNET_GetMACAddr(1), TM_ETHERNET_GetMACAddr(2), TM_ETHERNET_GetMACAddr(3), TM_ETHERNET_GetMACAddr(4), TM_ETHERNET_GetMACAddr(5) ); /* Print netmask to user */ printf("Netmask: %d.%d.%d.%d\n", TM_ETHERNET_GetGateway(0), TM_ETHERNET_GetGateway(1), TM_ETHERNET_GetGateway(2), TM_ETHERNET_GetGateway(3) ); /* Print gateway to user */ printf("Gateway: %d.%d.%d.%d\n", TM_ETHERNET_GetNetmask(0), TM_ETHERNET_GetNetmask(1), TM_ETHERNET_GetNetmask(2), TM_ETHERNET_GetNetmask(3) ); /* Print 100M link status, 1 = 100M, 0 = 10M */ printf("Link 100M: %d\n", TM_ETHERNET.speed_100m); /* Print duplex status: 1 = Full, 0 = Half */ printf("Full duplex: %d\n", TM_ETHERNET.full_duplex); } void TM_ETHERNET_LinkIsDownCallback(void) { /* This function will be called when ethernet cable will not be plugged */ /* It will also be called on initialization if connection is not detected */ /* Print to user */ printf("Link is down, do you have connected to your modem/router?"); } void TM_ETHERNET_LinkIsUpCallback(void) { /* Cable has been plugged in back, link is detected */ /* I suggest you that you reboot MCU here */ /* Do important stuff before */ /* Print to user */ printf("Link is up back\n"); } /* For printf function */ int fputc(int ch, FILE *f) { /* Send over usart */ TM_USART_Putc(USART6, ch); /* Return character back */ return ch; } |
Example 2
- STM configured as server mode on port 80.
- For debug purpose is used PC6 (USART6) @ 115200baud where you will be able to see initialization settings.
- How it works:
- Data for user are stored on SD card (how you will implement low layer is on you, but you can use my FatFs library as well)
- There are SSI tags which are replaced with some settings
- There is one CGI handlers which handles LEDs actions
- DHCP is disabled, 192.168.0.120 IP is used
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
/** * Keil project template for ethernet server. * File to be shown to user is stored on SD card * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx Keil packs version 2.2.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.4.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_disco.h" #include "tm_stm32f4_usart.h" #include "tm_stm32f4_ethernet.h" #include "tm_stm32f4_rtc.h" #include "tm_stm32f4_watchdog.h" #include "tm_stm32f4_fatfs.h" #include <stdio.h> #include <stdlib.h> /* File variable */ FIL fil[ETHERNET_MAX_OPEN_FILES]; /* Fatfs variable */ FATFS fs; /* RTC data variable */ TM_RTC_t RTC_Data; /* Set SSI tags for handling variables */ static TM_ETHERNET_SSI_t SSI_Tags[] = { "led1_s", /* Tag 0 = led1 status */ "led2_s", /* Tag 1 = led2 status */ "led3_s", /* Tag 2 = led3 status */ "led4_s", /* Tag 3 = led4 status */ "srv_adr",/* Tag 4 = server address */ "clt_a_c",/* Tag 5 = client all connections */ "clt_s_c",/* Tag 6 = client successfull connections */ "clt_per",/* Tag 7 = client percentage */ "clt_tx", /* Tag 8 = client TX bytes */ "clt_rx", /* Tag 9 = client RX bytes */ "srv_c", /* Tag 10 = server all connections */ "srv_tx", /* Tag 11 = server TX bytes */ "srv_rx", /* Tag 12 = server RX bytes */ "mac_adr",/* Tag 13 = MAC address */ "gateway",/* Tag 14 = gateway */ "netmask",/* Tag 15 = netmask */ "link", /* Tag 16 = link status */ "duplex", /* Tag 17 = duplex status */ "hardware",/* Tag 18 = hardware where code is running */ "rtc_time",/* Tag 19 = current RTC time */ "compiled",/* Tag 20 = compiled date and time */ }; /* LED CGI handler */ const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); /* CGI call table, only one CGI used */ TM_ETHERNET_CGI_t CGI_Handlers[] = { {"/ledaction.cgi", LEDS_CGI_Handler}, /* LEDS_CGI_Handler will be called when user connects to "/ledaction.cgi" URL */ }; int main(void) { /* Initialize system */ SystemInit(); /* Init USART6, TX: PC6 for debug */ TM_USART_Init(USART6, TM_USART_PinsPack_1, 115200); /* Enable watchdog, 4 seconds before timeout */ if (TM_WATCHDOG_Init(TM_WATCHDOG_Timeout_4s)) { /* Report to user */ printf("Reset occured because of Watchdog\n"); } /* Initialize delay */ TM_DELAY_Init(); /* Initialize leds on board */ TM_DISCO_LedInit(); /* Initialize button */ TM_DISCO_ButtonInit(); /* Display to user */ printf("Program starting..\n"); /* Initialize RTC with internal clock if not already */ if (!TM_RTC_Init(TM_RTC_ClockSource_Internal)) { /* Set default time for RTC */ /* Set date and time if RTC is not initialized already */ TM_RTC_SetDateTimeString("28.02.15.6;23:35:30"); }; /* Initialize ethernet peripheral */ /* All parameters NULL, default options for MAC, static IP, gateway and netmask will be used */ /* They are defined in tm_stm32f4_ethernet.h file */ if (TM_ETHERNET_Init(NULL, NULL, NULL, NULL) == TM_ETHERNET_Result_Ok) { /* Successfully initialized */ TM_DISCO_LedOn(LED_GREEN); } else { /* Unsuccessfull communication */ TM_DISCO_LedOn(LED_RED); } /* Reset watchdog */ TM_WATCHDOG_Reset(); /* Initialize ethernet server if you want use it, server port 80 */ TM_ETHERNETSERVER_Enable(80); /* Set SSI tags, we have 21 SSI tags */ TM_ETHERNETSERVER_SetSSITags(SSI_Tags, 21); /* Set CGI tags, we have 1 CGI handler, for leds only */ TM_ETHERNETSERVER_SetCGIHandlers(CGI_Handlers, 1); /* Read RTC clock */ TM_RTC_GetDateTime(&RTC_Data, TM_RTC_Format_BIN); /* Print current time to USART */ printf("Current date: %02d:%02d:%02d\n", RTC_Data.hours, RTC_Data.minutes, RTC_Data.seconds); /* Reset watchdog */ TM_WATCHDOG_Reset(); while (1) { /* Update ethernet, call this as fast as possible */ TM_ETHERNET_Update(); /* If button pressed, toggle server status */ if (TM_DISCO_ButtonOnPressed()) { /* If server is enabled */ if (TM_ETHERNETSERVER_Enabled()) { /* Disable it */ TM_ETHERNETSERVER_Disable(); /* Print to user */ printf("Server disabled\n"); } else { /* Enable it */ TM_ETHERNETSERVER_Enable(80); /* Print to user */ printf("Server enabled\n"); } } /* Reset watchdog */ TM_WATCHDOG_Reset(); } } /* Delay 1ms handler */ void TM_DELAY_1msHandler(void) { /* Time update for ethernet, 1ms */ /* Add 1ms time for ethernet */ TM_ETHERNET_TimeUpdate(1); } /* Handle CGI request for LEDS */ const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { uint8_t i; /* This function handles request like one below: */ /* /ledaction.cgi?ledtoggle=1&ledoff=2 */ /* This will toggle LED 1 and turn off LED 2 */ /* Callback */ if (iIndex == 0) { /* Go through all params */ for (i = 0; i < iNumParams; i++) { /* If current pair = ledtoggle=someled */ if (strstr(pcParam[i], "ledtoggle")) { /* Switch first character */ switch (pcValue[i][0]) { case '1': TM_DISCO_LedToggle(LED_GREEN); break; case '2': TM_DISCO_LedToggle(LED_ORANGE); break; case '3': TM_DISCO_LedToggle(LED_RED); break; case '4': TM_DISCO_LedToggle(LED_BLUE); break; default: break; } } else if (strstr(pcParam[i], "ledon")) { switch (pcValue[i][0]) { case '1': TM_DISCO_LedOn(LED_GREEN); break; case '2': TM_DISCO_LedOn(LED_ORANGE); break; case '3': TM_DISCO_LedOn(LED_RED); break; case '4': TM_DISCO_LedOn(LED_BLUE); break; default: break; } } else if (strstr(pcParam[i], "ledoff")) { switch (pcValue[i][0]) { case '1': TM_DISCO_LedOff(LED_GREEN); break; case '2': TM_DISCO_LedOff(LED_ORANGE); break; case '3': TM_DISCO_LedOff(LED_RED); break; case '4': TM_DISCO_LedOff(LED_BLUE); break; default: break; } } } } /* Return URL to be used after call */ return "/index.shtml"; } /* SSI server callback, always is called this callback */ uint16_t TM_ETHERNETSERVER_SSICallback(int iIndex, char *pcInsert, int iInsertLen) { uint8_t status; /* Return number of characters written */ if (iIndex < 4) { /* First 4 tags are leds */ /* Get led status */ switch (iIndex) { case 0: /* Green LED */ status = TM_DISCO_LedIsOn(LED_GREEN); break; case 1: /* Orange LED */ status = TM_DISCO_LedIsOn(LED_ORANGE); break; case 2: /* Red LED */ status = TM_DISCO_LedIsOn(LED_RED); break; case 3: /* Blue LED */ status = TM_DISCO_LedIsOn(LED_BLUE); break; default: return 0; } /* Set string according to status */ if (status) { /* Led is ON */ sprintf(pcInsert, "<span class=\"green\">On</span>"); } else { /* Led is OFF */ sprintf(pcInsert, "<span class=\"red\">Off</span>"); } } else if (iIndex == 4) { /* #serv_adr tag is requested */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetLocalIP(0), TM_ETHERNET_GetLocalIP(1), TM_ETHERNET_GetLocalIP(2), TM_ETHERNET_GetLocalIP(3)); } else if (iIndex == 5) { /* #clt_a_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETCLIENT_GetConnectionsCount()); } else if (iIndex == 6) { /* #clt_s_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount()); } else if (iIndex == 7) { /* #clt_per tag */ if (TM_ETHERNETCLIENT_GetConnectionsCount() == 0) { strcpy(pcInsert, "0 %"); } else { sprintf(pcInsert, "%f %%", (float)TM_ETHERNETCLIENT_GetSuccessfullConnectionsCount() / (float)TM_ETHERNETCLIENT_GetConnectionsCount() * 100); } } else if (iIndex == 8) { /* #clt_tx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETCLIENT_GetTXBytes()); } else if (iIndex == 9) { /* #clt_rx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETCLIENT_GetRXBytes()); } else if (iIndex == 10) { /* #srv_c tag */ sprintf(pcInsert, "%u", TM_ETHERNETSERVER_GetConnectionsCount()); } else if (iIndex == 11) { /* #srv_tx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETSERVER_GetTXBytes()); } else if (iIndex == 12) { /* #srv_rx tag */ sprintf(pcInsert, "%llu", TM_ETHERNETSERVER_GetRXBytes()); } else if (iIndex == 13) { /* #mac_adr */ sprintf(pcInsert, "%02X-%02X-%02X-%02X-%02X-%02X", TM_ETHERNET_GetMACAddr(0), TM_ETHERNET_GetMACAddr(1), TM_ETHERNET_GetMACAddr(2), TM_ETHERNET_GetMACAddr(3), TM_ETHERNET_GetMACAddr(4), TM_ETHERNET_GetMACAddr(5) ); } else if (iIndex == 14) { /* #gateway */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetGateway(0), TM_ETHERNET_GetGateway(1), TM_ETHERNET_GetGateway(2), TM_ETHERNET_GetGateway(3) ); } else if (iIndex == 15) { /* #netmask */ sprintf(pcInsert, "%d.%d.%d.%d", TM_ETHERNET_GetNetmask(0), TM_ETHERNET_GetNetmask(1), TM_ETHERNET_GetNetmask(2), TM_ETHERNET_GetNetmask(3) ); } else if (iIndex == 16) { /* #link */ if (TM_ETHERNET_Is100M()) { strcpy(pcInsert, "100Mbit"); } else { strcpy(pcInsert, "10Mbit"); } } else if (iIndex == 17) { /* #duplex */ if (TM_ETHERNET_IsFullDuplex()) { strcpy(pcInsert, "Full"); } else { strcpy(pcInsert, "Half"); } } else if (iIndex == 18) { /* #hardware */ strcpy(pcInsert, "STM32F4-Discovery"); } else if (iIndex == 19) { /* #rtc_time */ TM_RTC_GetDateTime(&RTC_Data, TM_RTC_Format_BIN); sprintf(pcInsert, "%04d-%02d-%02d %02d:%02d:%02d", RTC_Data.year + 2000, RTC_Data.month, RTC_Data.date, RTC_Data.hours, RTC_Data.minutes, RTC_Data.seconds ); } else if (iIndex == 20) { /* #compiled */ strcpy(pcInsert, __DATE__ " at " __TIME__); } else { /* No valid tag */ return 0; } /* Return number of characters written in buffer */ return strlen(pcInsert); } void TM_ETHERNET_IPIsSetCallback(uint8_t ip_addr1, uint8_t ip_addr2, uint8_t ip_addr3, uint8_t ip_addr4, uint8_t dhcp) { /* Called when we have valid IP, it might be static or DHCP */ if (dhcp) { /* IP set with DHCP */ printf("IP: %d.%d.%d.%d assigned by DHCP server\n", ip_addr1, ip_addr2, ip_addr3, ip_addr4); } else { /* Static IP */ printf("IP: %d.%d.%d.%d; STATIC IP used\n", ip_addr1, ip_addr2, ip_addr3, ip_addr4); } /* Print MAC address to user */ printf("MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", TM_ETHERNET_GetMACAddr(0), TM_ETHERNET_GetMACAddr(1), TM_ETHERNET_GetMACAddr(2), TM_ETHERNET_GetMACAddr(3), TM_ETHERNET_GetMACAddr(4), TM_ETHERNET_GetMACAddr(5) ); /* Print netmask to user */ printf("Netmask: %d.%d.%d.%d\n", TM_ETHERNET_GetGateway(0), TM_ETHERNET_GetGateway(1), TM_ETHERNET_GetGateway(2), TM_ETHERNET_GetGateway(3) ); /* Print gateway to user */ printf("Gateway: %d.%d.%d.%d\n", |