aboutsummaryrefslogtreecommitdiff
path: root/stm32f091/server.c
blob: 80013809ccea8c8481d071cd7437a34f3f7f26e6 (plain)
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
#include <stm32f0xx_hal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../shared/protocol.h"
#include "esp8266.h"
#include "server.h"
#include "setup.h"
#include "consts.h"

ws_s_server_parser g_ws_server_parser = {
	.last_response = WS_SERVER_RC_NONE,
	.mode = WS_SERVER_LM_IDLE,

	.current_channel = 0,
	.channel_data_length = 0,
	.channel_data_counter = 0,
	.channel_listen_mode = WS_SERVER_CL_CHANNEL_ID,
};

static ws_s_protocol_req_parser_state* g_ws_protocol_parsers[WS_SERVER_MAX_CHANNELS] = {0};
static unsigned int g_ws_esp8266_dma_tx_buffer_index = 0;

void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore) {
	if (ignore) return;
	if (channel >= WS_SERVER_MAX_CHANNELS) return;

	if (g_ws_protocol_parsers[channel] == NULL) {
		g_ws_protocol_parsers[channel] = ws_protocol_req_parser_alloc();
	}

	ws_protocol_parse_req_byte(g_ws_protocol_parsers[channel], byte);
}

void ws_server_req_finish(unsigned int channel, bool ignore) {
	if (ignore) return;
	if (channel >= WS_SERVER_MAX_CHANNELS) return;
	
	if (g_ws_protocol_parsers[channel] != NULL) {
		ws_protocol_req_parser_free(g_ws_protocol_parsers[channel]);
		g_ws_protocol_parsers[channel] = NULL;
	}
}

// TODO: next_few_bytes_are assumes that the complete search string is in the
// buffer, so won't work for buffer cutoffs
#define next_few_bytes_are(code) (i + sizeof(code) - 1 < size && strncmp((char*)&data[i], code, sizeof(code) - 1) == 0)
void ws_server_req_incoming(uint8_t* data, size_t size) {
#ifdef WS_DBG_PRINT_ESP_OVER_USART2
	uint8_t red[] = { 0x1b, 0x5b, 0x33, 0x31, 0x6d };
	HAL_UART_Transmit(&huart2, red, sizeof(red), 100);
	HAL_UART_Transmit(&huart2, data, size, 100);
#endif

	for (unsigned int i = 0; i < size; i++) {
		uint8_t byte = data[i];

		switch (g_ws_server_parser.mode) {
			case WS_SERVER_LM_CMD_ECHO: {
				if (byte == '\n') g_ws_server_parser.mode = WS_SERVER_LM_STATUS_CODE;
				break;
			}
			case WS_SERVER_LM_STATUS_CODE: {
				bool code_got = false;
				if (next_few_bytes_are("OK")) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_OK;
				} else if (next_few_bytes_are("ERROR") || next_few_bytes_are("FAIL")) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_ERR;
				} else if (next_few_bytes_are("busy p...")) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_BUSY;
				}
				if (code_got) g_ws_server_parser.mode = WS_SERVER_LM_IDLE;
				break;
			}
			case WS_SERVER_LM_IDLE: {
				if (next_few_bytes_are("+IPD,")) {
					i += 4; // skip I, P, D, and comma
					g_ws_server_parser.mode = WS_SERVER_LM_IPD_LISTENING;
				} else if (byte == '>') {
					g_ws_server_parser.mode = WS_SERVER_LM_CIPSEND_LISTENING;
					ws_server_buffer_send_finish();
				}
				break;
			}
			case WS_SERVER_LM_IPD_LISTENING: {
					switch (g_ws_server_parser.channel_listen_mode) {
						case WS_SERVER_CL_CHANNEL_ID: {
							if (byte == ',') {
								g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_DATA_LENGTH;
								break;
							}
							g_ws_server_parser.current_channel *= 10;
							g_ws_server_parser.current_channel += byte - '0'; // ascii to int
							break;
						}
						case WS_SERVER_CL_DATA_LENGTH: {
							if (byte == ':') {
								g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_DATA_READ;
								if (g_ws_server_parser.channel_data_length > WS_PROTOCOL_CMD_BUFFER_LEN)
									g_ws_server_parser.channel_data_ignore = true;
								break;
							}
							g_ws_server_parser.channel_data_length *= 10;
							g_ws_server_parser.channel_data_length += byte - '0'; // ascii to int
							break;
						}
						case WS_SERVER_CL_DATA_READ: {
							ws_server_req_parse_byte(g_ws_server_parser.current_channel, byte, g_ws_server_parser.channel_data_ignore);
							g_ws_server_parser.channel_data_counter++;
							if (g_ws_server_parser.channel_data_counter == g_ws_server_parser.channel_data_length) {
								g_ws_server_parser.current_channel = 0;
								g_ws_server_parser.channel_data_counter = 0;
								g_ws_server_parser.channel_data_length = 0;
								g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_CHANNEL_ID;
								ws_server_req_finish(g_ws_server_parser.current_channel, g_ws_server_parser.channel_data_ignore);
								g_ws_server_parser.mode = WS_SERVER_LM_IDLE;
							}
							break;
						}
						default: {}
					}
				break;
			}
			case WS_SERVER_LM_CIPSEND_LISTENING: {
				if (next_few_bytes_are("SEND OK")) {
					ws_server_req_respond_end(0);
					// g_ws_server_parser.mode = WS_SERVER_LM_IDLE;
				}
				break;
			}
			default: {}
		}
	}
}

void ws_server_send(uint8_t* data, size_t size) {
	g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO;
	ws_esp8266_send(data, size);
	while (g_ws_server_parser.mode != WS_SERVER_LM_IDLE) {};
}

void ws_server_buffer_send_append(uint8_t* data, size_t size) {
	// TODO: buffer overrun protection
	// while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); // make sure buffer isn't used
	strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_index], (char*) data, size); // append string
	g_ws_esp8266_dma_tx_buffer_index += size; // shift head
}

void ws_server_buffer_send_finish() {
#ifdef WS_DBG_PRINT_ESP_OVER_USART2
	uint8_t green[] = { 0x1b, 0x5b, 0x33, 0x32, 0x6d };
	HAL_UART_Transmit(&huart2, green, sizeof(green), 100);
	HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer), 100);
#endif

	HAL_UART_Transmit_DMA(&huart1, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer));
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
	g_ws_esp8266_dma_tx_buffer_index = 0;
	while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2));
}

void ws_server_req_respond_start(unsigned int channel, size_t size) {
	char* cmd = NULL;
	size_t len = asiprintf(&cmd, "AT+CIPSEND=%d,%d\r\n", channel, size);
	g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO;
	ws_esp8266_send((uint8_t*) cmd, len);
	while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2));
}

void ws_server_req_respond_end(unsigned int channel) {
	char* cmd = NULL;
	size_t len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", channel);
	g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO;
	ws_esp8266_send((uint8_t*) cmd, len);
	while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2));
}