├── IR_LED_driver.png ├── main ├── component.mk └── rmt_server.c ├── README.md └── demoWebPage └── ESP32-RMT-server.html /IR_LED_driver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimeckert/ESP32-RMT-server/HEAD/IR_LED_driver.png -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32-RMT-server 2 | WiFi server that drives low-level commands to the ESP32 RMT peripheral 3 | 4 | __NOTE: This code seems to work reliably and has all the features that I plan to implement. It is released.__ 5 | 6 | The ESP32 receives an HTTP POST request and decodes commands contained in the request body. 7 | These commands control the RMT peripheral and drive an infrared LED. 8 | The commands are low-level mark and space commands. 9 | There is no protocol decode implemented in this application. 10 | This allows the RMT to transmit virtually any infrared protocol. 11 | Compiles with [ESP-IDF](https://github.com/espressif/esp-idf) 12 | 13 | * The HTTP POST request body consists of one or more text lines. Lines are separated by newline (\n) characters. Returns (\r) are allowed, but are ignored. 14 | * Each line consists of comma-separated values. There is one command on each line. Each line starts with one character that identifies the type of command for this line. 15 | 16 | The intent is that a JavaScript program contained in an HTML file, running on a web browser and served by a host machine (not the ESP32) will create these low-level RMT commands and transmit them to the ESP32. An example HTML file is part of this repository. A real application will have its own repository. 17 | 18 | # Commands 19 | 20 | The commands closely follow the RMT register/RAM definitions. Refer to the ESP32 documentation at http://esp32.net/ . 21 | Lines that do not follow these specifictions are silently ignored and the next line is processed. 22 | * __c,[div],[high],[low]__ 23 | * Sets the RMT channel clock frequency and the carrier clock frequency and duty cycle. 24 | * __[div]__: RMT channel clock divider (RMT_DIV_CNT_CHn). Text representation of an integer between 1 and 255, inclusive. Defines the RMT channel clock division ratio. The channel clock is divided from the source clock. The ESP32 source clock is 80MHz. 25 | * __[high]__ and __[low]__: High (RMT_CARRIER_HIGH_CHn) and low (RMT_CARRIER_LOW_CHn) duration of the carrier waveform. Text representation of integers between 1 and 65,535, inclusive. The unit of carrier_high/low is one source clock period. 26 | * __t,[non-zero duration], ... ,0__ 27 | * Defines a sequence of durations of IR transmission bits, both modulated at the carrier frequency (mark) and idle (space). 28 | * __[non-zero duration]__: A text representation of a non-zero integer between -32,767 and 32,767, inclusive. These integers define the durations of transmit marks and spaces. A zero value denotes the end of the transmission sequence. 29 | * Positive integers create a burst of IR output (mark) at the carrier frequency, with duration of [non-zero-duration] channel clock periods. 30 | * Negative integers create a duration on the IR output with no carrier (space). The duration is in channel clock periods. 31 | * Positive and negative values do not need to be alternated. Either positive or negative values can follow a positive or negative value. 32 | * A zero value tells the RMT to stop the RMT transmission sequence. The last value on the line must be a zero. A zero anywhere else on the line will terminate the transmission sequence at that point. When terminated, a new RMT transmission can be started with a new command on a new line. There will be an indeterminate delay between consecutive RMT transmissions. 33 | * The RMT RAM can store a maximum of 128 duration values. If a line contains more than 128 values, the driver implements the RMT wrap-around mode to transmit the longer sequence. The terminating zero duration counts as one of the duration values. 34 | * __d,[milliseconds delay]__ 35 | * __[milliseconds delay]__: Create a delay before decoding the next line. Used to create a realtively long gap between IR tramsmissions. Text representation of a positive non-zero integer of the number of milliseconds for the delay. Implemented with the FreeRTOS function: 36 | * vTaskDelay( milliseconds delay / portTICK_PERIOD_MS ); and has the limitations of that function. See the documentation for this function for the maximum possible delay, which depends on the tick period of your system and the data type used for this function. If your tick period is 1mS and the data type uses a 16-bit unsigned int, the maximum duration is about 65 seconds. 37 | 38 | # Definitions 39 | * __HTTP POST Request__: A combination of request header and request body, sent to the ESP32. Your web browser automatically inserts a blank line between the header and body. 40 | * __Request Header__: Your browser creates most of this. Important options for this application are: 41 | * __Request Type__: POST. Needed to avoid CORS restrictions and to contain enough information for the ESP32. 42 | * __Content-Type__: text/plain. Needed to avoid CORS restrictions. 43 | * __Request Body__: One or more lines of text, following the format described above. 44 | * __Lines__: In this application, each line in the request body consists of multiple text values, separated by commas. All of the numbers transmitted to the ESP32 are text representations of decimal numbers. Each line is terminated by either: 45 | * a newline (\n), or 46 | * a return (\r) and a newline (\n), or 47 | * the end of the request body 48 | * __Same-Origin-Policy__: Keeps your compliant browser from fetching information from a different server than the original web page was served from. This is an important internet security feature. 49 | * __CORS__: Cross-Orgin-Resource-Sharing. A complex way to allow communications between different web hosts. This is the authorized way to skirt the Same-Origin-Policy. See the WiKi for more information. 50 | -------------------------------------------------------------------------------- /demoWebPage/ESP32-RMT-server.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | ESP32-RMT-server 15 | 16 | 34 | 35 | 129 | 130 | 131 |

ESP32-RMT-server

132 | 133 |

This is an example of how JavaScript can sent POST commands directly to an ESP32 that is running 134 | the application ESP32-RMT-server. See the description on 135 | https://github.com/kimeckert/ESP32-RMT-server. 137 | Use one of the following tools to compose and transmit commands to the ESP32. 138 |

139 | 140 |
141 | 142 |

ESP32 IP Address

143 |

Enter the IP address of your ESP32: 144 | 145 | , such as '192.168.1.25'. 146 | This software needs the IP address to send the POST command.

147 | 148 |
149 | 150 |

IR Transmissions

151 |

Enter one or more lines of text to send to the RMT. 152 | Each line can be any command that the ESP32-RMT-server can receive. 153 | All lines are sent in one POST message when you click the SEND button. 154 |
155 |
156 | 157 | 158 |

159 | 160 |
161 | 162 |

Frequencies

163 | You can send clock variables in the box above, or you can use the table below to 164 | calculate the effect that those variables will have on the ESP32. 165 | The initial values in the table reflect the default values used in the ESP32-RMT-server software. 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 |
ItemValueUnitsDescription
ESP32 Clock frequencyMHzSource Clock
RMT_DIV_CNT_CHnChannel clock divisor
Channel Clock FrequencyKHz= Source Clock frequency / RMT_DIV_CNT_CHn
RMT_CARRIER_HIGH_CHnCarrier clock high duration, in Source Clock periods
RMT_CARRIER_LOW_CHnCarrier clock low duration, in Source Clock periods
Carrier clock frequencyKHz= Source Clock Frequency / (RMT_CARRIER_HIGH_CHn + RMT_CARRIER_LOW_CHn)
Carrier clock duty cyclePercent= RMT_CARRIER_HIGH_CHn / (RMT_CARRIER_HIGH_CHn + RMT_CARRIER_LOW_CHn)
Pulse Duration ResolutionMicroseconds = One Channel clock period
Pulse Maximum DurationMicroseconds = (2^15) * Channel clock period
RMT_server commandSend the clock command to the ESP32
212 | 213 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /main/rmt_server.c: -------------------------------------------------------------------------------- 1 | /* RMT transmit control over http server. 2 | * 3 | * HTTP server code modified from 4 | * https://github.com/feelfreelinux/myesp32tests/blob/master/examples/http_server.c 5 | * That software is distributed under GNU General Public License 6 | * 7 | * RMT code modified from example: rmt_nec_tx_rx 8 | * That software is distributed under Public Domain (or CC0 licensed, at your option.) 9 | * 10 | * Additional software included in this application is distributed under 11 | * Public Domain (or CC0 licensed, at your option.) 12 | * 13 | * This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 | * CONDITIONS OF ANY KIND, either express or implied. 15 | */ 16 | 17 | #include 18 | #include "freertos/FreeRTOS.h" 19 | #include "freertos/task.h" 20 | #include "freertos/event_groups.h" 21 | #include "esp_system.h" 22 | #include "esp_wifi.h" 23 | #include "esp_event_loop.h" 24 | #include "esp_log.h" 25 | #include "nvs_flash.h" 26 | #include "driver/gpio.h" 27 | #include "driver/rmt.h" 28 | 29 | #include "lwip/sys.h" 30 | #include "lwip/netdb.h" 31 | #include "lwip/api.h" 32 | 33 | // FreeRTOS function 34 | #define INCLUDE_vTaskDelay 1 35 | 36 | // HTTP responses 37 | const static char http_html_Accepted[] = "HTTP/1.1 202 Accepted\r\nConnection: close\r\n\r\n"; 38 | const static char http_html_Not_Allowed[] = "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n\r\n"; 39 | 40 | // LED on Huzzah32 board 41 | const int LED_BUILTIN = 13; 42 | 43 | // used during debug 44 | const static char http_debug1[] = "HTTP/1.1 202 Accepted\r\nContent-type: text/html\r\n\r\n"; 45 | const static char http_debug2[] = "ESP32
";
 46 | const static char http_debug3[] = "
"; 47 | 48 | // how to connect to my local WiFi 49 | #define WIFI_SSID "Your SSID Here" 50 | #define WIFI_PASS "Your password here" 51 | 52 | // RMT values 53 | #define RMT_TX_CHANNEL RMT_CHANNEL_0 54 | #define RMT_TX_GPIO GPIO_NUM_26 55 | // channel clock period = 1 uS 56 | #define RMT_CLK_DIV 80 57 | 58 | // WIFI values 59 | static EventGroupHandle_t wifi_event_group; 60 | const int CONNECTED_BIT = BIT0; 61 | 62 | // used when parsing integers from character arrays 63 | typedef struct { 64 | int num; 65 | bool good; 66 | } returnIntVal; 67 | 68 | // WiFi event handler 69 | static esp_err_t event_handler(void *ctx, system_event_t *event) { 70 | switch(event->event_id) { 71 | case SYSTEM_EVENT_STA_START: 72 | esp_wifi_connect(); 73 | break; 74 | case SYSTEM_EVENT_STA_GOT_IP: 75 | xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); 76 | break; 77 | case SYSTEM_EVENT_STA_DISCONNECTED: 78 | /* This is a workaround as ESP32 WiFi libs don't currently 79 | auto-reassociate. */ 80 | esp_wifi_connect(); 81 | xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); 82 | break; 83 | default: 84 | break; 85 | } 86 | return ESP_OK; 87 | } 88 | 89 | // initialize WiFi 90 | static void initialise_wifi(void) { 91 | tcpip_adapter_init(); 92 | wifi_event_group = xEventGroupCreate(); 93 | ESP_ERROR_CHECK( esp_event_loop_init( event_handler, NULL ) ); 94 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 95 | ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); 96 | ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); 97 | wifi_config_t wifi_config = { 98 | .sta = { 99 | .ssid = WIFI_SSID, 100 | .password = WIFI_PASS, 101 | }, 102 | }; 103 | ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); 104 | ESP_ERROR_CHECK( esp_wifi_set_config( WIFI_IF_STA, &wifi_config ) ); 105 | ESP_ERROR_CHECK( esp_wifi_start() ); 106 | printf("WiFi initialized\n"); 107 | } 108 | 109 | // initialize RMT peripheral for output 110 | // Note that some of these settings can be modified during operation 111 | static void rmt_tx_init() { 112 | rmt_config_t rmt_tx; 113 | rmt_tx.rmt_mode = RMT_MODE_TX; 114 | rmt_tx.channel = RMT_TX_CHANNEL; 115 | rmt_tx.gpio_num = RMT_TX_GPIO; 116 | rmt_tx.mem_block_num = 1; 117 | rmt_tx.clk_div = RMT_CLK_DIV; 118 | rmt_tx.tx_config.loop_en = false; 119 | rmt_tx.tx_config.carrier_duty_percent = 30; 120 | rmt_tx.tx_config.carrier_freq_hz = 38000; 121 | rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; 122 | rmt_tx.tx_config.carrier_en = true; 123 | rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; 124 | rmt_tx.tx_config.idle_output_en = true; 125 | 126 | ESP_ERROR_CHECK( rmt_config(&rmt_tx) ); 127 | ESP_ERROR_CHECK( rmt_driver_install(rmt_tx.channel, 0, 0) ); 128 | printf("RMT initialized\n"); 129 | } 130 | 131 | // find the start of the request body, which follows a blank line 132 | // a blank line is created by two consecutive \n's, ignoring \r's 133 | // more than two consecutive newlines are accepted 134 | // returns the index of the character following the newlines 135 | u16_t find_body( char* buf, u16_t length ) { 136 | printf("Finding POST body, buffer size %d\n", length); 137 | // counts number of consecutive newlines 138 | u16_t newlines = 0; 139 | // character pointer 140 | u16_t this_char; 141 | // the response starts with 'POST ', so start at character 5 142 | for ( this_char=5; this_char<=length; this_char++ ) { 143 | if ( buf[this_char] == '\r' ) { continue; } 144 | if ( buf[this_char] == '\n' ) { newlines++; } 145 | // only received a single newline, reset counter 146 | else if ( newlines == 1 ) { newlines = 0; } 147 | if ( ( newlines > 1 ) && ( buf[this_char] != '\n' ) ) { 148 | printf("Found body start %d\n", this_char); 149 | return this_char; 150 | } 151 | } 152 | // body not found 153 | return 0; 154 | } 155 | 156 | // push item onto rmt_item32_t array 157 | // value_index points to: duration0/level0, duration1/level1, ... 158 | // value_index: 0 1 2 3 4 5 6 7 159 | // value_index / 2: 0 0 1 1 2 2 3 3 160 | // items index: 0 0 1 1 2 2 3 3 161 | void pushItem( rmt_item32_t* items, u16_t value_index, bool level, u16_t duration ) { 162 | u16_t i = value_index / 2; 163 | // lower 16 bits of the 32-bit item 164 | if ( value_index % 2 == 0 ) { 165 | items[i].level0 = level; 166 | items[i].duration0 = duration; 167 | // just in case this is the last item, fill up the next entry 168 | items[i].level1 = level; 169 | items[i].duration1 = 0; 170 | } 171 | // upper 16 bits of the 32-bit item 172 | else { 173 | items[i].level1 = level; 174 | items[i].duration1 = duration; 175 | } 176 | printf("Item pushed to RMT data RAM: level %d, duration %u\n", level, duration); 177 | } 178 | 179 | // set the clock divisor and carrier clock high/low durations 180 | // set during the decode of RMT data 181 | void set_rmt_frequency( uint16_t div, uint16_t high, uint16_t low ) { 182 | printf("Set frequency %i, %i, %i\n", div, high, low); 183 | 184 | // if clock divisor changes, set to new value 185 | uint8_t previous_div; 186 | rmt_get_clk_div( RMT_TX_CHANNEL, &previous_div ); 187 | printf("previous div: %i\n", previous_div); 188 | if ( (uint8_t) div != previous_div ) { 189 | rmt_set_clk_div( RMT_TX_CHANNEL, (uint8_t) div ); 190 | printf("set div = %i\n", div); 191 | } 192 | 193 | // set clock high and low times 194 | // args: channel, carrier_en, high_level, low_level, carrier_level 195 | rmt_set_tx_carrier( RMT_TX_CHANNEL, true, high, low, RMT_CARRIER_LEVEL_HIGH ); 196 | printf("Reset RMT frequency\n"); 197 | } 198 | 199 | // returns the number of comma-separated fields in this line, 200 | // including the first field, the line type designation 201 | u16_t count_values( char* buf, u16_t start, u16_t end ) { 202 | u16_t count = 0; 203 | u16_t pointer; 204 | for ( pointer=start; pointer<=end; pointer++ ) { 205 | if ( buf[pointer] == ',' ) { count++; } 206 | } 207 | return count + 1; 208 | } 209 | 210 | // get the n-th field from the comma-separated line 211 | // the first numerical field is index = 0 212 | returnIntVal get_number( char* buf, u16_t start, u16_t end, int count ) { 213 | returnIntVal n; 214 | n.num = 0; 215 | n.good = true; 216 | bool is_neg = false; 217 | u16_t this_char = start; 218 | u16_t commas = 0; 219 | printf("get_number: look for %d\n", count); 220 | 221 | // count values separated by commas 222 | if ( count > 0 ) { 223 | while( this_char++ <= end ) { 224 | if ( buf[this_char] == ',' ) { commas++; } 225 | if ( commas == count ) { break; } 226 | } 227 | // point to the character after the comma 228 | this_char++; 229 | } 230 | 231 | // did not find the value 232 | if ( commas < count ) { 233 | printf("get_number not found\n"); 234 | n.good = false; 235 | return n; 236 | } 237 | 238 | // is the number negative? 239 | if ( buf[this_char] == '-' ) { 240 | is_neg = true; 241 | this_char++; 242 | } 243 | 244 | // get numerical characters 245 | while( (this_char <= end) && 246 | (buf[this_char]>47) && 247 | (buf[this_char]<58 ) ) { 248 | n.num = ( 10 * n.num ) + ( buf[this_char] - 48 ); 249 | this_char++; 250 | } 251 | 252 | // return 253 | if ( is_neg ) { n.num = -1 * n.num; } 254 | // printf("get_number found %d\n", n.num); 255 | return n; 256 | } 257 | 258 | // write frequency and clock data to the RMT peripheral 259 | void send_freq( char* buf, u16_t start, u16_t end ) { 260 | // frequency settings: [Division Ratio, High Duration, Low Duration] 261 | int freq[3]; 262 | bool good = true; 263 | returnIntVal n; 264 | printf("send_freq %d to %d\n", start, end); 265 | 266 | // division ratio, 8-bit register 267 | n = get_number( buf, start, end, 0 ); 268 | if ( (n.good) && (n.num>0) && (n.num<256) ) { 269 | freq[0] = n.num; 270 | // printf("get_num 0 %d\n", n.num); 271 | } 272 | else { good = false; } 273 | 274 | // clock high duration, 16-bit register 275 | n = get_number( buf, start, end, 1 ); 276 | if ( (n.good) && (n.num>0) && (n.num<65536) ) { 277 | freq[1] = n.num; 278 | // printf("get_num 1 %d\n", n.num); 279 | } 280 | else { good = false; } 281 | 282 | // clock low duration, 16-bit register 283 | n = get_number( buf, start, end, 2 ); 284 | if ( (n.good) && (n.num>0) && (n.num<65536) ) { 285 | freq[2] = n.num; 286 | // printf("get_num 2 %d\n", n.num); 287 | } 288 | else { good = false; } 289 | 290 | // set register values 291 | if ( good ) { 292 | set_rmt_frequency( freq[0], freq[1], freq[2] ); 293 | //printf("Set frequency %d, %d, %d\n", freq[0], freq[1], freq[2]); 294 | } 295 | } 296 | 297 | // write duration data to the RMT RAM 298 | void send_duration( char* buf, u16_t start, u16_t end ) { 299 | u16_t count, c; 300 | returnIntVal val; 301 | bool good = true; 302 | 303 | // the number of comma-separated numeric values on this line 304 | count = count_values(buf, start, end); 305 | 306 | // each 32-bit RMT item holds 2 duration/level values 307 | // divide count of numerical values by 2 get required number of 32-bit values 308 | // multiply by 4 to get bytes 309 | // count: 0 1 2 3 4 5 6 7 8 310 | // count + 1: 1 2 3 4 5 6 7 8 9 311 | // (count + 1) / 2: 0 1 1 2 2 3 3 4 4 312 | // RMT RAM items: 0 1 1 2 2 3 3 4 4 313 | // malloc bytes: 0 4 4 8 8 12 12 16 16 314 | 315 | // number of bytes in the 32-bit RMT item array 316 | size_t size = 4 * ( ( count + 1 ) / 2 ); 317 | rmt_item32_t* items = (rmt_item32_t*) malloc(size); 318 | printf("Row has %i values, allocated %i bytes\n", count, size); 319 | printf("Starts with %c, ends with %c\n", buf[start], buf[end]); 320 | 321 | // create an object for RMT RAM values 322 | for ( c=0; c 0 ) ) { 353 | vTaskDelay( val.num / portTICK_PERIOD_MS ); 354 | printf("Delay %d\n", val.num); 355 | } 356 | } 357 | 358 | // get lines of RMT commands from POST request 359 | // start is first valid character of the request 360 | // end is the last character of the request 361 | void get_request_line( char* buf, u16_t start, u16_t end ) { 362 | u16_t line_start; 363 | u16_t this_char = start; 364 | line_start = start; 365 | while ( this_char <= end ) { 366 | // found end of line, decode it 367 | if ( ( buf[this_char] == '\r' ) || 368 | ( buf[this_char] == '\n' ) || 369 | ( this_char == end ) ) { 370 | printf("Line %d to %d\n", line_start, this_char); 371 | 372 | // ignore newline character at end of this line 373 | if ( ( buf[this_char] == '\r' ) || ( buf[this_char] == '\n' ) ) { 374 | this_char--; 375 | } 376 | // is there anything to decode? 377 | if ( ( this_char - line_start ) > 1 ) { 378 | if ( ( buf[line_start] == 'c' ) && ( buf[line_start+1] == ',' ) ) { 379 | printf("clock\n"); 380 | // send frequency data to the RMT peripheral 381 | send_freq( buf, line_start+2, this_char ); 382 | } 383 | else if ( ( buf[line_start] == 't' ) && ( buf[line_start+1] == ',' ) ) { 384 | printf("transmit\n"); 385 | // turn on the visible LED 386 | gpio_set_level(LED_BUILTIN,1); 387 | 388 | // send duration data to the RMT peripheral 389 | send_duration( buf, line_start+2, this_char ); 390 | 391 | gpio_set_level(LED_BUILTIN,0); 392 | } 393 | else if ( ( buf[line_start] == 'd' ) && ( buf[line_start+1] == ',' ) ) { 394 | printf("delay\n"); 395 | // delay this task 396 | delay_task( buf, line_start+2, this_char ); 397 | } 398 | else { 399 | // do not recognize this line 400 | printf("unknown line\n"); 401 | } 402 | } 403 | // advance to the character AFTER the end of the line 404 | if ( this_char < end ) { this_char++; } 405 | 406 | // skip possible multiple \r and \n 407 | while ( this_char <= end && 408 | ( buf[this_char] == '\r' || buf[this_char] == '\n' ) ) { 409 | this_char++; 410 | } 411 | line_start = this_char; 412 | } 413 | this_char++; 414 | } 415 | } 416 | 417 | // Process an HTTP POST request 418 | static void http_server_netconn_serve(struct netconn *conn) { 419 | struct netbuf *inbuf; 420 | char *buf; 421 | u16_t buflen; 422 | u16_t rmt_start; 423 | err_t err; 424 | 425 | // Read the data from the port, blocking if nothing yet there. 426 | err = netconn_recv(conn, &inbuf); 427 | 428 | printf("Start looking for POST request\n"); 429 | 430 | if (err == ERR_OK) { 431 | netbuf_data(inbuf, (void**)&buf, &buflen); 432 | 433 | // Is this an HTTP POST command? 434 | if ( buflen>5 && 435 | buf[0]=='P' && buf[1]=='O' && buf[2]=='S' && buf[3]=='T' ) { 436 | 437 | printf("Decoding POST request\n"); 438 | 439 | // process the POST request 440 | rmt_start = find_body( buf, buflen ); 441 | if ( rmt_start > 0 ) { 442 | get_request_line( buf, rmt_start, buflen ); 443 | } 444 | 445 | // HTTP Response to POST request 446 | netconn_write(conn, http_html_Accepted, sizeof(http_html_Accepted)-1, NETCONN_NOCOPY); 447 | 448 | // HTTP Debug response, instead of the normal response, echoes the entire request 449 | //netconn_write(conn, http_debug1, sizeof(http_debug1)-1, NETCONN_NOCOPY); 450 | //netconn_write(conn, http_debug2, sizeof(http_debug1)-1, NETCONN_NOCOPY); 451 | //netconn_write(conn, buf, buflen, NETCONN_NOCOPY); 452 | //netconn_write(conn, http_debug3, sizeof(http_debug1)-1, NETCONN_NOCOPY); 453 | 454 | // gpio_set_level(LED_BUILTIN,0); 455 | } 456 | // do not accept non-POST requests 457 | else { 458 | netconn_write(conn, http_html_Not_Allowed, sizeof(http_html_Not_Allowed)-1, NETCONN_NOCOPY); 459 | } 460 | } 461 | // Close the connection 462 | netconn_close(conn); 463 | 464 | // Delete the buffer 465 | netbuf_delete(inbuf); 466 | } 467 | 468 | // HTTP server 469 | static void http_server(void *pvParameters) { 470 | struct netconn *conn, *newconn; 471 | err_t err; 472 | conn = netconn_new(NETCONN_TCP); 473 | netconn_bind(conn, NULL, 80); 474 | netconn_listen(conn); 475 | do { 476 | err = netconn_accept(conn, &newconn); 477 | if (err == ERR_OK) { 478 | http_server_netconn_serve(newconn); 479 | netconn_delete(newconn); 480 | } 481 | } while(err == ERR_OK); 482 | netconn_close(conn); 483 | netconn_delete(conn); 484 | } 485 | 486 | void app_main() { 487 | // set board built-in LED as an output 488 | gpio_pad_select_gpio(LED_BUILTIN); 489 | gpio_set_direction(LED_BUILTIN, GPIO_MODE_OUTPUT); 490 | 491 | // Initialize NVS flash storage 492 | nvs_flash_init(); 493 | 494 | // Initialize the RMT peripheral for output 495 | rmt_tx_init(); 496 | 497 | // Initialize WiFi 498 | initialise_wifi(); 499 | 500 | // HTTP server task 501 | xTaskCreate(&http_server, "http_server", 2048, NULL, 5, NULL); 502 | } 503 | --------------------------------------------------------------------------------