Skip to content

Commit

Permalink
send json data to browser and render (#3)
Browse files Browse the repository at this point in the history
- refactor sending bot state on change into server
- print bot state into json
- refactor led timers into effects
- visualize bot state in browser
  • Loading branch information
ahdinosaur authored May 25, 2021
1 parent 3dd87a4 commit 2a91413
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 50 deletions.
11 changes: 10 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
"ctime": "cpp",
"ratio": "cpp",
"regex": "cpp",
"shared_mutex": "cpp"
"shared_mutex": "cpp",
"csignal": "cpp",
"forward_list": "cpp",
"list": "cpp",
"set": "cpp",
"unordered_set": "cpp",
"iomanip": "cpp",
"mutex": "cpp",
"thread": "cpp",
"valarray": "cpp"
}
}
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ build_flags =
lib_deps =
khoih.prog/STM32_TimerInterrupt@^1.2.0
khoih.prog/AsyncWebServer_STM32@^1.3.0
cesanta/mjson@^1.2.2
2 changes: 2 additions & 0 deletions src/effects/bot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

#include <effects/context.hpp>
#include <effects/leds.hpp>
#include <effects/clock.hpp>

namespace BotEffects {
void setup(BotContext *context) {
LedsEffects::setup(context);
ClockEffects::setup(context);
}
}
16 changes: 16 additions & 0 deletions src/effects/clock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <effects/context.hpp>

namespace ClockEffects {
void tick(void *params) {
BotContext *context = (BotContext*) params;
auto store = context->store;
store->dispatch(ClockModel::ActionTick {});
}

void setup(BotContext *context) {
auto timer = context->timer;
timer->set_interval(10L, tick, context);
}
}
28 changes: 27 additions & 1 deletion src/effects/leds.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <Arduino.h>
#include <STM32_ISR_Timer.h>

#include <effects/context.hpp>

Expand All @@ -15,12 +14,39 @@ namespace LedsEffects {
digitalWrite(LED_RED, state.leds.red);
}

void green_toggle(void *params) {
BotContext *context = (BotContext*) params;
auto store = context->store;
store->dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::GREEN
});
}

void blue_toggle(void *params) {
BotContext *context = (BotContext*) params;
auto store = context->store;
store->dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::BLUE
});
}

void red_toggle(void *params) {
BotContext *context = (BotContext*) params;
auto store = context->store;
store->dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::RED
});
}

void setup(BotContext *context) {
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
pinMode(LED_RED, OUTPUT);

auto timer = context->timer;
timer->set_interval(10L, output, context);
timer->set_interval(1000L, green_toggle, context);
timer->set_interval(2000L, blue_toggle, context);
timer->set_interval(4000L, red_toggle, context);
}
}
38 changes: 3 additions & 35 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ BotContext context = {
&timer
};

volatile bool has_state_changed;

void setup()
{
Serial.begin(115200);
Expand All @@ -34,43 +32,13 @@ void setup()
delay(1000);

timer.setup();
server.begin();
BotEffects::setup(&context);

store.subscribe([](BotModel::State state) {
has_state_changed = true;
});

timer.set_interval(1000L, [](){
store.dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::GREEN
});
});

timer.set_interval(2000L, [](){
store.dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::BLUE
});
});

timer.set_interval(4000L, [](){
store.dispatch(LedsModel::ActionToggle {
led_id: LedsModel::LED_ID::RED
});
});
server.begin(&store);
}

void loop()
{
if (has_state_changed) {
BotModel::State state = store.get_state();

String status = "";
if (state.leds.green) status += ":green";
if (state.leds.blue) status += ":blue";
if (state.leds.red) status += ":red";

server.events.send(status.c_str(), "status", millis());
has_state_changed = false;
}
server.loop();
delay(10);
}
18 changes: 18 additions & 0 deletions src/models/bot.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <Arduino.h>
#include <mjson.h>

#include <mpark/variant.hpp>
#include <overload.hpp>
Expand Down Expand Up @@ -33,4 +34,21 @@ namespace BotModel {

return state;
}

int print(mjson_print_fn_t fn, void * fndata, va_list *ap) {
State *state = va_arg(*ap, State*);

noInterrupts();

int n = 0;
n += mjson_printf(fn, fndata, "{ ");
n += mjson_printf(fn, fndata, "%Q: %M", "leds", LedsModel::print, &(state->leds));
n += mjson_printf(fn, fndata, ", ");
n += mjson_printf(fn, fndata, "%Q: %M", "clock", ClockModel::print, &(state->clock));
n += mjson_printf(fn, fndata, " }");

interrupts();

return n;
}
}
13 changes: 12 additions & 1 deletion src/models/clock.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <mjson.h>

#include <mpark/variant.hpp>
#include <overload.hpp>

Expand All @@ -8,7 +10,7 @@ namespace ClockModel {
using Action = mpark::variant<ActionTick>;

struct State {
uint16_t ticks = 0;
volatile unsigned long ticks = 0UL;
};

State reducer(State state, Action action) {
Expand All @@ -20,4 +22,13 @@ namespace ClockModel {

return state;
}

int print(mjson_print_fn_t fn, void * fndata, va_list *ap) {
State *state = va_arg(*ap, State*);
return mjson_printf(
fn, fndata,
"{ %Q: %lu }",
"ticks", state->ticks
);
}
}
20 changes: 17 additions & 3 deletions src/models/leds.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#pragma once

#include <mjson.h>

#include <mpark/variant.hpp>
#include <overload.hpp>

namespace LedsModel {
struct State {
bool green = true;
bool blue = true;
bool red = true;
volatile bool green = true;
volatile bool blue = true;
volatile bool red = true;
};

enum class LED_ID { GREEN, RED, BLUE };
Expand Down Expand Up @@ -35,4 +37,16 @@ namespace LedsModel {

return state;
}


int print(mjson_print_fn_t fn, void * fndata, va_list *ap) {
State *state = va_arg(*ap, State*);
return mjson_printf(
fn, fndata,
"{ %Q: %B, %Q: %B, %Q: %B }",
"green", state->green,
"blue", state->blue,
"red", state->red
);
}
}
34 changes: 32 additions & 2 deletions src/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <STM32Ethernet.h>
#include <AsyncWebServer_STM32.h>

#include <store.hpp>
#include <ui/index.h>

// TODO: generate random mac on first run and store in EEPROM
Expand All @@ -18,12 +19,15 @@ class BotServer {
AsyncWebServer web_server;
AsyncEventSource events;

BotStore* store;
volatile bool has_state_changed = false;

BotServer() :
ip(10, 0, 0, 2),
web_server(80),
events("/events") {};

void begin() {
void begin(BotStore *_store) {
Serial.println("\nStart AsyncWebServer on " + String(BOARD_NAME));
Ethernet.begin(mac, ip);

Expand All @@ -37,6 +41,32 @@ class BotServer {

Serial.print(F("HTTP EthernetWebServer is @ IP : "));
Serial.println(Ethernet.localIP());

store = _store;
store->subscribe([this](BotModel::State state) {
this->has_state_changed = true;
});
}

void loop() {
if (has_state_changed) {
send_state_json(&events);
has_state_changed = false;
}
}

void send_state_json(AsyncEventSourceClient *client) {
BotModel::State state = store->get_state();
char *output = NULL;
mjson_printf(&mjson_print_dynamic_buf, &output, "%M", BotModel::print, &state);
client->send(output, "state", millis());
}

void send_state_json(AsyncEventSource *events) {
BotModel::State state = store->get_state();
char *output = NULL;
mjson_printf(&mjson_print_dynamic_buf, &output, "%M", BotModel::print, &state);
events->send(output, "state", millis());
}

void handle_index (AsyncWebServerRequest *request) {
Expand Down Expand Up @@ -65,6 +95,6 @@ class BotServer {
}

void on_events_connect (AsyncEventSourceClient *client) {
client->send("hello!", NULL);
send_state_json(client);
}
};
2 changes: 1 addition & 1 deletion tools/cdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function writeHtmlGzipped(key, sourceFile, resultFile) {
#include <Arduino.h>
// Autogenerated from ${sourceFile}, do not edit!!
const String PAGE_${key} = String("${escapeString(html)}}");
const String PAGE_${key} = String("${escapeString(html)}");
`

console.info("Writing " + resultFile)
Expand Down
Loading

0 comments on commit 2a91413

Please sign in to comment.