-
Notifications
You must be signed in to change notification settings - Fork 905
/
Copy pathpico_freertos_httpd.c
217 lines (186 loc) · 6.48 KB
/
pico_freertos_httpd.c
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
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#include "lwip/ip4_addr.h"
#include "lwip/apps/mdns.h"
#include "lwip/init.h"
#include "lwip/apps/httpd.h"
#include "FreeRTOS.h"
#include "task.h"
void httpd_init(void);
static absolute_time_t wifi_connected_time;
static bool led_on = false;
#ifndef RUN_FREERTOS_ON_CORE
#define RUN_FREERTOS_ON_CORE 0
#endif
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )
#if LWIP_MDNS_RESPONDER
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
err_t res;
LWIP_UNUSED_ARG(txt_userdata);
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
#endif
// Return some characters from the ascii representation of the mac address
// e.g. 112233445566
// chr_off is index of character in mac to start
// chr_len is length of result
// chr_off=8 and chr_len=4 would return "5566"
// Return number of characters put into destination
static size_t get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest_in) {
static const char hexchr[16] = "0123456789ABCDEF";
uint8_t mac[6];
char *dest = dest_in;
assert(chr_off + chr_len <= (2 * sizeof(mac)));
cyw43_hal_get_mac(idx, mac);
for (; chr_len && (chr_off >> 1) < sizeof(mac); ++chr_off, --chr_len) {
*dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
}
return dest - dest_in;
}
static const char *cgi_handler_test(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
if (!strcmp(pcParam[0], "test")) {
return "/test.shtml";
} else if (strcmp(pcParam[0], "toggleled") == 0) {
led_on = !led_on;
cyw43_gpio_set(&cyw43_state, 0, led_on);
}
return "/index.shtml";
}
static tCGI cgi_handlers[] = {
{ "/", cgi_handler_test },
{ "/index.shtml", cgi_handler_test },
};
// 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
u16_t ssi_example_ssi_handler(int iIndex, char *pcInsert, int iInsertLen
#if LWIP_HTTPD_SSI_MULTIPART
, uint16_t current_tag_part, uint16_t *next_tag_part
#endif
) {
size_t printed;
switch (iIndex) {
case 0: { /* "status" */
printed = snprintf(pcInsert, iInsertLen, "Pass");
break;
}
case 1: { /* "welcome" */
printed = snprintf(pcInsert, iInsertLen, "Hello from Pico");
break;
}
case 2: { /* "uptime" */
uint64_t uptime_s = absolute_time_diff_us(wifi_connected_time, get_absolute_time()) / 1e6;
printed = snprintf(pcInsert, iInsertLen, "%"PRIu64, uptime_s);
break;
}
case 3: { // "ledstate"
printed = snprintf(pcInsert, iInsertLen, "%s", led_on ? "ON" : "OFF");
break;
}
#if LWIP_HTTPD_SSI_MULTIPART
case 4: { /* "table" */
printed = snprintf(pcInsert, iInsertLen, "<tr><td>This is table row number %d</td></tr>", current_tag_part + 1);
// Leave "next_tag_part" unchanged to indicate that all data has been returned for this tag
if (current_tag_part < 9) {
*next_tag_part = current_tag_part + 1;
}
break;
}
#endif
default: { /* unknown tag */
printed = 0;
break;
}
}
return (u16_t)printed;
}
// Be aware of LWIP_HTTPD_MAX_TAG_NAME_LEN
static const char * ssi_tags[] = {
"status",
"welcome",
"uptime",
"ledstate",
"table",
};
void main_task(__unused void *params) {
if (cyw43_arch_init()) {
printf("failed to initialise\n");
return;
}
cyw43_arch_enable_sta_mode();
char hostname[sizeof(CYW43_HOST_NAME) + 4];
memcpy(&hostname[0], CYW43_HOST_NAME, sizeof(CYW43_HOST_NAME) - 1);
get_mac_ascii(CYW43_HAL_MAC_WLAN0, 8, 4, &hostname[sizeof(CYW43_HOST_NAME) - 1]);
hostname[sizeof(hostname) - 1] = '\0';
netif_set_hostname(&cyw43_state.netif[CYW43_ITF_STA], hostname);
printf("Connecting to WiFi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
exit(1);
} else {
printf("Connected.\n");
}
wifi_connected_time = get_absolute_time();
#if LWIP_MDNS_RESPONDER
mdns_resp_init();
printf("mdns host name %s.local\n", hostname);
#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 2
mdns_resp_add_netif(&cyw43_state.netif[CYW43_ITF_STA], hostname);
mdns_resp_add_service(&cyw43_state.netif[CYW43_ITF_STA], "picow_freertos_httpd", "_http", DNSSD_PROTO_TCP, 80, srv_txt, NULL);
#else
mdns_resp_add_netif(&cyw43_state.netif[CYW43_ITF_STA], hostname, 60);
mdns_resp_add_service(&cyw43_state.netif[CYW43_ITF_STA], "picow_freertos_httpd", "_http", DNSSD_PROTO_TCP, 80, 60, srv_txt, NULL);
#endif
#endif
printf("\nReady, running httpd at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
httpd_init();
http_set_cgi_handlers(cgi_handlers, LWIP_ARRAYSIZE(cgi_handlers));
http_set_ssi_handler(ssi_example_ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
while(true) {
vTaskDelay(100);
}
#if LWIP_MDNS_RESPONDER
mdns_resp_remove_netif(&cyw43_state.netif[CYW43_ITF_STA]);
#endif
cyw43_arch_deinit();
}
void vLaunch( void) {
TaskHandle_t task;
xTaskCreate(main_task, "TestMainThread", configMINIMAL_STACK_SIZE, NULL, TEST_TASK_PRIORITY, &task);
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
// we must bind the main task to one core (well at least while the init is called)
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
// takes care of it otherwise)
vTaskCoreAffinitySet(task, 1);
#endif
/* Start the tasks and timer running. */
vTaskStartScheduler();
}
int main( void )
{
stdio_init_all();
/* Configure the hardware ready to run the demo. */
const char *rtos_name;
#if ( portSUPPORT_SMP == 1 )
rtos_name = "FreeRTOS SMP";
#else
rtos_name = "FreeRTOS";
#endif
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
printf("Starting %s on both cores:\n", rtos_name);
vLaunch();
#elif ( RUN_FREE_RTOS_ON_CORE == 1 )
printf("Starting %s on core 1:\n", rtos_name);
multicore_launch_core1(vLaunch);
while (true);
#else
printf("Starting %s on core 0:\n", rtos_name);
vLaunch();
#endif
return 0;
}