A low level modern C++17 framework that provides opaque and unified access to different hardwares, without exposing their inner workings.
If you want a higher level framework, safer, but more opinionated, check: https://github.com/internet-of-plants/iop
- IOP_ESP8266 (all boards supported by esp8266/Arduino)
- IOP_ESP32 (all boards supported by espressif/arduino-esp32)
- IOP_LINUX_MOCK (all targets that support Linux with mocked GPIOs)
- IOP_LINUX (all targets that support Linux)
Note: Some functionalities in the linux target are NOOP, most will be implemented to support Raspberry Pis and other boards that support linux. But for now this is mostly used for testing
Provides the following functionalities:
iop_hal::setup
,iop_hal::loop
: User definediop_hal
entrypoints, from#include <iop-hal/runtime.hpp>
iop_hal::WiFi
: Access Point + Station management, useiop::wifi
from#include <iop-hal/network.hpp>
iop::Update
: Make over-the-air firmware updates, from#include <iop-hal/update.hpp>
iop::Thread
: Thread management, useiop::thisThread
from#include <iop-hal/thread.hpp>
iop::StaticString
: Disk stored strings, use it withIOP_STR(str)
macro, from#include <iop-hal/string.h>
iop::CowString
,iop::to_view
: Unifies borrowed strings handling, from#include<iop-hal/string.h>
- With string utils functions, we use
std::string
for dynamically allocated strings - With fixed sized (non zero terminated) char arrays castable with
iop::to_view
- Like
iop::MD5Hash
,iop::MacAddress
,iop::NetworkName
,iop::NetworkPassword
- With string utils functions, we use
iop::Storage
: Low level access to persistent flat storage, from#include <iop-hal/storage.hpp>
iop::HttpServer
: HTTP server hosting in the device, from#include <iop-hal/server.hpp>
iop::CaptivePortal
: Turns Access Point into a captive portal, from#include <iop-hal/server.hpp>
- Hijacks DNS to redirect all TCP requests in its own AP to some port
iop_panic
andiop_assert
macros: Fatal error handler hook API, from#include <iop-hal/panic.hpp>
- Panic hooks should never return, either halt/wait for a interaction, or reboot the process
- Exceptions aren't supported, fatal errors should use iop_hal's panic
iop::HttpClient
: HTTP(s) client, from#include <iop-hal/client.hpp>
iop::Network
: Higher level HTTP(s) client, from#include <iop-hal/network.hpp>
- With authentication + JSON requests + update hook
iop::Log
: String log system, from#include <iop-hal/log.hpp>
- With variadic arguments + levels + extension hooks, for
iop::StaticString
andstd::string_view
- One comes from the
IOP_STR(str)
macro, the other fromiop::to_view
+std::to_string
- With variadic arguments + levels + extension hooks, for
iop::Device
: Unified hardware management, from#include <iop-hal/device.hpp>
#include <iop-hal/runtime.hpp>
#include <iop-hal/string.hpp>
#include <iop-hal/storage.hpp>
#include <optional>
static iop::Wifi wifi;
static uint8_t wifiCredsWrittenToFlag = 128;
static std::optional<std::pair<std::array<char, 64>, std::array<char, 32>>> wifiCredentials;
constexpr static iop::time::milliseconds twoHours = 2 * 3600 * 1000;
static iop::time::milliseconds waitUntilUseHardcodedCredentials = iop::thisThread.timeRunning() + twoHours;
namespace iop {
auto setup() noexcept -> void {
wifi.setup();
// Raw storage access, storage is just a huge array backed by HDD/SSD/Flash, not RAM
if (storage.get(0) == wifiCredsWrittenToFlag) {
const auto ssid = storage.read<64>(1);
iop_assert(ssid, IOP_STR("Invalid address when accessing SSID from storage"));
const auto psk = storage.read<32>(65); // flag + ssid
iop_assert(psk, IOP_STR("Invalid address when accessing PSK from storage"));
wifiCredentials = std::make_pair(*ssid, *psk);
wifi.connectToAccessPoint(iop::to_view(*ssid), iop::to_view(*psk));
}
}
auto loop() noexcept -> void {
if (iop::Network::isConnected() && !wifiCredentials) {
const auto [name, password] = wifi.credentials();
wifiCredentials = std::make_pair(name, password);
// Avoids writing to flash if not needed
if (storage.get(0) == wifiCredsWrittenToFlag && name == storage.read<64>(1) && password == storage.read<32>(65)) {
return;
}
// Store credentials for simpler reuse
storage.set(0, wifiCredsWrittenToFlag);
storage.write(1, name);
storage.write(65, password);
}
// Just to show more about wifi, you should not hardcode creds
// Check the captive_portal.cpp example for a better way
if (!wifiCredentials && iop::thisThread.timeRunning() > waitUntilUseHardcodedCredetials) {
wifi.connectToAccessPoint("my-ssid", "my-super-secret-psk");
}
}
}
GNU Affero General Public License version 3 or later (AGPL-3.0+)