|
| 1 | +/** |
| 2 | + * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: BSD-3-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#include "pico/cyw43_arch.h" |
| 8 | +#include "pico/stdlib.h" |
| 9 | + |
| 10 | +#include "lwip/ip4_addr.h" |
| 11 | +#include "lwip/apps/mdns.h" |
| 12 | +#include "lwip/init.h" |
| 13 | +#include "lwip/apps/httpd.h" |
| 14 | + |
| 15 | +#include "FreeRTOS.h" |
| 16 | +#include "task.h" |
| 17 | + |
| 18 | +void httpd_init(void); |
| 19 | + |
| 20 | +static absolute_time_t wifi_connected_time; |
| 21 | +static bool led_on = false; |
| 22 | + |
| 23 | +#ifndef RUN_FREERTOS_ON_CORE |
| 24 | +#define RUN_FREERTOS_ON_CORE 0 |
| 25 | +#endif |
| 26 | + |
| 27 | +#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL ) |
| 28 | + |
| 29 | +#if LWIP_MDNS_RESPONDER |
| 30 | +static void srv_txt(struct mdns_service *service, void *txt_userdata) |
| 31 | +{ |
| 32 | + err_t res; |
| 33 | + LWIP_UNUSED_ARG(txt_userdata); |
| 34 | + |
| 35 | + res = mdns_resp_add_service_txtitem(service, "path=/", 6); |
| 36 | + LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return); |
| 37 | +} |
| 38 | +#endif |
| 39 | + |
| 40 | +// Return some characters from the ascii representation of the mac address |
| 41 | +// e.g. 112233445566 |
| 42 | +// chr_off is index of character in mac to start |
| 43 | +// chr_len is length of result |
| 44 | +// chr_off=8 and chr_len=4 would return "5566" |
| 45 | +// Return number of characters put into destination |
| 46 | +static size_t get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest_in) { |
| 47 | + static const char hexchr[16] = "0123456789ABCDEF"; |
| 48 | + uint8_t mac[6]; |
| 49 | + char *dest = dest_in; |
| 50 | + assert(chr_off + chr_len <= (2 * sizeof(mac))); |
| 51 | + cyw43_hal_get_mac(idx, mac); |
| 52 | + for (; chr_len && (chr_off >> 1) < sizeof(mac); ++chr_off, --chr_len) { |
| 53 | + *dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf]; |
| 54 | + } |
| 55 | + return dest - dest_in; |
| 56 | +} |
| 57 | + |
| 58 | +static const char *cgi_handler_test(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { |
| 59 | + if (!strcmp(pcParam[0], "test")) { |
| 60 | + return "/test.shtml"; |
| 61 | + } else if (strcmp(pcParam[0], "toggleled") == 0) { |
| 62 | + led_on = !led_on; |
| 63 | + cyw43_gpio_set(&cyw43_state, 0, led_on); |
| 64 | + } |
| 65 | + return "/index.shtml"; |
| 66 | +} |
| 67 | + |
| 68 | +static tCGI cgi_handlers[] = { |
| 69 | + { "/", cgi_handler_test }, |
| 70 | + { "/index.shtml", cgi_handler_test }, |
| 71 | +}; |
| 72 | + |
| 73 | +// Note that the buffer size is limited by LWIP_HTTPD_MAX_TAG_INSERT_LEN, so use LWIP_HTTPD_SSI_MULTIPART to return larger amounts of data |
| 74 | +u16_t ssi_example_ssi_handler(int iIndex, char *pcInsert, int iInsertLen |
| 75 | +#if LWIP_HTTPD_SSI_MULTIPART |
| 76 | + , uint16_t current_tag_part, uint16_t *next_tag_part |
| 77 | +#endif |
| 78 | +) { |
| 79 | + size_t printed; |
| 80 | + switch (iIndex) { |
| 81 | + case 0: { /* "status" */ |
| 82 | + printed = snprintf(pcInsert, iInsertLen, "Pass"); |
| 83 | + break; |
| 84 | + } |
| 85 | + case 1: { /* "welcome" */ |
| 86 | + printed = snprintf(pcInsert, iInsertLen, "Hello from Pico"); |
| 87 | + break; |
| 88 | + } |
| 89 | + case 2: { /* "uptime" */ |
| 90 | + uint64_t uptime_s = absolute_time_diff_us(wifi_connected_time, get_absolute_time()) / 1e6; |
| 91 | + printed = snprintf(pcInsert, iInsertLen, "%"PRIu64, uptime_s); |
| 92 | + break; |
| 93 | + } |
| 94 | + case 3: { // "ledstate" |
| 95 | + printed = snprintf(pcInsert, iInsertLen, "%s", led_on ? "ON" : "OFF"); |
| 96 | + break; |
| 97 | + } |
| 98 | +#if LWIP_HTTPD_SSI_MULTIPART |
| 99 | + case 4: { /* "table" */ |
| 100 | + printed = snprintf(pcInsert, iInsertLen, "<tr><td>This is table row number %d</td></tr>", current_tag_part + 1); |
| 101 | + // Leave "next_tag_part" unchanged to indicate that all data has been returned for this tag |
| 102 | + if (current_tag_part < 9) { |
| 103 | + *next_tag_part = current_tag_part + 1; |
| 104 | + } |
| 105 | + break; |
| 106 | + } |
| 107 | +#endif |
| 108 | + default: { /* unknown tag */ |
| 109 | + printed = 0; |
| 110 | + break; |
| 111 | + } |
| 112 | + } |
| 113 | + return (u16_t)printed; |
| 114 | +} |
| 115 | + |
| 116 | +// Be aware of LWIP_HTTPD_MAX_TAG_NAME_LEN |
| 117 | +static const char * ssi_tags[] = { |
| 118 | + "status", |
| 119 | + "welcome", |
| 120 | + "uptime", |
| 121 | + "ledstate", |
| 122 | + "table", |
| 123 | +}; |
| 124 | + |
| 125 | +void main_task(__unused void *params) { |
| 126 | + if (cyw43_arch_init()) { |
| 127 | + printf("failed to initialise\n"); |
| 128 | + return; |
| 129 | + } |
| 130 | + |
| 131 | + cyw43_arch_enable_sta_mode(); |
| 132 | + |
| 133 | + char hostname[sizeof(CYW43_HOST_NAME) + 4]; |
| 134 | + memcpy(&hostname[0], CYW43_HOST_NAME, sizeof(CYW43_HOST_NAME) - 1); |
| 135 | + get_mac_ascii(CYW43_HAL_MAC_WLAN0, 8, 4, &hostname[sizeof(CYW43_HOST_NAME) - 1]); |
| 136 | + hostname[sizeof(hostname) - 1] = '\0'; |
| 137 | + netif_set_hostname(&cyw43_state.netif[CYW43_ITF_STA], hostname); |
| 138 | + |
| 139 | + printf("Connecting to WiFi...\n"); |
| 140 | + if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { |
| 141 | + printf("failed to connect.\n"); |
| 142 | + exit(1); |
| 143 | + } else { |
| 144 | + printf("Connected.\n"); |
| 145 | + } |
| 146 | + |
| 147 | + wifi_connected_time = get_absolute_time(); |
| 148 | + |
| 149 | +#if LWIP_MDNS_RESPONDER |
| 150 | + mdns_resp_init(); |
| 151 | + printf("mdns host name %s.local\n", hostname); |
| 152 | +#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 2 |
| 153 | + mdns_resp_add_netif(&cyw43_state.netif[CYW43_ITF_STA], hostname); |
| 154 | + mdns_resp_add_service(&cyw43_state.netif[CYW43_ITF_STA], "picow_freertos_httpd", "_http", DNSSD_PROTO_TCP, 80, srv_txt, NULL); |
| 155 | +#else |
| 156 | + mdns_resp_add_netif(&cyw43_state.netif[CYW43_ITF_STA], hostname, 60); |
| 157 | + mdns_resp_add_service(&cyw43_state.netif[CYW43_ITF_STA], "picow_freertos_httpd", "_http", DNSSD_PROTO_TCP, 80, 60, srv_txt, NULL); |
| 158 | +#endif |
| 159 | +#endif |
| 160 | + |
| 161 | + printf("\nReady, running httpd at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list))); |
| 162 | + httpd_init(); |
| 163 | + |
| 164 | + http_set_cgi_handlers(cgi_handlers, LWIP_ARRAYSIZE(cgi_handlers)); |
| 165 | + http_set_ssi_handler(ssi_example_ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags)); |
| 166 | + |
| 167 | + while(true) { |
| 168 | + vTaskDelay(100); |
| 169 | + } |
| 170 | + |
| 171 | +#if LWIP_MDNS_RESPONDER |
| 172 | + mdns_resp_remove_netif(&cyw43_state.netif[CYW43_ITF_STA]); |
| 173 | +#endif |
| 174 | + |
| 175 | + cyw43_arch_deinit(); |
| 176 | +} |
| 177 | + |
| 178 | +void vLaunch( void) { |
| 179 | + TaskHandle_t task; |
| 180 | + xTaskCreate(main_task, "TestMainThread", configMINIMAL_STACK_SIZE, NULL, TEST_TASK_PRIORITY, &task); |
| 181 | + |
| 182 | +#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1 |
| 183 | + // we must bind the main task to one core (well at least while the init is called) |
| 184 | + // (note we only do this in NO_SYS mode, because cyw43_arch_freertos |
| 185 | + // takes care of it otherwise) |
| 186 | + vTaskCoreAffinitySet(task, 1); |
| 187 | +#endif |
| 188 | + |
| 189 | + /* Start the tasks and timer running. */ |
| 190 | + vTaskStartScheduler(); |
| 191 | +} |
| 192 | + |
| 193 | +int main( void ) |
| 194 | +{ |
| 195 | + stdio_init_all(); |
| 196 | + |
| 197 | + /* Configure the hardware ready to run the demo. */ |
| 198 | + const char *rtos_name; |
| 199 | +#if ( portSUPPORT_SMP == 1 ) |
| 200 | + rtos_name = "FreeRTOS SMP"; |
| 201 | +#else |
| 202 | + rtos_name = "FreeRTOS"; |
| 203 | +#endif |
| 204 | + |
| 205 | +#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 ) |
| 206 | + printf("Starting %s on both cores:\n", rtos_name); |
| 207 | + vLaunch(); |
| 208 | +#elif ( RUN_FREE_RTOS_ON_CORE == 1 ) |
| 209 | + printf("Starting %s on core 1:\n", rtos_name); |
| 210 | + multicore_launch_core1(vLaunch); |
| 211 | + while (true); |
| 212 | +#else |
| 213 | + printf("Starting %s on core 0:\n", rtos_name); |
| 214 | + vLaunch(); |
| 215 | +#endif |
| 216 | + return 0; |
| 217 | +} |
0 commit comments