Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Clean up api for serialization, fix bug with config fetching from webserver. #235

Merged
merged 3 commits into from
Dec 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 46 additions & 34 deletions src/thing/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,56 @@

namespace thing {

void Config::SerializeToJson(Stream* output, std::function<void(int size)> handle_size) const {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["host"] = host.c_str();
root["auth"] = auth.c_str();
root["path"] = path.c_str();
root["wifi_ssid"] = wifi_ssid.c_str();
root["wifi_key"] = wifi_key.c_str();
root["analog_activation"] = analog_activation_threshold;
root["wifi_connect_attempts"] = wifi_connect_attempts;
ConfigJsonSerializer::ConfigJsonSerializer(const Config& config) {
JsonObject& root = buffer_.createObject();
root_ = &root;
root["host"] = config.host.c_str();
root["auth"] = config.auth.c_str();
root["path"] = config.path.c_str();
root["wifi_ssid"] = config.wifi_ssid.c_str();
root["wifi_key"] = config.wifi_key.c_str();
root["analog_activation"] = config.analog_activation_threshold;
root["wifi_connect_attempts"] = config.wifi_connect_attempts;

JsonObject& pins_root = root.createNestedObject("pins");
pins_root["digital_in"] = pins.digital_in;
pins_root["digital_out"] = pins.digital_out;
pins_root["analog_in"] = pins.analog_in;
pins_root["analog_out"] = pins.analog_out;
pins_root["config_mode_button"] = pins.config_mode_button;

handle_size(root.measureLength());
root.printTo(*output);
pins_root["digital_in"] = config.pins.digital_in;
pins_root["digital_out"] = config.pins.digital_out;
pins_root["analog_in"] = config.pins.analog_in;
pins_root["analog_out"] = config.pins.analog_out;
pins_root["config_mode_button"] = config.pins.config_mode_button;
}

void Config::ReadFromJson(char* string) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(string);
host = root["host"].asString();
auth = root["auth"].asString();
path = root["path"].asString();
wifi_ssid = root["wifi_ssid"].asString();
wifi_key = root["wifi_key"].asString();
analog_activation_threshold = root["activation_threshold"];
wifi_connect_attempts = root["wifi_connect_attempts"];

pins.digital_in = root["pins"]["digital_in"];
pins.digital_out = root["pins"]["digital_out"];
pins.analog_in = root["pins"]["analog_in"];
pins.analog_out = root["pins"]["analog_out"];
pins.config_mode_button = root["pins"]["config_mode_button"];
ConfigJsonSerializer::ConfigJsonSerializer(char* serialized_config) {
root_ = &(buffer_.parseObject(serialized_config));
}

int ConfigJsonSerializer::content_length() const {
return root_->measureLength();
}

void ConfigJsonSerializer::SerializeTo(Stream* output) {
// TODO: We "should" be able to have the root_ print directly to the stream
// however it currently closes the connection half way through. Fixing this
// would save ~250B of memory during serialization.
String buffer;
root_->printTo(buffer);
output->print(buffer);
}

void ConfigJsonSerializer::DeserializeTo(Config* config) {
config->host = root()["host"].asString();
config->auth = root()["auth"].asString();
config->path = root()["path"].asString();
config->wifi_ssid = root()["wifi_ssid"].asString();
config->wifi_key = root()["wifi_key"].asString();
config->analog_activation_threshold = root()["activation_threshold"];
config->wifi_connect_attempts = root()["wifi_connect_attempts"];

config->pins.digital_in = root()["pins"]["digital_in"];
config->pins.digital_out = root()["pins"]["digital_out"];
config->pins.analog_in = root()["pins"]["analog_in"];
config->pins.analog_out = root()["pins"]["analog_out"];
config->pins.config_mode_button = root()["pins"]["config_mode_button"];
}

};
Expand Down
18 changes: 16 additions & 2 deletions src/thing/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Arduino.h"
#include <string>
#include <functional>
#include "third-party/arduino-json-5.6.7/include/ArduinoJson.h"

namespace thing {

Expand All @@ -29,11 +30,24 @@ struct Config {
int wifi_connect_attempts;

Pins pins;
};

void SerializeToJson(Stream* output, std::function<void(int size)> handle_size) const;
class ConfigJsonSerializer {
public:
ConfigJsonSerializer(const Config& config);

// We need a mutable char array here, otherwise a copy will be made.
void ReadFromJson(char* string);
ConfigJsonSerializer(char* config);

int content_length() const;
void SerializeTo(Stream* output);
void DeserializeTo(Config* config);

private:
JsonObject& root() {return *root_;}

DynamicJsonBuffer buffer_;
JsonObject* root_;
};

} // namespace thing
Expand Down
23 changes: 19 additions & 4 deletions src/thing/FireThing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ Config kDefaultConfig = {
"", // wifi ssid
"", // wifi key
0.1, // analog activation threshold
2, // wifi connect attempts
{
D1, // digital in
BUILTIN_LED, // digital out
A0, // analog in
D1, // analog out
D0, // config mode button
}
};

const char kStorageFilename[] = "fthing.cfg";
Expand All @@ -32,8 +35,7 @@ bool FireThing::Setup() {
return false;
}
SetPinModes(config);

if (digitalRead(config.pins.config_mode_button) || !ConnectToWiFi(config)) {
if (digitalRead(config.pins.config_mode_button) == HIGH || !ConnectToWiFi(config)) {
wifi_.StartAP();
}

Expand All @@ -54,9 +56,20 @@ void FireThing::Loop() {
transcriber_.Loop();
}

bool FireThing::DeleteStoredConfig() {
if (!SPIFFS.begin()) {
debug_("Failed to mount FS.");
return false;
}
bool success = SPIFFS.remove(kStorageFilename);
SPIFFS.end();
return success;
}

bool FireThing::ConnectToWiFi(const Config& config) {
debug_("Connecting to wifi:");
debug_(config.wifi_ssid.c_str());
// TODO we should probably not print the key to serial.
debug_(config.wifi_key.c_str());
if (wifi_.Connect(config.wifi_ssid, config.wifi_key)) {
debug_("Connected");
Expand Down Expand Up @@ -93,7 +106,8 @@ bool FireThing::ReadConfigFromStorage(Config* config) {
}
char buffer[cfg.size()];
cfg.readBytes(buffer, cfg.size());
config->ReadFromJson(buffer);
ConfigJsonSerializer serializer(buffer);
serializer.DeserializeTo(config);
debug_("Config read from disk.");
}

Expand All @@ -113,7 +127,8 @@ bool FireThing::WriteConfigToStorage(const Config& config) {
SPIFFS.end();
return false;
}
config.SerializeToJson(&cfg, [](int){});
ConfigJsonSerializer serializer(config);
serializer.SerializeTo(&cfg);

SPIFFS.end();
return true;
Expand Down
3 changes: 3 additions & 0 deletions src/thing/FireThing.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class FireThing {

void SetDebugHandler(std::function<void(const char* message)> debug);

// Called to delete the currently stored config from the filesystem.
bool DeleteStoredConfig();

private:
bool ReadConfigFromStorage(Config* config);
bool WriteConfigToStorage(const Config& config);
Expand Down
17 changes: 10 additions & 7 deletions src/thing/Portal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ void Portal::Start(const Config& config) {
server_.on("/config", [&] () {
if (server_.method() == HTTP_GET) {
auto client = server_.client();
config_.SerializeToJson(&client,
[this](int size) {
server_.setContentLength(size);
server_.send(200, "application/json");
});

ConfigJsonSerializer serializer(config_);
server_.setContentLength(serializer.content_length());
server_.send(200, "application/json");
serializer.SerializeTo(&client);

debug_("config retrieved");
} else if (server_.method() == HTTP_POST) {
Expand All @@ -132,8 +132,11 @@ void Portal::Start(const Config& config) {
buffer = (char*)malloc(config.length()+1);
memcpy(buffer, config.c_str(), config.length()+1);
}
config_.ReadFromJson(buffer);
free(buffer);
{ // Scoped because serializer is invalid after free().
ConfigJsonSerializer serializer(buffer);
serializer.DeserializeTo(&config_);
free(buffer);
}

callback_(config_);
server_.send(200, "text/plain", "");
Expand Down