summaryrefslogtreecommitdiff
path: root/minion
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-05-08 18:55:42 +0200
committerHampusM <hampus@hampusmat.com>2022-05-08 18:55:42 +0200
commit2809f92eeb8b727e20167fe82e4cb9c3627d4870 (patch)
tree06a01c862088333aa388e74dfa4381a87568bfc1 /minion
parent3a11866cb6a8fd46d86cb6e04dc1022344ea8d45 (diff)
chore: move most files to minion folder
Diffstat (limited to 'minion')
-rw-r--r--minion/.clang-format19
-rw-r--r--minion/.clang-tidy47
-rw-r--r--minion/Makefile20
-rw-r--r--minion/platformio.ini16
-rw-r--r--minion/src/gymnasiearbete.cpp69
-rw-r--r--minion/src/util.cpp35
-rw-r--r--minion/src/util.hpp27
-rw-r--r--minion/src/wifi_module.cpp312
-rw-r--r--minion/src/wifi_module.hpp93
9 files changed, 638 insertions, 0 deletions
diff --git a/minion/.clang-format b/minion/.clang-format
new file mode 100644
index 0000000..782b0a9
--- /dev/null
+++ b/minion/.clang-format
@@ -0,0 +1,19 @@
+BasedOnStyle: LLVM
+UseTab: Always
+IndentWidth: 4
+TabWidth: 4
+BreakBeforeBraces: Allman
+AllowShortIfStatementsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortLambdasOnASingleLine: None
+IndentCaseLabels: false
+ColumnLimit: 90
+AccessModifierOffset: -4
+AlwaysBreakTemplateDeclarations: Yes
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+AllowAllArgumentsOnNextLine: false
+AllowAllParametersOfDeclarationOnNextLine: false
+BinPackArguments: false
+BinPackParameters: false
+AlignAfterOpenBracket: BlockIndent
+Cpp11BracedListStyle: false
diff --git a/minion/.clang-tidy b/minion/.clang-tidy
new file mode 100644
index 0000000..8a92317
--- /dev/null
+++ b/minion/.clang-tidy
@@ -0,0 +1,47 @@
+---
+Checks: '
+ clang-analyzer-*,
+ cppcoreguidelines-*,
+ google-*,
+ misc-*,
+ modernize-*,
+ bugprone-*,
+ performance-*,
+ readability-*,
+ -modernize-avoid-c-arrays,
+ -cppcoreguidelines-avoid-c-arrays,
+ -cppcoreguidelines-no-malloc,
+ -cppcoreguidelines-owning-memory'
+WarningsAsErrors: '*'
+HeaderFilterRegex: '\/src\/'
+AnalyzeTemporaryDtors: false
+CheckOptions:
+ - key: readability-function-cognitive-complexity.Threshold
+ value: 100
+ - key: readability-identifier-naming.ClassCase
+ value: CamelCase
+ - key: readability-identifier-naming.PrivateMemberPrefix
+ value: _
+ - key: readability-identifier-naming.StructCase
+ value: CamelCase
+ - key: google-readability-braces-around-statements.ShortStatementLines
+ value: '1'
+ - key: google-readability-function-size.StatementThreshold
+ value: '800'
+ - key: google-readability-namespace-comments.ShortNamespaceLines
+ value: '10'
+ - key: google-readability-namespace-comments.SpacesBeforeComments
+ value: '2'
+ - key: modernize-loop-convert.MaxCopySize
+ value: '16'
+ - key: modernize-loop-convert.MinConfidence
+ value: reasonable
+ - key: modernize-loop-convert.NamingStyle
+ value: CamelCase
+ - key: modernize-pass-by-value.IncludeStyle
+ value: llvm
+ - key: modernize-replace-auto-ptr.IncludeStyle
+ value: llvm
+ - key: modernize-use-nullptr.NullMacros
+ value: 'NULL'
+...
diff --git a/minion/Makefile b/minion/Makefile
new file mode 100644
index 0000000..986833f
--- /dev/null
+++ b/minion/Makefile
@@ -0,0 +1,20 @@
+TARGET = gymnasiearbete
+
+PIO = platformio
+
+all: $(TARGET)
+
+.PHONY: $(TARGET) upload clean monitor
+
+$(TARGET):
+ $(PIO) run -v
+ $(PIO) run --target compiledb
+
+upload:
+ $(PIO) run --target upload
+
+clean:
+ $(PIO) run --target clean
+
+monitor:
+ $(PIO) run --target monitor
diff --git a/minion/platformio.ini b/minion/platformio.ini
new file mode 100644
index 0000000..4bac56e
--- /dev/null
+++ b/minion/platformio.ini
@@ -0,0 +1,16 @@
+[platformio]
+build_dir = build
+
+[env:uno]
+platform = atmelavr
+board = uno
+framework = arduino
+src_build_flags =
+ -Wextra
+ -Wpedantic
+ -Wshadow
+ -Wcast-align
+ -Wunused
+ -Wold-style-cast
+ -Wconversion
+ -pedantic
diff --git a/minion/src/gymnasiearbete.cpp b/minion/src/gymnasiearbete.cpp
new file mode 100644
index 0000000..0e1adb5
--- /dev/null
+++ b/minion/src/gymnasiearbete.cpp
@@ -0,0 +1,69 @@
+#include "secrets.hpp"
+#include "wifi_module.hpp"
+
+#include <Arduino.h>
+#include <SoftwareSerial.h>
+#include <string.h>
+
+constexpr auto BAUDRATE = 9600U;
+
+constexpr auto NETWORK_MODULE_RX_PIN = 3;
+constexpr auto NETWORK_MODULE_TX_PIN = 2;
+
+auto wifi_module = WiFiModule(NETWORK_MODULE_RX_PIN, NETWORK_MODULE_TX_PIN);
+
+void setup()
+{
+ Serial.begin(BAUDRATE);
+
+ pinMode(NETWORK_MODULE_RX_PIN, INPUT);
+ pinMode(NETWORK_MODULE_TX_PIN, OUTPUT);
+
+ wifi_module.begin(BAUDRATE);
+
+ wifi_module.reset();
+
+ delay(1000);
+
+ auto wifi_module_connected = wifi_module.test();
+
+ Serial.print("Wifi module connected: ");
+ Serial.println(wifi_module_connected ? "Yes" : "No");
+
+ if (!wifi_module_connected)
+ {
+ while (true)
+ {
+ }
+ }
+
+ wifi_module.set_echo_enabled(false);
+
+ delay(1000);
+
+ const auto wifi_connect_success = wifi_module.connect(WIFI_SSID, WIFI_PASSWORD);
+
+ if (wifi_connect_success)
+ {
+ Serial.print("Connected to wifi network '");
+ Serial.print(WIFI_SSID);
+ Serial.println("' successfully");
+ }
+ else
+ {
+ Serial.print("Failed to connect to wifi network '");
+ Serial.print(WIFI_SSID);
+ Serial.println("'");
+ }
+
+ wifi_module.set_wifi_mode(WifiMode::Station);
+
+ delay(3000);
+
+ char local_ip[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ Serial.print("IP address: ");
+ Serial.println(wifi_module.get_local_ip(local_ip));
+}
+
+void loop() {}
diff --git a/minion/src/util.cpp b/minion/src/util.cpp
new file mode 100644
index 0000000..f587781
--- /dev/null
+++ b/minion/src/util.cpp
@@ -0,0 +1,35 @@
+#include "util.hpp"
+
+namespace util
+{
+
+bool str_ends_with(const char *str, const char *other_str) noexcept
+{
+ if (str == nullptr || other_str == nullptr)
+ {
+ return false;
+ }
+
+ auto str_length = strlen(str);
+ auto other_str_length = strlen(other_str);
+
+ if (other_str_length > str_length)
+ {
+ return false;
+ }
+
+ return strncmp(str + str_length - other_str_length, other_str, other_str_length) == 0;
+}
+
+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)
+ {
+ *dest_head = *char_ptr;
+ dest_head++;
+ }
+}
+
+} // namespace util
diff --git a/minion/src/util.hpp b/minion/src/util.hpp
new file mode 100644
index 0000000..d6f7f1c
--- /dev/null
+++ b/minion/src/util.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace util
+{
+
+template <typename Type>
+Type *malloc(size_t size) noexcept
+{
+ return static_cast<Type *>(::malloc(size));
+}
+
+bool str_ends_with(const char *str, const char *other_str) noexcept;
+
+/**
+ * Extracts a portion of a string.
+ *
+ * @param str The target string.
+ * @param end A pointer to a place inside the target string.
+ * @param dest Output buffer.
+ */
+void substr(const char *str, const char *end, char *dest) noexcept;
+
+} // namespace util
diff --git a/minion/src/wifi_module.cpp b/minion/src/wifi_module.cpp
new file mode 100644
index 0000000..2e25dc9
--- /dev/null
+++ b/minion/src/wifi_module.cpp
@@ -0,0 +1,312 @@
+#include "wifi_module.hpp"
+
+#include "util.hpp"
+
+#include <Arduino.h>
+#include <string.h>
+
+WiFiModule::WiFiModule(uint8_t receive_pin, uint8_t transmit_pin) noexcept
+ : _serial(receive_pin, transmit_pin)
+{
+}
+
+void WiFiModule::begin(size_t baudrate) noexcept
+{
+ _serial.begin(baudrate);
+}
+
+int WiFiModule::get_available() noexcept
+{
+ return _serial.available();
+}
+
+void WiFiModule::reset() noexcept
+{
+ _send_serial("AT+RST");
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ const auto response_status = _read(2000U, response);
+
+ Serial.println(
+ response_status == ResponseStatus::OK ? "Reset wifi module"
+ : "Failed to reset wifi module"
+ );
+}
+
+bool WiFiModule::connect(const char *ssid, const char *password) noexcept
+{
+ const char cmd[] = "AT+CWJAP";
+
+ auto command_length = strlen(cmd) + strlen(ssid) + strlen(password) + 6U + 1U;
+
+ auto *command = util::malloc<char>(command_length);
+
+ if (command == nullptr)
+ {
+ Serial.println("Memory allocation failed for creating full 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("Failed to send connection command");
+ return false;
+ }
+
+ free(command);
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ const auto response_status = _read(20000U, response);
+
+ if (response_status != ResponseStatus::OK)
+ {
+ Serial.print("Connection command responded with status ");
+ Serial.println(response_status);
+ return false;
+ }
+
+ return true;
+}
+
+void WiFiModule::set_wifi_mode(WifiMode wifi_mode) noexcept
+{
+ const char cmd[] = "AT+CWMODE_CUR";
+
+ auto command_length = strlen(cmd) + 2U + 1U;
+
+ auto *command = util::malloc<char>(command_length);
+
+ snprintf(command, command_length, "%s=%u", cmd, static_cast<int>(wifi_mode));
+
+ _send_serial(command);
+
+ free(command);
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ _read(1500U, 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<char>(command_length);
+
+ snprintf(command, command_length, "%s=%u", cmd, is_enabled ? 1U : 0U);
+
+ _send_serial(command);
+
+ free(command);
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ _read(1500U, response);
+
+ // Serial.println(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<char>(command_length);
+
+ 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);
+
+ if (response_status == ResponseStatus::OK)
+ {
+ Serial.print("Turned ");
+ Serial.print(is_enabled ? "on" : "off");
+ Serial.println(" AT commands echo");
+ }
+ else
+ {
+ Serial.print("Failed to turn ");
+ Serial.print(is_enabled ? "on" : "off");
+ Serial.println(" AT commands echo");
+ }
+}
+
+void WiFiModule::create_tcp_server(size_t port) noexcept
+{
+ const auto cmd = "AT+CIPSERVER";
+
+ auto command_length = strlen(cmd) + 7U + 1U;
+
+ auto *command = util::malloc<char>(command_length);
+
+ snprintf(command, command_length, "%s=1,%u", cmd, port);
+
+ _send_serial(command);
+
+ free(command);
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ _read(1500U, response);
+
+ // Serial.println(response);
+}
+
+bool WiFiModule::test() noexcept
+{
+ const auto send_success = _send_serial("AT");
+
+ if (!send_success)
+ {
+ return false;
+ }
+
+ char response[MAX_NETWORK_MODULE_RESPONSE_LENGTH] = "";
+
+ const auto response_status = _read(5000U, response);
+
+ if (response_status == ResponseStatus::TIMEOUT)
+ {
+ return false;
+ }
+
+ return strcmp(response, "") != 0;
+}
+
+const char *WiFiModule::get_local_ip(char *local_ip_out) noexcept
+{
+ const auto command = "AT+CIFSR";
+
+ const auto send_success = _send_serial(command);
+
+ if (!send_success)
+ {
+ return local_ip_out;
+ }
+
+ auto *buf = util::malloc<char>(strlen(local_ip_out));
+
+ if (buf == nullptr)
+ {
+ strcpy(local_ip_out, "Memory allocation failure");
+ return local_ip_out;
+ }
+
+ const auto response_status = _read(10000U, buf);
+
+ if (response_status != ResponseStatus::OK)
+ {
+ free(buf);
+
+ sprintf(
+ local_ip_out,
+ "Response status was not OK. Was %d",
+ static_cast<int>(response_status)
+ );
+
+ return local_ip_out;
+ }
+
+ const 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;
+}
+
+bool WiFiModule::_send_serial(const char *command) noexcept
+{
+ auto full_command_length = strlen(command) + 2U + 1U;
+
+ auto *full_command = util::malloc<char>(full_command_length);
+
+ if (full_command == nullptr)
+ {
+ return false;
+ }
+
+ snprintf(full_command, full_command_length, "%s\r\n", command);
+
+ _serial.print(full_command);
+
+ // Serial.print("Sent command: ");
+ // Serial.println(full_command);
+
+ free(full_command);
+
+ return true;
+}
+
+ResponseStatus WiFiModule::_read(uint64_t timeout, char *response_out) noexcept
+{
+ const auto start_time = millis();
+
+ 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)
+ {
+ char character = _read_byte();
+
+ strncat(response_out, &character, 1U);
+
+ // *response_out_head = character;
+ // response_out_head++;
+
+ if (util::str_ends_with(response_out, "OK"))
+ {
+ status = ResponseStatus::OK;
+ has_end = true;
+ }
+
+ if (util::str_ends_with(response_out, "ERROR"))
+ {
+ status = ResponseStatus::ERROR;
+ has_end = true;
+ }
+
+ if (util::str_ends_with(response_out, "FAIL"))
+ {
+ status = ResponseStatus::FAIL;
+ has_end = true;
+ }
+ }
+ }
+
+ return status;
+}
+
+char WiFiModule::_read_byte() noexcept
+{
+ return static_cast<char>(_serial.read());
+}
diff --git a/minion/src/wifi_module.hpp b/minion/src/wifi_module.hpp
new file mode 100644
index 0000000..5a4148c
--- /dev/null
+++ b/minion/src/wifi_module.hpp
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <SoftwareSerial.h>
+#include <stddef.h>
+#include <stdint.h>
+
+constexpr auto MAX_NETWORK_MODULE_RESPONSE_LENGTH = 128U;
+
+enum WifiMode
+{
+ Station = 1,
+ SoftAP = 2,
+ SoftAPAndStation = 3
+};
+
+enum ResponseStatus
+{
+ OK,
+ FAIL,
+ ERROR,
+ TIMEOUT
+};
+
+class WiFiModule
+{
+public:
+ WiFiModule(uint8_t receive_pin, uint8_t transmit_pin) noexcept;
+
+ void begin(size_t baudrate) noexcept;
+
+ int get_available() noexcept;
+
+ void reset() noexcept;
+
+ /**
+ * Connects to a wifi network.
+ *
+ * @param ssid The service set identifier of a wifi network.
+ * @param password The wifi network password.
+ *
+ * @returns Whether or not it succeeded.
+ */
+ bool connect(const char *ssid, const char *password) noexcept;
+
+ void set_wifi_mode(WifiMode wifi_mode) noexcept;
+
+ void set_multiple_connections_enabled(bool is_enabled) noexcept;
+
+ void set_echo_enabled(bool is_enabled) noexcept;
+
+ void create_tcp_server(size_t port) noexcept;
+
+ /**
+ * Tests the connection to the wifi module.
+ *
+ * @returns Whether or not the test succeeded.
+ */
+ bool test() noexcept;
+
+ /**
+ * Gets local IP address of the wifi module.
+ *
+ * @param local_ip_out Local IP output buffer.
+ *
+ * @returns A pointer to the local IP output buffer.
+ */
+ const char *get_local_ip(char *local_ip_out) noexcept;
+
+private:
+ SoftwareSerial _serial;
+
+ /**
+ * Sends a command to the wifi module.
+ *
+ * @param command A command without the "AT+" in the beginning.
+ *
+ * @returns Whether or not it succeeded.
+ */
+ bool _send_serial(const char *command) noexcept;
+
+ /**
+ * Reads from the wifi module until it responds with a status.
+ *
+ * @param timeout Timeout in milliseconds.
+ * @param response_out Response output buffer.
+ *
+ * @returns The response status.
+ *
+ */
+ ResponseStatus _read(uint64_t timeout, char *response_out) noexcept;
+
+ char _read_byte() noexcept;
+};