aboutsummaryrefslogtreecommitdiff
path: root/stm32f091/server.c
blob: 1d4a4690135204bdfd56827edd028aa18f22267b (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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#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"
#include "util.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,

	.rc = { 0 },
};

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_head = 0;
static unsigned int g_ws_esp8266_dma_tx_buffer_tail = 0;
static unsigned int g_ws_esp8266_dma_tx_buffer_cs = 0; // chunk size

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;
	}
}

static bool ws_server_is_response(char data, uint8_t* counter, const char* cmd, unsigned short cmd_len) {
	if (data == cmd[*counter]) *counter += 1;
	else *counter = 0;
	if (*counter == cmd_len) return true;
	return false;
}

void ws_server_req_incoming(uint8_t* data, size_t size) {
#ifdef WS_DBG_PRINT_ESP_OVER_USART2
	ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_RX);
	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 (ws_server_is_response(byte, &g_ws_server_parser.rc.s_ok, "OK", 2)) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_OK;
				} else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_error, "ERROR", 5)) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_ERR;
				} else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_fail, "FAIL", 4)) {
					code_got = true;
					g_ws_server_parser.last_response = WS_SERVER_RC_ERR;
				} else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_busy, "busy p...", 9)) {
					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 (ws_server_is_response(byte, &g_ws_server_parser.rc.i_ipd, "+IPD,", 5)) {
					g_ws_server_parser.mode = WS_SERVER_LM_IPD_LISTENING;
				} else if (ws_server_is_response(byte, &g_ws_server_parser.rc.i_prompt, ">", 1)) {
					// ^^^ this is ">" on official espressif firmware, "> " on ai-thinker firmware
					g_ws_server_parser.mode = WS_SERVER_LM_CIPSEND_LISTENING;
					ws_server_buffer_send_chunk();
				}
				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;
							ws_server_buffer_request_chunk_send();
						}
						break;
					}
					default: {}
				}
				break;
			}
			case WS_SERVER_LM_CIPSEND_LISTENING: {
				if (ws_server_is_response(byte, &g_ws_server_parser.rc.l_send_ok, "SEND OK", 7) || ws_server_is_response(byte, &g_ws_server_parser.rc.l_error, "ERROR", 5)) {
					ws_server_buffer_request_chunk_send();
				}
				break;
			}
			default: {}
		}
	}
}

/** @brief get amount of bytes in g_ws_esp8266_dma_tx_buffer until \n */
static unsigned int ws_server_next_line_length() {
	for (unsigned int i = g_ws_esp8266_dma_tx_buffer_tail; i <= g_ws_esp8266_dma_tx_buffer_head; i++)
		if (g_ws_esp8266_dma_tx_buffer[i] == '\n') return i - g_ws_esp8266_dma_tx_buffer_tail + 1;
	return g_ws_esp8266_dma_tx_buffer_head - g_ws_esp8266_dma_tx_buffer_tail;
}

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) {
  size_t limited_size = WS_MIN(size, g_ws_esp8266_dma_tx_buffer_head - g_ws_esp8266_dma_tx_buffer_tail);
	strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_head], (char*) data, limited_size); // append string
	g_ws_esp8266_dma_tx_buffer_head += size; // shift head
}

void ws_server_buffer_request_chunk_send() {
	g_ws_esp8266_dma_tx_buffer_cs = ws_server_next_line_length();

	char* cmd = NULL;
	size_t len;

	if (g_ws_esp8266_dma_tx_buffer_cs > 0) {
		len = asiprintf(&cmd, "AT+CIPSEND=%d,%d\r\n", g_ws_server_parser.current_channel, g_ws_esp8266_dma_tx_buffer_cs);
	} else {
		len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", g_ws_server_parser.current_channel);
	}
	free(cmd);

	g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO;

#ifdef WS_DBG_PRINT_ESP_OVER_USART2
	ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX);
	HAL_UART_Transmit(&huart2, (uint8_t*) cmd, len, 100);
#endif
	HAL_UART_Transmit(&huart1, (uint8_t*) cmd, len, 100);
}

void ws_server_buffer_send_chunk() {
#ifdef WS_DBG_PRINT_ESP_OVER_USART2
	ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX);
 	HAL_UART_Transmit(&huart2, &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_tail], g_ws_esp8266_dma_tx_buffer_cs, 100);
#endif
 	HAL_UART_Transmit(&huart1, &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_tail], g_ws_esp8266_dma_tx_buffer_cs, 100);
	g_ws_esp8266_dma_tx_buffer_tail += g_ws_esp8266_dma_tx_buffer_cs;

	if (g_ws_esp8266_dma_tx_buffer_head == g_ws_esp8266_dma_tx_buffer_tail) {
		g_ws_esp8266_dma_tx_buffer_head = g_ws_esp8266_dma_tx_buffer_tail = 0;
	}
}