From e4b7b5ba2e1371b142167e75a3ddcd63a0e00a48 Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 31 May 2022 11:39:04 +0200 Subject: style(minion): change eol to LF --- minion/src/wifi_module.cpp | 1302 ++++++++++++++++++++++---------------------- 1 file changed, 651 insertions(+), 651 deletions(-) (limited to 'minion/src/wifi_module.cpp') diff --git a/minion/src/wifi_module.cpp b/minion/src/wifi_module.cpp index 8a2dd6a..51b22dc 100644 --- a/minion/src/wifi_module.cpp +++ b/minion/src/wifi_module.cpp @@ -1,651 +1,651 @@ -#include "wifi_module.hpp" - -#include "network_connection.hpp" -#include "util.hpp" - -#include -#include - -WiFiModule::WiFiModule(const WiFiModuleOptions &options) noexcept - : _serial(options.receive_pin, options.transmit_pin) -{ -} - -void WiFiModule::begin(size_t baudrate) noexcept -{ - _serial.begin(baudrate); -} - -auto WiFiModule::get_available() noexcept -> int -{ - return _serial.available(); -} - -void WiFiModule::reset() noexcept -{ - const auto send_success = _send_serial("AT+RST"); - - if (!send_success) - { - Serial.println(F("Failed to send command to reset wifi module")); - return; - } - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - const auto response_status = _read(2000U, response); - - Serial.println( - response_status == WiFiModuleResponseStatus::OK ? F("Reset wifi module") - : F("Failed to reset wifi module") - ); -} - -auto WiFiModule::connect_to_wifi(const char *ssid, const char *password) noexcept -> bool -{ - const auto cmd = "AT+CWJAP_CUR"; - - auto command_length = - WIFI_CONNECT_COMMAND_BASE_LENGTH + strlen(cmd) + strlen(ssid) + strlen(password); - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - Serial.println( - F("Heap memory allocation failed for creating a wifi connection command") - ); - return false; - } - - snprintf(command, command_length, "%s=\"%s\",\"%s\"", cmd, ssid, password); - - const auto send_success = _send_serial(command); - - if (!send_success) - { - Serial.println(F("Failed to send wifi connect command")); - free(command); - return false; - } - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - const auto response_status = _read(40000U, response); - - return response_status == WiFiModuleResponseStatus::OK; -} - -void WiFiModule::set_wifi_mode(WifiMode wifi_mode) noexcept -{ - const char cmd[] = "AT+CWMODE_CUR"; - - const auto command_length = strlen(cmd) + 2U + 1U; - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - return; - } - - snprintf(command, command_length, "%s=%u", cmd, static_cast(wifi_mode)); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - _read(TIMEOUT_SHORT, response); -} - -void WiFiModule::set_multiple_connections_enabled(bool is_enabled) noexcept -{ - const char cmd[] = "AT+CIPMUX"; - - auto command_length = strlen(cmd) + 2U + 1U; - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - return; - } - - snprintf(command, command_length, "%s=%u", cmd, is_enabled ? 1U : 0U); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - _read(TIMEOUT_SHORT, response); -} - -void WiFiModule::set_echo_enabled(bool is_enabled) noexcept -{ - const char cmd[] = "ATE"; - - auto command_length = strlen(cmd) + 1U + 1U; - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - return; - } - - snprintf(command, command_length, "%s%u", cmd, is_enabled ? 1U : 0U); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - const auto response_status = _read(1500U, response); - - Serial.print( - response_status == WiFiModuleResponseStatus::OK ? F("Turned ") - : F("Failed to turn ") - ); - Serial.print(is_enabled ? F("on") : F("off")); - Serial.println(F(" AT commands echo")); -} - -void WiFiModule::create_tcp_server(size_t port) noexcept -{ - const auto *cmd = "AT+CIPSERVER"; - - auto command_length = CREATE_TCP_SERVER_COMMAND_BASE_LENGTH + strlen(cmd); - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - return; - } - - snprintf(command, command_length, "%s=1,%u", cmd, port); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - _read(TIMEOUT_MEDIUM, response); -} - -auto WiFiModule::test() noexcept -> bool -{ - const auto send_success = _send_serial("AT"); - - if (!send_success) - { - return false; - } - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - const auto response_status = _read(8000U, response); - - if (response_status == WiFiModuleResponseStatus::TIMEOUT) - { - return false; - } - - return strcmp(response, "") != 0; -} - -auto WiFiModule::get_local_ip(char *local_ip_out) noexcept -> const char * -{ - const auto send_success = _send_serial("AT+CIFSR"); - - if (!send_success) - { - return local_ip_out; - } - - auto *buf = util::malloc(strlen(local_ip_out) + 1U); - - if (buf == nullptr) - { - strcpy(local_ip_out, "Memory allocation failure"); - return local_ip_out; - } - - strcpy(buf, ""); - - const auto response_status = _read(10000U, buf); - - if (response_status != WiFiModuleResponseStatus::OK) - { - free(buf); - - sprintf( - local_ip_out, - "Response status was not OK. Was %d", - static_cast(response_status) - ); - - return local_ip_out; - } - - auto local_ip_end = strstr(buf, "\"\r\n+CIFSR:STAMAC"); - - if (local_ip_end == nullptr) - { - free(buf); - strcpy(local_ip_out, "Response parsing error"); - return local_ip_out; - } - - const auto staip_title_length = 16U; // The length of '+CIFSR:STAIP,"' - - util::substr(buf + staip_title_length, local_ip_end, local_ip_out); - - free(buf); - - return local_ip_out; -} - -auto WiFiModule::get_mac_address(char *mac_address_out) noexcept -> const char * -{ - const auto send_success = _send_serial("AT+CIFSR"); - - if (!send_success) - { - return mac_address_out; - } - - auto *buf = util::malloc(strlen(mac_address_out) + 1U); - - if (buf == nullptr) - { - strcpy(mac_address_out, "Memory allocation failure"); - return mac_address_out; - } - - strcpy(buf, ""); - - const auto response_status = _read(10000U, buf); - - if (response_status != WiFiModuleResponseStatus::OK) - { - free(buf); - - sprintf( - mac_address_out, - "Response status was not OK. Was %d", - static_cast(response_status) - ); - - return mac_address_out; - } - - const auto stamac_title = "CIFSR:STAMAC,\""; - - auto mac_address_start = strstr(buf, stamac_title); - - if (mac_address_start == nullptr) - { - free(buf); - strcpy(mac_address_out, "Response parsing error"); - return mac_address_out; - } - - mac_address_start += strlen(stamac_title); - - util::substr(mac_address_start, mac_address_start + 17U, mac_address_out); - - free(buf); - - return mac_address_out; -} - -auto WiFiModule::read_incoming_request() noexcept -> HTTPRequest -{ - char request_prefix[] = "+IPD,"; - - if (get_available() == 0 || !_serial.find(request_prefix)) - { - return HTTPRequest::create_invalid(); - } - - const auto min_available_bytes = 5; - - // Wait for the data buffer a bit - while (get_available() < min_available_bytes) - { - } - - const auto connection = NetworkConnection(_read_connection_id()); - - auto request_data_length = _read_request_data_length(); - - const auto request_method = _read_request_method(request_data_length); - - // Read request path - char request_path[REQUEST_PATH_MAX_LENGTH] = ""; - _read_to(&request_path[0], sizeof(request_path) - 1U, ' ', TIMEOUT_MEDIUM); - - request_data_length -= strlen(request_path) + 1U; - - // Read request HTTP version - char http_version[REQUEST_HTTP_VERSION_MAX_LENGTH] = ""; - _read_to(&http_version[0], sizeof(http_version) - 1U, '\r', TIMEOUT_MEDIUM); - - request_data_length -= strlen(http_version) + 1U; - - // Skip the newline - while (get_available() == 0) - { - } - _serial.read(); - request_data_length -= 1U; - - auto request_data = util::malloc(request_data_length + 1U); - - if (request_data == nullptr) - { - return HTTPRequest::create_invalid(); - } - - strcpy(request_data, ""); - - _read_bytes(request_data, request_data_length, TIMEOUT_LONG); - - free(request_data); - - return HTTPRequest( - connection, - request_method, - http_version, - request_path, - 0, // request_data_length, - nullptr // request_data - ); -} - -auto WiFiModule::close_connection(NetworkConnection &connection) noexcept -> bool -{ - const auto *cmd = "AT+CIPCLOSE"; - - auto command_length = CLOSE_CONNECTION_COMMAND_BASE_LENGTH + strlen(cmd); - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - Serial.println( - F("Heap memory allocation failed for creating close connection command") - ); - return false; - } - - snprintf(command, command_length, "%s=%u", cmd, connection.id()); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - const auto response_status = _read(4000U, response); - - if (response_status != WiFiModuleResponseStatus::OK) - { - Serial.print(F("Failed to close connection to ")); - Serial.println(connection.id()); - Serial.println(response); - return false; - } - - connection.set_is_closed(true); - - Serial.print(F("Closed connection to ")); - Serial.println(connection.id()); - - return true; -} - -auto WiFiModule::send_response( - const NetworkConnection &connection, - size_t status_code, - const char **headers, - size_t headers_cnt, - const char *body -) noexcept -> bool -{ - const auto *cmd = "AT+CIPSEND"; - - auto tot_headers_lengths = 0U; - - for (size_t index = 0U; index < headers_cnt; index++) - { - tot_headers_lengths += strlen(headers[index]) + 2U; - } - - const auto data_length = strlen_P(RESPONSE_HTTP_VERSION) + 1 + - RESPONSE_STATUS_CODE_LENGTH + 4 + strlen(body) + - tot_headers_lengths; - - auto command_length = SEND_RESPONSE_COMMAND_BASE_LENGTH + strlen(cmd) + data_length; - - auto *command = util::malloc(command_length); - - if (command == nullptr) - { - Serial.println( - F("Heap memory allocation failed for creating send response command") - ); - return false; - } - - snprintf(command, command_length, "%s=%u,%u", cmd, connection.id(), data_length); - - _send_serial(command); - - free(command); - - char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; - - _read(TIMEOUT_MEDIUM, response); - - _serial.print(reinterpret_cast(RESPONSE_HTTP_VERSION)); - _serial.print(F(" ")); - _serial.print(status_code); - _serial.print(F("\r\n")); - - // Print headers - for (size_t index = 0U; index < headers_cnt; index++) - { - _serial.print(headers[index]); - _serial.print(F("\r\n")); - } - - _serial.print(F("\r\n")); - _serial.print(body); - - strcpy(response, ""); - - _read(TIMEOUT_MEDIUM, response); - - return true; -} - -auto WiFiModule::_send_serial(const char *command) noexcept -> bool -{ - auto full_command_length = strlen(command) + 2U + 1U; - - auto *full_command = util::malloc(full_command_length); - - if (full_command == nullptr) - { - // NOLINTNEXTLINE(readability-simplify-boolean-expr) - return false; - } - - snprintf(full_command, full_command_length, "%s\r\n", command); - - _serial.print(full_command); - - free(full_command); - - return true; -} - -auto WiFiModule::_read_connection_id() noexcept -> int8_t -{ - const auto connection_id = _serial.read() - ASCII_TO_CHAR; - - // Skip the comma - _serial.read(); - - return static_cast(connection_id); -} - -auto WiFiModule::_read_request_data_length() noexcept -> size_t -{ - char data_length_buf[REQUEST_DATA_LENGTH_BUF_SIZE] = ""; - - _read_to(&data_length_buf[0], sizeof(data_length_buf) - 1U, ':', TIMEOUT_SHORT); - - return static_cast(strtoul(data_length_buf, nullptr, NUMBER_BASE)); -} - -auto WiFiModule::_read_request_method(size_t &request_data_length) noexcept - -> HTTPRequestMethod -{ - char request_method_buf[REQUEST_METHOD_STR_MAX_LENGTH] = ""; - - _read_to( - &request_method_buf[0], - sizeof(request_method_buf) - 1U, - ' ', - TIMEOUT_MEDIUM - ); - - const auto request_method = str_to_http_request_method(request_method_buf); - - request_data_length -= strlen(request_method_buf) + 1U; - - return request_method; -} - -auto WiFiModule::_read(uint64_t timeout, char *response_out) noexcept - -> WiFiModuleResponseStatus -{ - const auto start_time = millis(); - size_t index = 0U; - bool has_end = false; - auto status = WiFiModuleResponseStatus::TIMEOUT; - - while (!has_end && (start_time + timeout) > millis()) - { - while (_serial.available() != 0) - { - char character = _read_byte(); - - if (has_end) - { - continue; - } - - const auto end_pos = index + 1U; - - response_out[index] = character; - response_out[end_pos] = '\0'; - - if (util::str_ends_with(response_out, end_pos, "OK")) - { - status = WiFiModuleResponseStatus::OK; - has_end = true; - } - - if (util::str_ends_with(response_out, end_pos, "ERROR")) - { - status = WiFiModuleResponseStatus::ERROR; - has_end = true; - } - - if (util::str_ends_with(response_out, end_pos, "FAIL")) - { - status = WiFiModuleResponseStatus::FAIL; - has_end = true; - } - - index++; - } - } - - return status; -} - -void WiFiModule::_read_to( - char *buffer_out, - size_t length, // NOLINT(bugprone-easily-swappable-parameters) - char stop_char, - uint64_t timeout -) noexcept -{ - auto position = 0U; - const auto start_time = millis(); - - while (position < length && (start_time + timeout) > millis()) - { - if (get_available() == 0) - { - continue; - } - - auto character = _read_byte(); - - if (character == stop_char) - { - break; - } - - buffer_out[position++] = character; - } - - buffer_out[position] = '\0'; -} - -// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -void WiFiModule::_read_bytes(char *buffer_out, size_t length, uint64_t timeout) noexcept -{ - const auto original_length = length; - - auto position = 0U; - const auto start_time = millis(); - - while (position != length && (start_time + timeout) > millis()) - { - if (get_available() == 0) - { - continue; - } - - char character = _read_byte(); - - buffer_out[position++] = character; - - if (character == '\n' && position != original_length) - { - length -= 2U; - } - } - - buffer_out[position] = '\0'; -} - -auto WiFiModule::_read_byte() noexcept -> char -{ - return static_cast(_serial.read()); -} +#include "wifi_module.hpp" + +#include "network_connection.hpp" +#include "util.hpp" + +#include +#include + +WiFiModule::WiFiModule(const WiFiModuleOptions &options) noexcept + : _serial(options.receive_pin, options.transmit_pin) +{ +} + +void WiFiModule::begin(size_t baudrate) noexcept +{ + _serial.begin(baudrate); +} + +auto WiFiModule::get_available() noexcept -> int +{ + return _serial.available(); +} + +void WiFiModule::reset() noexcept +{ + const auto send_success = _send_serial("AT+RST"); + + if (!send_success) + { + Serial.println(F("Failed to send command to reset wifi module")); + return; + } + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + const auto response_status = _read(2000U, response); + + Serial.println( + response_status == WiFiModuleResponseStatus::OK ? F("Reset wifi module") + : F("Failed to reset wifi module") + ); +} + +auto WiFiModule::connect_to_wifi(const char *ssid, const char *password) noexcept -> bool +{ + const auto cmd = "AT+CWJAP_CUR"; + + auto command_length = + WIFI_CONNECT_COMMAND_BASE_LENGTH + strlen(cmd) + strlen(ssid) + strlen(password); + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + Serial.println( + F("Heap memory allocation failed for creating a wifi connection command") + ); + return false; + } + + snprintf(command, command_length, "%s=\"%s\",\"%s\"", cmd, ssid, password); + + const auto send_success = _send_serial(command); + + if (!send_success) + { + Serial.println(F("Failed to send wifi connect command")); + free(command); + return false; + } + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + const auto response_status = _read(40000U, response); + + return response_status == WiFiModuleResponseStatus::OK; +} + +void WiFiModule::set_wifi_mode(WifiMode wifi_mode) noexcept +{ + const char cmd[] = "AT+CWMODE_CUR"; + + const auto command_length = strlen(cmd) + 2U + 1U; + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + return; + } + + snprintf(command, command_length, "%s=%u", cmd, static_cast(wifi_mode)); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + _read(TIMEOUT_SHORT, response); +} + +void WiFiModule::set_multiple_connections_enabled(bool is_enabled) noexcept +{ + const char cmd[] = "AT+CIPMUX"; + + auto command_length = strlen(cmd) + 2U + 1U; + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + return; + } + + snprintf(command, command_length, "%s=%u", cmd, is_enabled ? 1U : 0U); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + _read(TIMEOUT_SHORT, response); +} + +void WiFiModule::set_echo_enabled(bool is_enabled) noexcept +{ + const char cmd[] = "ATE"; + + auto command_length = strlen(cmd) + 1U + 1U; + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + return; + } + + snprintf(command, command_length, "%s%u", cmd, is_enabled ? 1U : 0U); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + const auto response_status = _read(1500U, response); + + Serial.print( + response_status == WiFiModuleResponseStatus::OK ? F("Turned ") + : F("Failed to turn ") + ); + Serial.print(is_enabled ? F("on") : F("off")); + Serial.println(F(" AT commands echo")); +} + +void WiFiModule::create_tcp_server(size_t port) noexcept +{ + const auto *cmd = "AT+CIPSERVER"; + + auto command_length = CREATE_TCP_SERVER_COMMAND_BASE_LENGTH + strlen(cmd); + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + return; + } + + snprintf(command, command_length, "%s=1,%u", cmd, port); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + _read(TIMEOUT_MEDIUM, response); +} + +auto WiFiModule::test() noexcept -> bool +{ + const auto send_success = _send_serial("AT"); + + if (!send_success) + { + return false; + } + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + const auto response_status = _read(8000U, response); + + if (response_status == WiFiModuleResponseStatus::TIMEOUT) + { + return false; + } + + return strcmp(response, "") != 0; +} + +auto WiFiModule::get_local_ip(char *local_ip_out) noexcept -> const char * +{ + const auto send_success = _send_serial("AT+CIFSR"); + + if (!send_success) + { + return local_ip_out; + } + + auto *buf = util::malloc(strlen(local_ip_out) + 1U); + + if (buf == nullptr) + { + strcpy(local_ip_out, "Memory allocation failure"); + return local_ip_out; + } + + strcpy(buf, ""); + + const auto response_status = _read(10000U, buf); + + if (response_status != WiFiModuleResponseStatus::OK) + { + free(buf); + + sprintf( + local_ip_out, + "Response status was not OK. Was %d", + static_cast(response_status) + ); + + return local_ip_out; + } + + auto local_ip_end = strstr(buf, "\"\r\n+CIFSR:STAMAC"); + + if (local_ip_end == nullptr) + { + free(buf); + strcpy(local_ip_out, "Response parsing error"); + return local_ip_out; + } + + const auto staip_title_length = 16U; // The length of '+CIFSR:STAIP,"' + + util::substr(buf + staip_title_length, local_ip_end, local_ip_out); + + free(buf); + + return local_ip_out; +} + +auto WiFiModule::get_mac_address(char *mac_address_out) noexcept -> const char * +{ + const auto send_success = _send_serial("AT+CIFSR"); + + if (!send_success) + { + return mac_address_out; + } + + auto *buf = util::malloc(strlen(mac_address_out) + 1U); + + if (buf == nullptr) + { + strcpy(mac_address_out, "Memory allocation failure"); + return mac_address_out; + } + + strcpy(buf, ""); + + const auto response_status = _read(10000U, buf); + + if (response_status != WiFiModuleResponseStatus::OK) + { + free(buf); + + sprintf( + mac_address_out, + "Response status was not OK. Was %d", + static_cast(response_status) + ); + + return mac_address_out; + } + + const auto stamac_title = "CIFSR:STAMAC,\""; + + auto mac_address_start = strstr(buf, stamac_title); + + if (mac_address_start == nullptr) + { + free(buf); + strcpy(mac_address_out, "Response parsing error"); + return mac_address_out; + } + + mac_address_start += strlen(stamac_title); + + util::substr(mac_address_start, mac_address_start + 17U, mac_address_out); + + free(buf); + + return mac_address_out; +} + +auto WiFiModule::read_incoming_request() noexcept -> HTTPRequest +{ + char request_prefix[] = "+IPD,"; + + if (get_available() == 0 || !_serial.find(request_prefix)) + { + return HTTPRequest::create_invalid(); + } + + const auto min_available_bytes = 5; + + // Wait for the data buffer a bit + while (get_available() < min_available_bytes) + { + } + + const auto connection = NetworkConnection(_read_connection_id()); + + auto request_data_length = _read_request_data_length(); + + const auto request_method = _read_request_method(request_data_length); + + // Read request path + char request_path[REQUEST_PATH_MAX_LENGTH] = ""; + _read_to(&request_path[0], sizeof(request_path) - 1U, ' ', TIMEOUT_MEDIUM); + + request_data_length -= strlen(request_path) + 1U; + + // Read request HTTP version + char http_version[REQUEST_HTTP_VERSION_MAX_LENGTH] = ""; + _read_to(&http_version[0], sizeof(http_version) - 1U, '\r', TIMEOUT_MEDIUM); + + request_data_length -= strlen(http_version) + 1U; + + // Skip the newline + while (get_available() == 0) + { + } + _serial.read(); + request_data_length -= 1U; + + auto request_data = util::malloc(request_data_length + 1U); + + if (request_data == nullptr) + { + return HTTPRequest::create_invalid(); + } + + strcpy(request_data, ""); + + _read_bytes(request_data, request_data_length, TIMEOUT_LONG); + + free(request_data); + + return HTTPRequest( + connection, + request_method, + http_version, + request_path, + 0, // request_data_length, + nullptr // request_data + ); +} + +auto WiFiModule::close_connection(NetworkConnection &connection) noexcept -> bool +{ + const auto *cmd = "AT+CIPCLOSE"; + + auto command_length = CLOSE_CONNECTION_COMMAND_BASE_LENGTH + strlen(cmd); + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + Serial.println( + F("Heap memory allocation failed for creating close connection command") + ); + return false; + } + + snprintf(command, command_length, "%s=%u", cmd, connection.id()); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + const auto response_status = _read(4000U, response); + + if (response_status != WiFiModuleResponseStatus::OK) + { + Serial.print(F("Failed to close connection to ")); + Serial.println(connection.id()); + Serial.println(response); + return false; + } + + connection.set_is_closed(true); + + Serial.print(F("Closed connection to ")); + Serial.println(connection.id()); + + return true; +} + +auto WiFiModule::send_response( + const NetworkConnection &connection, + size_t status_code, + const char **headers, + size_t headers_cnt, + const char *body +) noexcept -> bool +{ + const auto *cmd = "AT+CIPSEND"; + + auto tot_headers_lengths = 0U; + + for (size_t index = 0U; index < headers_cnt; index++) + { + tot_headers_lengths += strlen(headers[index]) + 2U; + } + + const auto data_length = strlen_P(RESPONSE_HTTP_VERSION) + 1 + + RESPONSE_STATUS_CODE_LENGTH + 4 + strlen(body) + + tot_headers_lengths; + + auto command_length = SEND_RESPONSE_COMMAND_BASE_LENGTH + strlen(cmd) + data_length; + + auto *command = util::malloc(command_length); + + if (command == nullptr) + { + Serial.println( + F("Heap memory allocation failed for creating send response command") + ); + return false; + } + + snprintf(command, command_length, "%s=%u,%u", cmd, connection.id(), data_length); + + _send_serial(command); + + free(command); + + char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = ""; + + _read(TIMEOUT_MEDIUM, response); + + _serial.print(reinterpret_cast(RESPONSE_HTTP_VERSION)); + _serial.print(F(" ")); + _serial.print(status_code); + _serial.print(F("\r\n")); + + // Print headers + for (size_t index = 0U; index < headers_cnt; index++) + { + _serial.print(headers[index]); + _serial.print(F("\r\n")); + } + + _serial.print(F("\r\n")); + _serial.print(body); + + strcpy(response, ""); + + _read(TIMEOUT_MEDIUM, response); + + return true; +} + +auto WiFiModule::_send_serial(const char *command) noexcept -> bool +{ + auto full_command_length = strlen(command) + 2U + 1U; + + auto *full_command = util::malloc(full_command_length); + + if (full_command == nullptr) + { + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + return false; + } + + snprintf(full_command, full_command_length, "%s\r\n", command); + + _serial.print(full_command); + + free(full_command); + + return true; +} + +auto WiFiModule::_read_connection_id() noexcept -> int8_t +{ + const auto connection_id = _serial.read() - ASCII_TO_CHAR; + + // Skip the comma + _serial.read(); + + return static_cast(connection_id); +} + +auto WiFiModule::_read_request_data_length() noexcept -> size_t +{ + char data_length_buf[REQUEST_DATA_LENGTH_BUF_SIZE] = ""; + + _read_to(&data_length_buf[0], sizeof(data_length_buf) - 1U, ':', TIMEOUT_SHORT); + + return static_cast(strtoul(data_length_buf, nullptr, NUMBER_BASE)); +} + +auto WiFiModule::_read_request_method(size_t &request_data_length) noexcept + -> HTTPRequestMethod +{ + char request_method_buf[REQUEST_METHOD_STR_MAX_LENGTH] = ""; + + _read_to( + &request_method_buf[0], + sizeof(request_method_buf) - 1U, + ' ', + TIMEOUT_MEDIUM + ); + + const auto request_method = str_to_http_request_method(request_method_buf); + + request_data_length -= strlen(request_method_buf) + 1U; + + return request_method; +} + +auto WiFiModule::_read(uint64_t timeout, char *response_out) noexcept + -> WiFiModuleResponseStatus +{ + const auto start_time = millis(); + size_t index = 0U; + bool has_end = false; + auto status = WiFiModuleResponseStatus::TIMEOUT; + + while (!has_end && (start_time + timeout) > millis()) + { + while (_serial.available() != 0) + { + char character = _read_byte(); + + if (has_end) + { + continue; + } + + const auto end_pos = index + 1U; + + response_out[index] = character; + response_out[end_pos] = '\0'; + + if (util::str_ends_with(response_out, end_pos, "OK")) + { + status = WiFiModuleResponseStatus::OK; + has_end = true; + } + + if (util::str_ends_with(response_out, end_pos, "ERROR")) + { + status = WiFiModuleResponseStatus::ERROR; + has_end = true; + } + + if (util::str_ends_with(response_out, end_pos, "FAIL")) + { + status = WiFiModuleResponseStatus::FAIL; + has_end = true; + } + + index++; + } + } + + return status; +} + +void WiFiModule::_read_to( + char *buffer_out, + size_t length, // NOLINT(bugprone-easily-swappable-parameters) + char stop_char, + uint64_t timeout +) noexcept +{ + auto position = 0U; + const auto start_time = millis(); + + while (position < length && (start_time + timeout) > millis()) + { + if (get_available() == 0) + { + continue; + } + + auto character = _read_byte(); + + if (character == stop_char) + { + break; + } + + buffer_out[position++] = character; + } + + buffer_out[position] = '\0'; +} + +// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) +void WiFiModule::_read_bytes(char *buffer_out, size_t length, uint64_t timeout) noexcept +{ + const auto original_length = length; + + auto position = 0U; + const auto start_time = millis(); + + while (position != length && (start_time + timeout) > millis()) + { + if (get_available() == 0) + { + continue; + } + + char character = _read_byte(); + + buffer_out[position++] = character; + + if (character == '\n' && position != original_length) + { + length -= 2U; + } + } + + buffer_out[position] = '\0'; +} + +auto WiFiModule::_read_byte() noexcept -> char +{ + return static_cast(_serial.read()); +} -- cgit v1.2.3-18-g5258