summaryrefslogtreecommitdiff
path: root/minion
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-05-10 15:47:05 +0200
committerHampusM <hampus@hampusmat.com>2022-05-11 23:14:41 +0200
commit05cf212e79728c2bf1449ee5cfdf7dd6b1a8c4fd (patch)
treef613790a2df7b0ac6a5a339f83e43dbd9d547a6a /minion
parent6decaf83fc2b1e751876a76d72c4370b3b66a507 (diff)
refactor(minion): create request class
Diffstat (limited to 'minion')
-rw-r--r--minion/src/gymnasiearbete.cpp42
-rw-r--r--minion/src/http/request.cpp107
-rw-r--r--minion/src/http/request.hpp65
-rw-r--r--minion/src/util.cpp9
-rw-r--r--minion/src/util.hpp16
-rw-r--r--minion/src/wifi_module.cpp162
-rw-r--r--minion/src/wifi_module.hpp30
7 files changed, 365 insertions, 66 deletions
diff --git a/minion/src/gymnasiearbete.cpp b/minion/src/gymnasiearbete.cpp
index 927cd1c..30e5605 100644
--- a/minion/src/gymnasiearbete.cpp
+++ b/minion/src/gymnasiearbete.cpp
@@ -1,3 +1,4 @@
+#include "http/request.hpp"
#include "secrets.hpp"
#include "wifi_module.hpp"
@@ -9,13 +10,11 @@ constexpr auto HTTP_PORT = 80U;
constexpr auto BAUDRATE = 9600U;
-constexpr auto NETWORK_MODULE_RX_PIN = 3;
-constexpr auto NETWORK_MODULE_TX_PIN = 2;
+constexpr auto NETWORK_MODULE_RX_PIN = 13U;
+constexpr auto NETWORK_MODULE_TX_PIN = 11U;
constexpr auto SECOND_IN_MILLIS = 1000U;
-constexpr auto MAX_HTTP_REQUEST_SIZE = 200U;
-
auto wifi_module = WiFiModule({ NETWORK_MODULE_RX_PIN, NETWORK_MODULE_TX_PIN });
void setup()
@@ -74,22 +73,35 @@ void setup()
void loop()
{
- if (wifi_module.has_incoming_request())
+ const auto *request = wifi_module.read_incoming_request();
+
+ if (request == nullptr)
{
- char raw_request[MAX_HTTP_REQUEST_SIZE] = "";
+ return;
+ }
- const auto connection_id = wifi_module.read_incoming_request(raw_request);
+ const auto connection_id = request->connection_id();
- Serial.print("Connection ID: ");
- Serial.println(static_cast<unsigned int>(connection_id));
+ Serial.print("Connection ID: ");
+ Serial.println(static_cast<unsigned int>(connection_id));
- Serial.print("\nRaw request: ");
- Serial.println(raw_request);
+ Serial.print("Request method: ");
+ Serial.println(http_request_method_strs[static_cast<size_t>(request->method())]);
- wifi_module.send(connection_id, "lmao!");
+ Serial.print("Request HTTP version: ");
+ Serial.println(request->http_version());
- wifi_module.close_connection(connection_id);
+ Serial.print("Request path: ");
+ Serial.println(request->path());
- delay(SECOND_IN_MILLIS);
- }
+ Serial.print("\nData: ");
+ Serial.println(request->data());
+
+ wifi_module.send(connection_id, "lmao!");
+
+ wifi_module.close_connection(connection_id);
+
+ delete request;
+
+ delay(SECOND_IN_MILLIS);
}
diff --git a/minion/src/http/request.cpp b/minion/src/http/request.cpp
new file mode 100644
index 0000000..9a35d37
--- /dev/null
+++ b/minion/src/http/request.cpp
@@ -0,0 +1,107 @@
+#include "request.hpp"
+
+#include "util.hpp"
+
+#include <string.h>
+
+auto str_to_http_request_method(const char *http_request_method_str) -> HTTPRequestMethod
+{
+ if (util::streq(http_request_method_str, "GET"))
+ {
+ return HTTPRequestMethod::GET;
+ }
+
+ if (util::streq(http_request_method_str, "POST"))
+ {
+ return HTTPRequestMethod::POST;
+ }
+
+ if (util::streq(http_request_method_str, "PUT"))
+ {
+ return HTTPRequestMethod::PUT;
+ }
+
+ if (util::streq(http_request_method_str, "HEAD"))
+ {
+ return HTTPRequestMethod::HEAD;
+ }
+
+ if (util::streq(http_request_method_str, "DELETE"))
+ {
+ return HTTPRequestMethod::DELETE;
+ }
+
+ if (util::streq(http_request_method_str, "CONNECT"))
+ {
+ return HTTPRequestMethod::CONNECT;
+ }
+
+ if (util::streq(http_request_method_str, "OPTIONS"))
+ {
+ return HTTPRequestMethod::OPTIONS;
+ }
+
+ if (util::streq(http_request_method_str, "TRACE"))
+ {
+ return HTTPRequestMethod::TRACE;
+ }
+
+ if (util::streq(http_request_method_str, "PATCH"))
+ {
+ return HTTPRequestMethod::PATCH;
+ }
+
+ return HTTPRequestMethod::GET;
+}
+
+HTTPRequest::HTTPRequest(
+ size_t connection_id,
+ HTTPRequestMethod method,
+ char *http_version, // NOLINT(bugprone-easily-swappable-parameters)
+ char *path,
+ int data_length,
+ char *data
+) noexcept
+ : _connection_id(connection_id),
+ _method(method),
+ _http_version(http_version),
+ _path(path),
+ _data_length(data_length),
+ _data(data)
+{
+}
+
+HTTPRequest::~HTTPRequest() noexcept
+{
+ free(_data);
+}
+
+auto HTTPRequest::connection_id() const noexcept -> size_t
+{
+ return _connection_id;
+}
+
+auto HTTPRequest::method() const noexcept -> HTTPRequestMethod
+{
+ return _method;
+}
+
+auto HTTPRequest::http_version() const noexcept -> const char *
+{
+ return _http_version;
+}
+
+auto HTTPRequest::path() const noexcept -> const char *
+{
+ return _path;
+}
+
+auto HTTPRequest::data_length() const noexcept -> int
+{
+ return _data_length;
+}
+
+auto HTTPRequest::data() const noexcept -> const char *
+{
+ return _data;
+}
diff --git a/minion/src/http/request.hpp b/minion/src/http/request.hpp
new file mode 100644
index 0000000..85af722
--- /dev/null
+++ b/minion/src/http/request.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <stddef.h>
+
+enum HTTPRequestMethod
+{
+ GET,
+ POST,
+ PUT,
+ HEAD,
+ DELETE,
+ CONNECT,
+ OPTIONS,
+ TRACE,
+ PATCH
+};
+
+constexpr const char *http_request_method_strs[] = { "GET", "POST", "PUT",
+ "HEAD", "DELETE", "CONNECT",
+ "OPTIONS", "TRACE", "PATCH" };
+
+auto str_to_http_request_method(const char *http_request_method_str) -> HTTPRequestMethod;
+
+class HTTPRequest
+{
+public:
+ explicit HTTPRequest(
+ size_t connection_id,
+ HTTPRequestMethod method,
+ char *http_version,
+ char *path,
+ int data_length,
+ char *data
+ ) noexcept;
+
+ HTTPRequest(const HTTPRequest &other) noexcept = delete;
+
+ HTTPRequest(HTTPRequest &&other) noexcept = delete;
+
+ ~HTTPRequest() noexcept;
+
+ auto connection_id() const noexcept -> size_t;
+
+ auto method() const noexcept -> HTTPRequestMethod;
+
+ auto http_version() const noexcept -> const char *;
+
+ auto path() const noexcept -> const char *;
+
+ auto data_length() const noexcept -> int;
+
+ auto data() const noexcept -> const char *;
+
+ auto operator=(const HTTPRequest &other) noexcept -> HTTPRequest & = delete;
+
+ auto operator=(HTTPRequest &&other) noexcept -> HTTPRequest & = delete;
+
+private:
+ const size_t _connection_id;
+ const HTTPRequestMethod _method;
+ char *_http_version;
+ char *_path;
+ const int _data_length;
+ char *_data;
+};
diff --git a/minion/src/util.cpp b/minion/src/util.cpp
index f587781..540a20c 100644
--- a/minion/src/util.cpp
+++ b/minion/src/util.cpp
@@ -3,7 +3,7 @@
namespace util
{
-bool str_ends_with(const char *str, const char *other_str) noexcept
+auto str_ends_with(const char *str, const char *other_str) noexcept -> bool
{
if (str == nullptr || other_str == nullptr)
{
@@ -25,11 +25,16 @@ void substr(const char *str, const char *end, char *dest) noexcept
{
auto *dest_head = dest;
- for (const char *char_ptr = str; char_ptr + 1 != end; ++char_ptr)
+ for (const char *char_ptr = str; char_ptr != end; ++char_ptr)
{
*dest_head = *char_ptr;
dest_head++;
}
}
+auto streq(const char *str_one, const char *str_two) noexcept -> bool
+{
+ return strcmp(str_one, str_two) == 0;
+}
+
} // namespace util
diff --git a/minion/src/util.hpp b/minion/src/util.hpp
index d6f7f1c..4cc3967 100644
--- a/minion/src/util.hpp
+++ b/minion/src/util.hpp
@@ -8,12 +8,12 @@ namespace util
{
template <typename Type>
-Type *malloc(size_t size) noexcept
+auto malloc(size_t size) noexcept -> Type *
{
return static_cast<Type *>(::malloc(size));
}
-bool str_ends_with(const char *str, const char *other_str) noexcept;
+auto str_ends_with(const char *str, const char *other_str) noexcept -> bool;
/**
* Extracts a portion of a string.
@@ -24,4 +24,16 @@ bool str_ends_with(const char *str, const char *other_str) noexcept;
*/
void substr(const char *str, const char *end, char *dest) noexcept;
+/**
+ * Compares two strings.
+ *
+ * Wrapper function for strcmp.
+ *
+ * @param str_one The first string.
+ * @param str_two The second string.
+ *
+ * @returns Whether or not the two string are the same.
+ */
+auto streq(const char *str_one, const char *str_two) noexcept -> bool;
+
} // namespace util
diff --git a/minion/src/wifi_module.cpp b/minion/src/wifi_module.cpp
index 8b04b70..065bcdf 100644
--- a/minion/src/wifi_module.cpp
+++ b/minion/src/wifi_module.cpp
@@ -146,7 +146,7 @@ void WiFiModule::create_tcp_server(size_t port) noexcept
char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
- _read(TIMEOUT_LONG, response);
+ _read(TIMEOUT_MEDIUM, response);
// Serial.println(response);
}
@@ -191,6 +191,8 @@ auto WiFiModule::get_local_ip(char *local_ip_out) noexcept -> const char *
return local_ip_out;
}
+ strcpy(buf, "");
+
const auto response_status = _read(10000U, buf);
if (response_status != ResponseStatus::OK)
@@ -206,7 +208,7 @@ auto WiFiModule::get_local_ip(char *local_ip_out) noexcept -> const char *
return local_ip_out;
}
- const auto *local_ip_end = strstr(buf, "\r\n+CIFSR:STAMAC");
+ const auto local_ip_end = strstr(buf, "\r\n+CIFSR:STAMAC");
if (local_ip_end == nullptr)
{
@@ -224,15 +226,15 @@ auto WiFiModule::get_local_ip(char *local_ip_out) noexcept -> const char *
return local_ip_out;
}
-auto WiFiModule::has_incoming_request() noexcept -> bool
+auto WiFiModule::read_incoming_request() noexcept -> HTTPRequest *
{
char request_prefix[] = "+IPD,";
- return get_available() != 0 && _serial.find(request_prefix);
-}
+ if (get_available() == 0 || !_serial.find(request_prefix))
+ {
+ return nullptr;
+ }
-auto WiFiModule::read_incoming_request(char *raw_request_out) noexcept -> size_t
-{
const auto min_available_bytes = 5;
// Wait for the data buffer a bit
@@ -240,41 +242,50 @@ auto WiFiModule::read_incoming_request(char *raw_request_out) noexcept -> size_t
{
}
- const auto connection_id = _serial.read() - ASCII_TO_CHAR;
+ const auto connection_id = _read_connection_id();
- // Skip the comma
- _serial.read();
+ auto request_data_length = _read_request_data_length();
- char data_length_buf[16] = { '\0' };
+ const auto request_method = _read_request_method(request_data_length);
- _read_buffer(&data_length_buf[0], sizeof(data_length_buf) - 1, ':');
+ // Read request path
+ char request_path[REQUEST_PATH_MAX_LENGTH] = "";
+ _read_to(&request_path[0], sizeof(request_path) - 1U, ' ', TIMEOUT_MEDIUM);
- auto data_length = atoi(data_length_buf);
+ request_data_length -= strlen(request_path) + 1U;
- Serial.print("Data length: ");
- Serial.println(data_length);
+ // Read request HTTP version
+ char http_version[REQUEST_HTTP_VERSION_MAX_LENGTH] = "";
+ _read_to(&http_version[0], sizeof(http_version) - 1U, '\r', TIMEOUT_MEDIUM);
- auto read_bytes = 0;
- const auto start_time = millis();
+ request_data_length -= strlen(http_version) + 1U;
- while (read_bytes != data_length && (start_time + 10000) > millis())
+ // Skip the newline
+ while (get_available() == 0)
{
- if (get_available() == 0)
- {
- continue;
- }
-
- char character = _read_byte();
+ }
+ _serial.read();
+ request_data_length -= 1U;
- strncat(raw_request_out, &character, 1U);
+ auto request_data = util::malloc<char>(request_data_length + 1U);
- read_bytes++;
+ if (request_data == nullptr)
+ {
+ return nullptr;
}
- // Skip the comma at the beginning
- raw_request_out++;
+ strcpy(request_data, "");
- return connection_id;
+ _read_bytes(request_data, request_data_length, TIMEOUT_LONG);
+
+ return new HTTPRequest(
+ connection_id,
+ request_method,
+ http_version,
+ request_path,
+ request_data_length,
+ request_data
+ );
}
auto WiFiModule::close_connection(size_t connection_id) noexcept -> bool
@@ -340,13 +351,13 @@ auto WiFiModule::send(size_t connection_id, const char *data) noexcept -> bool
char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
- _read(TIMEOUT_LONG, response);
+ _read(TIMEOUT_MEDIUM, response);
_serial.print(data);
strcpy(response, "");
- _read(TIMEOUT_LONG, response);
+ _read(TIMEOUT_MEDIUM, response);
return true;
}
@@ -374,6 +385,43 @@ auto WiFiModule::_send_serial(const char *command) noexcept -> bool
return true;
}
+size_t WiFiModule::_read_connection_id() noexcept
+{
+ const auto connection_id = _serial.read() - ASCII_TO_CHAR;
+
+ // Skip the comma
+ _serial.read();
+
+ return connection_id;
+}
+
+size_t WiFiModule::_read_request_data_length() noexcept
+{
+ 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<size_t>(strtoul(data_length_buf, nullptr, 10));
+}
+
+HTTPRequestMethod WiFiModule::_read_request_method(size_t &request_data_length) noexcept
+{
+ 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 -> ResponseStatus
{
const auto start_time = millis();
@@ -381,8 +429,6 @@ auto WiFiModule::_read(uint64_t timeout, char *response_out) noexcept -> Respons
bool has_end = false;
auto status = ResponseStatus::TIMEOUT;
- // auto *response_out_head = response_out;
-
while (!has_end && (start_time + timeout) > millis())
{
while (_serial.available() != 0)
@@ -391,9 +437,6 @@ auto WiFiModule::_read(uint64_t timeout, char *response_out) noexcept -> Respons
strncat(response_out, &character, 1U);
- // *response_out_head = character;
- // response_out_head++;
-
if (util::str_ends_with(response_out, "OK"))
{
status = ResponseStatus::OK;
@@ -417,16 +460,29 @@ auto WiFiModule::_read(uint64_t timeout, char *response_out) noexcept -> Respons
return status;
}
-void WiFiModule::_read_buffer(char *buffer_out, size_t length, char stop_char) noexcept
+void WiFiModule::_read_to(
+ char *buffer_out,
+ size_t length, // NOLINT(bugprone-easily-swappable-parameters)
+ char stop_char,
+ uint64_t timeout
+) noexcept
{
- byte position = 0;
+ auto position = 0U;
+ const auto start_time = millis();
- while (get_available() != 0 && position < length)
+ 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;
}
@@ -434,6 +490,34 @@ void WiFiModule::_read_buffer(char *buffer_out, size_t length, char stop_char) n
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<char>(_serial.read());
diff --git a/minion/src/wifi_module.hpp b/minion/src/wifi_module.hpp
index 43999d6..62ea4f4 100644
--- a/minion/src/wifi_module.hpp
+++ b/minion/src/wifi_module.hpp
@@ -1,15 +1,23 @@
#pragma once
+#include "http/request.hpp"
+
#include <SoftwareSerial.h>
#include <stddef.h>
#include <stdint.h>
constexpr auto MAX_NETWORK_MODULE_RESPONSE_LENGTH = 128U;
+constexpr auto REQUEST_DATA_LENGTH_BUF_SIZE = 16U;
+constexpr auto REQUEST_METHOD_STR_MAX_LENGTH = 10U;
+constexpr auto REQUEST_PATH_MAX_LENGTH = 64U;
+constexpr auto REQUEST_HTTP_VERSION_MAX_LENGTH = 10U;
+
constexpr auto ASCII_TO_CHAR = 48U;
constexpr auto TIMEOUT_SHORT = 1500U;
-constexpr auto TIMEOUT_LONG = 4000U;
+constexpr auto TIMEOUT_MEDIUM = 4000U;
+constexpr auto TIMEOUT_LONG = 10000U;
enum WifiMode
{
@@ -77,16 +85,13 @@ public:
*/
auto get_local_ip(char *local_ip_out) noexcept -> const char *;
- auto has_incoming_request() noexcept -> bool;
-
/**
* Reads a incoming HTTP request.
*
- * @param raw_request_out Raw request output buffer.
- *
- * @returns The connection ID.
+ * @returns A pointer to the request. Has to be deleted after use. Is nullptr if
+ * reading the request failed.
*/
- auto read_incoming_request(char *raw_request_out) noexcept -> size_t;
+ auto read_incoming_request() noexcept -> HTTPRequest *;
auto close_connection(size_t connection_id) noexcept -> bool;
@@ -104,6 +109,12 @@ private:
*/
auto _send_serial(const char *command) noexcept -> bool;
+ size_t _read_connection_id() noexcept;
+
+ size_t _read_request_data_length() noexcept;
+
+ HTTPRequestMethod _read_request_method(size_t &request_data_length) noexcept;
+
/**
* Reads from the wifi module until it responds with a status.
*
@@ -115,7 +126,10 @@ private:
*/
auto _read(uint64_t timeout, char *response_out) noexcept -> ResponseStatus;
- void _read_buffer(char *buffer_out, size_t length, char stop_char) noexcept;
+ void
+ _read_to(char *buffer_out, size_t length, char stop_char, uint64_t timeout) noexcept;
+
+ void _read_bytes(char *buffer_out, size_t length, uint64_t timeout) noexcept;
auto _read_byte() noexcept -> char;
};