Skip to content

Commit

Permalink
firmware wifi updates (#29)
Browse files Browse the repository at this point in the history
* login page update + better error on boot for bad srv config

* fsm wifi event stabilization

* remove vim specific file

* more diagnostic logging for job queueing

* try playing with merge_bins

* add a version string to common logs

* temporary escaping workaround

* add reminder, fix ca in CI

* quoted host ca
  • Loading branch information
dadleyy committed Jan 10, 2024
1 parent 11b2d80 commit e22b703
Show file tree
Hide file tree
Showing 26 changed files with 686 additions and 557 deletions.
6 changes: 6 additions & 0 deletions .automation/firmware-instructions/flashing-xiao.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ python esptool.py \
0xe000 boot_app0.bin \
0x10000 .pio/build/xiao/firmware.bin
```

Alternatively, the merged binary has been included:

```
esptool.py --chip esp32c3 write_flash 0x0 ./beetle-merged.bin
```
16 changes: 15 additions & 1 deletion .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
REDIS_PORT: "${{ secrets.PIO_REDIS_PORT }}"
REDIS_AUTH_USERNAME: "${{ secrets.PIO_REDIS_AUTH_USERNAME }}"
REDIS_AUTH_PASSWORD: "${{ secrets.PIO_REDIS_AUTH_PASSWORD }}"
REDIS_HOST_ROOT_CA: "${{ secrets.REDIS_HOST_ROOT_CA }}"
DISTRIBUTABLE_DIRECTORY_NAME: "beetle-pio-dist"
defaults:
run:
Expand All @@ -58,6 +59,7 @@ jobs:
id: vars
run: |
echo "SHORT_SHA=$(echo $GITHUB_SHA | head -c 7)">>$GITHUB_OUTPUT
echo "BEETLE_VERSION=$(echo $GITHUB_SHA | head -c 7)">>$GITHUB_ENV
- name: "import gpg"
run: |
Expand All @@ -72,7 +74,10 @@ jobs:
run: pip install --upgrade platformio

- name: "env prep: fill redis ca"
run: echo $REDIS_HOST_ROOT_CA > embeds/redis_host_root_ca.pem
run: |
echo -n "$REDIS_HOST_ROOT_CA" > embeds/redis_host_root_ca.pem
echo -n "$REDIS_HOST_ROOT_CA" | wc -l
wc -l embeds/redis_host_root_ca.pem
- name: "pio: check"
run: pio check
Expand All @@ -86,9 +91,18 @@ jobs:
- name: "pio(xiao): run xiao"
run: pio run -e xiao

- name: "pio(xiao): make merged"
run: make

- name: "bundle(xiao): prepare-dir"
run: mkdir -p $DISTRIBUTABLE_DIRECTORY_NAME/xiao

- name: "bundle(xiao): copy-merged"
run: |
gpg --trust-model always -e -r $BEETLE_GPG_KEY_ID -o \
$DISTRIBUTABLE_DIRECTORY_NAME/xiao/beetle-merged.bin.pgp \
beetle-merged-flash.bin
- name: "bundle(xiao): copy-bin"
run: |
gpg --trust-model always -e -r $BEETLE_GPG_KEY_ID -o \
Expand Down
2 changes: 1 addition & 1 deletion src/beetle-pio-tls-tester/platformio.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[platformio]
default_envs = firebeetle
default_envs = xiao

[env]
framework=arduino
Expand Down
4 changes: 1 addition & 3 deletions src/beetle-pio-tls-tester/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ void listNetworks() {
Serial.print("number of available networks:");
Serial.println(numSsid);
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
Serial.print(thisNet);
Serial.print(") ");
Serial.print(WiFi.SSID(thisNet));
Serial.print("\tSignal: ");
Serial.print(WiFi.RSSI(thisNet));
Serial.print(" dBm");
Serial.println(" dBm");
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/beetle-pio/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/.pio
beetle-merged-flash.bin
.ycm_extra_conf.py
/env
/*.log
/embeds/*.pem
Expand Down
35 changes: 35 additions & 0 deletions src/beetle-pio/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
PYTHON=python3

ESPTOOL=$(HOME)/.platformio/packages/tool-esptoolpy/esptool.py
BOOT_APP0=$(HOME)/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin

# TODO: consult either esptool.py or platformio. they handle this gracefully.
PORT=/dev/cu.usbmodem101

BINS=.pio/build/xiao/bootloader.bin .pio/build/xiao/partitions.bin .pio/build/xiao/firmware.bin
MERGED_BIN=beetle-merged-flash.bin

.PHONY: clean flash-merged tool

all: $(MERGED_BIN)

clean:
rm $(BINS)

$(BINS):
pio run

$(MERGED_BIN): $(BINS)
$(PYTHON) $(ESPTOOL) --chip esp32c3 merge_bin -o $@ \
--flash_size 4MB \
0x0000 .pio/build/xiao/bootloader.bin \
0x8000 .pio/build/xiao/partitions.bin \
0xe000 $(BOOT_APP0) \
0x10000 .pio/build/xiao/firmware.bin

help:
$(PYTHON) $(ESPTOOL) --help

flash-merged: $(MERGED_BIN)
echo $<
$(PYTHON) $(ESPTOOL) --chip esp32c3 --port $(PORT) write_flash --flash_mode dio --flash_freq 80m 0x0 $<
62 changes: 53 additions & 9 deletions src/beetle-pio/lib/redis-events/redis-events.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <WiFiClientSecure.h>

#include "redis-config.hpp"
#include "redis-event.hpp"
#include "redis-reader.hpp"
Expand Down Expand Up @@ -32,7 +33,7 @@ class Events final {
std::optional<wifievents::Events::EMessage> &wifi,
std::shared_ptr<std::array<uint8_t, T>> buffer, uint32_t time) {
auto visitor = StateVisitor{_context, &wifi, buffer, time, _reader};
auto[next, message] = std::visit(visitor, _state);
auto [next, message] = std::visit(visitor, _state);
_state = next;
return message;
}
Expand Down Expand Up @@ -154,7 +155,7 @@ class Events final {
context->device_id_len, context->device_id,
context->device_id_len, context->device_id);
context->client.print(context->outbound);
log_d("wrote auth: '%s'", context->outbound);
log_i("wrote auth: '%s'", context->outbound);
connected.authorization_stage =
AuthorizationStage::AuthorizationAttempted;

Expand Down Expand Up @@ -192,6 +193,10 @@ class Events final {
bool pending_burnin_auth = connected.authorization_stage ==
AuthorizationStage::AuthorizationRequested;

if (connected.last_read == 0) {
connected.last_read = time;
}

while (context->client.available()) {
auto token = (char)context->client.read();
auto event = reader->fill(token, buffer);
Expand All @@ -208,13 +213,23 @@ class Events final {
: AuthorizationStage::FullyAuthorized;
}
}

connected.last_read = time;
}

if (connected.authorization_stage ==
AuthorizationStage::FullyAuthorized) {
return std::make_pair(connected, Authorized{});
}

if (time - connected.last_read > 5000) {
log_e("expected OK from redis but none was received in time, aborting");
// important: explicitly stopping the client frees up internal memory
// used on the next connection attempt.
context->client.stop();
return std::make_pair(Connected{false}, FailedConnection{});
}

return std::make_pair(connected, std::nullopt);
}

Expand All @@ -232,7 +247,8 @@ class Events final {

if (result != 1) {
log_e("unable to establish connection - %d", result);
return std::make_pair(Disconnected{}, FailedConnection{});
context->client.stop();
return std::make_pair(Disconnected{time + 5000}, FailedConnection{});
}

log_i("redis connection established successfully");
Expand All @@ -256,7 +272,7 @@ class Events final {
context->device_id_len, context->device_id,
context->device_id_len, context->device_id);
context->client.print(context->outbound);
log_d("wrote auth: '%s'", context->outbound);
log_d("wrote auth: '%s'; clearing internal buffer", context->outbound);
connected.authorization_stage =
AuthorizationStage::AuthorizationAttempted;
return std::make_pair(connected, IdentificationReceived{});
Expand Down Expand Up @@ -392,7 +408,8 @@ class Events final {
context->device_id_len + 3, context->device_id);
}

log_i("writing message (heartbeat? %d)", sending_heartbeat);
log_i("id[%s] writing message (heartbeat? %d)", context->device_id,
sending_heartbeat);
context->client.print(context->outbound);
}

Expand All @@ -402,6 +419,7 @@ class Events final {
std::pair<std::variant<Disconnected, Connected>, std::optional<RedisEvent>>
operator()(Connected connected) {
if (*wifi_message == wifievents::Events::EMessage::Disconnected) {
context->client.stop();
return std::make_pair(Disconnected{}, std::nullopt);
}

Expand All @@ -413,6 +431,7 @@ class Events final {

if (connected.paused) {
if (*wifi_message == wifievents::Events::EMessage::ConnectionResumed) {
context->client.stop();
return std::make_pair(Disconnected{}, std::nullopt);
}

Expand All @@ -431,6 +450,9 @@ class Events final {

case AuthorizationStage::AuthorizationRequested:
case AuthorizationStage::AuthorizationAttempted:
// TODO: it is likely that we should be ensuring the buffer is cleared
// out _before_ moving into either of these authorization states.
buffer->fill('\0');
return read_ok(connected);

case AuthorizationStage::NotRequested:
Expand All @@ -442,16 +464,37 @@ class Events final {

std::pair<std::variant<Disconnected, Connected>, std::optional<RedisEvent>>
operator()(Disconnected d) {
if (*wifi_message == wifievents::Events::EMessage::Connected) {
bool reconnect =
*wifi_message == wifievents::Events::EMessage::Connected ||
*wifi_message == wifievents::Events::EMessage::ConnectionResumed;

if (d.reconnect_after > 0 && time > d.reconnect_after) {
log_i("explicit redis reconnection attempt");
return std::make_pair(Connected{false}, std::nullopt);
}

if (reconnect) {
log_i("redis events moving into connection attempt");
return std::make_pair(Connected{false}, std::nullopt);
}

return std::make_pair(Disconnected{}, std::nullopt);
if (d.last_debug == 0) {
d.last_debug = time;
}

if (time - d.last_debug > 3000) {
log_e("redis events disconnected; no connected wifi events received");
d.last_debug = time;
}

return std::make_pair(d, std::nullopt);
}
};

struct Disconnected final {};
struct Disconnected final {
uint32_t reconnect_after = 0;
uint32_t last_debug = 0;
};

struct ReceivingHeartbeatAck final {};

Expand All @@ -474,6 +517,7 @@ class Events final {
struct Connected final {
bool paused = false;
uint32_t last_write = 0;
uint32_t last_read = 0;
AuthorizationStage authorization_stage = AuthorizationStage::NotRequested;
std::variant<ReceivingHeartbeatAck, ReceivingPop, NotReceiving> state =
NotReceiving{true};
Expand All @@ -483,4 +527,4 @@ class Events final {
std::variant<Disconnected, Connected> _state;
std::shared_ptr<RedisReader<T>> _reader;
};
}
} // namespace redisevents

0 comments on commit e22b703

Please sign in to comment.