From e4cb28697bce82fa77f0bb61e4c595905aa7e61d Mon Sep 17 00:00:00 2001 From: Dirk Jahnke Date: Wed, 14 Nov 2018 08:43:50 +0100 Subject: [PATCH] Initial commit. --- .gitignore | 7 + .travis.yml | 67 +++++++++ include/README | 39 ++++++ lib/README | 46 +++++++ platformio.ini | 17 +++ src/config.h | 24 ++++ src/display.cpp | 194 ++++++++++++++++++++++++++ src/display.h | 52 +++++++ src/fastclock.cpp | 75 +++++++++++ src/fastclock.h | 31 +++++ src/main.cpp | 336 ++++++++++++++++++++++++++++++++++++++++++++++ test/README | 11 ++ 12 files changed, 899 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 include/README create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/config.h create mode 100644 src/display.cpp create mode 100644 src/display.h create mode 100644 src/fastclock.cpp create mode 100644 src/fastclock.h create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a2b2ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.pio +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json +.bak +.tmp diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7c486f1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,67 @@ +# Continuous Integration (CI) is the practice, in software +# engineering, of merging all developer working copies with a shared mainline +# several times a day < https://docs.platformio.org/page/ci/index.html > +# +# Documentation: +# +# * Travis CI Embedded Builds with PlatformIO +# < https://docs.travis-ci.com/user/integration/platformio/ > +# +# * PlatformIO integration with Travis CI +# < https://docs.platformio.org/page/ci/travis.html > +# +# * User Guide for `platformio ci` command +# < https://docs.platformio.org/page/userguide/cmd_ci.html > +# +# +# Please choose one of the following templates (proposed below) and uncomment +# it (remove "# " before each line) or use own configuration according to the +# Travis CI documentation (see above). +# + + +# +# Template #1: General project. Test it using existing `platformio.ini`. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio run + + +# +# Template #2: The project is intended to be used as a library with examples. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# env: +# - PLATFORMIO_CI_SRC=path/to/test/file.c +# - PLATFORMIO_CI_SRC=examples/file.ino +# - PLATFORMIO_CI_SRC=path/to/test/directory +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..7354227 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,17 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:heltec_wifi_kit_8] +platform = espressif8266 +board = heltec_wifi_kit_8 +framework = arduino + +[lib_deps] +library = WifiManager, RF24, U8g2 diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..3700460 --- /dev/null +++ b/src/config.h @@ -0,0 +1,24 @@ +#ifndef config_h_included +#define config_h_included + +#define PIN_MASTER_CLIENT_SELECT 2 +#define ROLE_MASTER LOW +#define ROLE_CLIENT HIGH +#define PIN_NRF24_CE 10 +#define PIN_NRF24_CSN 8 + +#define PIN_RELAY1 5 +#define PIN_RELAY2 6 + +// communication protocol definitions +#define nRF_Channel 1 +#define THIS_ADRESS 0 // uint8_t address of this node +#define NETWORK_ADDRESS_MASTER_SEND "1ClkM" +#define NETWORK_ADDRESS_MASTER_RECEIVE "2ClkM" + +// relay based clock control behaviour +#define DEFAULT_HOLD_RELAY_MS 150 +#define DEFAULT_MIN_RELAY_OFF_TIME_MS 80 +#define DEFAULT_RELAY_ACTIVE_LOW true + +#endif diff --git a/src/display.cpp b/src/display.cpp new file mode 100644 index 0000000..dd7fa37 --- /dev/null +++ b/src/display.cpp @@ -0,0 +1,194 @@ +#include +#include +#include + +#include "display.h" + + +// display +U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 16, /* clock=*/ 5, /* data=*/ 4); + +#define LOGO16_GLCD_HEIGHT 16 +#define LOGO16_GLCD_WIDTH 16 +static const unsigned char PROGMEM logo16_glcd_bmp[] = +{ 0x00, 0xc0, // B00000000, B11000000, + 0x01, 0xc0, // B00000001, B11000000, + 0x01, 0xc0, // B00000001, B11000000, + 0x03, 0xe0, // B00000011, B11100000, + 0xf3, 0xe0, // B11110011, B11100000, + 0xfe, 0xf8, // B11111110, B11111000, + 0x7e, 0xff, // B01111110, B11111111, + 0x33, 0x9f, // B00110011, B10011111, + 0x1f, 0xfc, // B00011111, B11111100, + 0x0d, 0x70, // B00001101, B01110000, + 0x1b, 0xa0, // B00011011, B10100000, + 0x3f, 0xe0, // B00111111, B11100000, + 0x3f, 0xf0, // B00111111, B11110000, + 0x7c, 0xf0, // B01111100, B11110000, + 0x70, 0x70, // B01110000, B01110000, + 0x00, 0x30 // B00000000, B00110000 +}; + + +void Display::setSmallTextSize(void) { u8g2.setFont(/*u8g2_font_profont10_tf*/ u8g2_font_4x6_tf ); } +int Display::getTextHeight(void) { return u8g2.getMaxCharHeight(); } +int Display::getTextCharsPerLine(void) { return u8g2.getDisplayWidth() / u8g2.getMaxCharWidth(); } + +void Display::setNormalTextSize(void) { u8g2.setFont(/*u8g2_font_t0_11_tf*/ u8g2_font_mozart_nbp_tf); } +//static uint8_t getNormalTextHeight() { return Org_01.yAdvance; } +//static uint8_t getNormalTextCharsPerLine() { return 24; } + +void Display::setLargeTextSize(void) { u8g2.setFont(u8g2_font_9x15B_tf); } +//static uint8_t getLargeTextHeight() { return FreeMonoBold9pt7b.yAdvance; } +//static uint8_t getLargeTextCharsPerLine() { return 12; } + +Display::Display() { + currentScreen = NoScreen; + numberLogLines = 0; + setClockName("noname"); + setClockSpeed("---"); + setTime(5, 0); + setClockWeekday("Mon"); + setClockHalted(true); + setNumberKnownClients(0); + for (int i=0; i 4) return true; // all is done; the value "4" corresponds to the number of steps in following case statement! + if (ms_per_step > millis() - lastStep_ms) return false; // do nothing, if last step execution is not long enough ago + Serial.print("showBootSequence: step="); Serial.println(step); + lastStep_ms = millis(); + + switch (step) { + case 0: + currentScreen = BootSequenceScreen; + break; + case 1: + u8g2.drawPixel(100, 10); + u8g2.drawPixel(102, 12); + u8g2.drawPixel(104, 14); + u8g2.drawPixel(106, 16); + u8g2.sendBuffer(); + break; + case 2: + u8g2.drawLine(100, u8g2.getDisplayHeight()-1, u8g2.getDisplayWidth()-1, u8g2.getDisplayHeight()/2); + u8g2.drawCircle(u8g2.getDisplayWidth()-20, u8g2.getDisplayHeight()-10, 10, U8G2_DRAW_UPPER_LEFT | U8G2_DRAW_LOWER_RIGHT); + u8g2.sendBuffer(); + break; + case 3: + u8g2.drawXBMP(60, 0, 16, 16, logo16_glcd_bmp); + u8g2.sendBuffer(); + break; + case 4: + break; // empty step to be sure, that last step is displayed long enough + // if you add a step, then you need to change the condition at the beginning of this method as well (if (step > ...) + default: // do nothing + break; + } + ++step; + return false; +} + +void Display::showLog(void) { + currentScreen = LogScreen; + u8g2.clearBuffer(); + u8g2.setDrawColor(1); + setSmallTextSize(); + for (int i=0; i= MAX_NUMBER_LOG_LINES) { + for (int i=0; i"); + + // ***** client list ***** + u8g2.drawVLine(79, 0, u8g2.getDisplayHeight()); + for (int i=0; i<5; ++i) { + u8g2.setDrawColor(1); + u8g2.drawBox(81, i * getTextHeight(), 3*3+1, getTextHeight()); + u8g2.setCursor(82, (i+1) * getTextHeight()); + u8g2.setDrawColor(0); + if (i < 10) u8g2.print(0); + u8g2.print(i); + u8g2.setDrawColor(1); + u8g2.setCursor(82+3*3+1+1, (i+1) * getTextHeight()); + u8g2.print(clientName[i]); + } + u8g2.sendBuffer(); +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..531d730 --- /dev/null +++ b/src/display.h @@ -0,0 +1,52 @@ +#ifndef display_h_included +#define display_h_included + +// avoid flickering of the display: +#define TIME_BETWEEN_DISPLAY_UPDATES_ms 200 + +#define MAX_CLOCK_NAME_LEN 8 +#define MAX_CLOCK_SPEED_LEN 8 +#define MAX_CLOCK_WEEKDAY_LEN 4 +#define MAX_NUMBER_CLIENTS_DISPLAYED 5 +#define MAX_CLIENT_NAME_LEN 10 +#define MAX_LOG_MESSAGE_LEN 30 +#define MAX_NUMBER_LOG_LINES 5 + +enum ScreenMode { NoScreen, BootSequenceScreen, LogScreen, DashboardScreen }; + +class Display { +public: + Display(); + void begin(void); + bool showBootSequenceFinished(unsigned int ms_per_step); // call this in your loop function, parameter ms_per_step controls the speed by naming the milliseconds each step should take + void showDashboard(void); + void setClockName(const char *name) { strncpy(clockName, name, MAX_CLOCK_NAME_LEN); }; + void setClockSpeed(const char *speed) { strncpy(clockSpeed, speed, MAX_CLOCK_SPEED_LEN); }; + void setTime(int hour, int minute) { clockHour = hour; clockMinute = minute; Serial.print("display: new time "); Serial.print(clockHour); Serial.print(":"); Serial.println(clockMinute); } + //void setClockSpeed(int _msPerModelSecond) { msPerModelSecond = _msPerModelSecond; setClockSpeed("x"); }; + void setClockWeekday(const char *weekday) { strncpy(clockWeekday, weekday, MAX_CLOCK_WEEKDAY_LEN); }; + void setClockHalted(bool halted) { clockHalted = halted; }; + void setNumberKnownClients(int _numberKnownClients) { numberKnownClients = _numberKnownClients; }; + void setClientName(int clientNumber, const char *name) { if (clientNumber < MAX_NUMBER_CLIENTS_DISPLAYED) { strncpy(clientName[clientNumber], name, MAX_CLIENT_NAME_LEN); }}; + void addLogMessage(const char *message); + void showLog(void); +private: + ScreenMode currentScreen; + char clockName[MAX_CLOCK_NAME_LEN]; + char clockSpeed[MAX_CLOCK_SPEED_LEN]; + //int msPerModelSecond; // milliseconds each model second takes. A 500 means the clock runs twice as fast as real time. + int clockHour; + int clockMinute; + char clockWeekday[MAX_CLOCK_WEEKDAY_LEN]; + bool clockHalted; + int numberKnownClients; + char clientName[MAX_NUMBER_CLIENTS_DISPLAYED][MAX_CLIENT_NAME_LEN]; + char logLine[MAX_NUMBER_LOG_LINES][MAX_LOG_MESSAGE_LEN]; + int numberLogLines; + void setSmallTextSize(void); + int getTextHeight(void); + int getTextCharsPerLine(void); + void setNormalTextSize(void); + void setLargeTextSize(void); +}; +#endif diff --git a/src/fastclock.cpp b/src/fastclock.cpp new file mode 100644 index 0000000..c00104d --- /dev/null +++ b/src/fastclock.cpp @@ -0,0 +1,75 @@ +#include +#include "fastclock.h" + + +void Fastclock::setClockSpeed(unsigned int _msPerModelSecond) { + msPerModelSecond = _msPerModelSecond; + char speedString[10]; + snprintf(speedString, 6, "1:%1.1f", 1000.0 / msPerModelSecond); + display->setClockSpeed(speedString); +} + +void Fastclock::incrementClockByMilliseconds(int amount) { + millisecond += amount; + if (millisecond >= 1000) { + unsigned int carryover = millisecond / 1000; + millisecond = millisecond % 1000; + second += carryover; + if (second >= 60) { + carryover = second / 60; + second = second % 60; + minute += carryover; + if (minute >= 60) { + carryover = minute / 60; + minute = minute % 60; + hour += carryover; + if (hour >= 24) { + carryover = hour / 24; + hour = hour % 24; + weekday += carryover; + if (weekday >= 7) { + weekday = weekday % 7; + } + } + } + } + } + /* + char timeString[51]; + snprintf(timeString, 50, "%02d:%02d:%02d.%03d day %d, incBy_ms=%d", hour, minute, second, millisecond, weekday, amount); + Serial.print("*** new clock: "); + Serial.println(timeString); + */ +} + +static const char *weekdayString[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + +void Fastclock::loop(void) { + long newTimeTick = millis(); + uint8_t oldMinute, oldDay; + + if (msPerModelSecond == 0) { + Serial.println("Model speed invalid, msPerModelSecond=0"); + msPerModelSecond = 500; + } + if (newTimeTick - lastTimeTickUsed < MIN_TIME_ms_BETWEEN_CLOCK_UPDATES) return; + int fastclockTimeAdvance = (newTimeTick - lastTimeTickUsed) * 1000 / msPerModelSecond; + + oldMinute = minute; + oldDay = weekday; + incrementClockByMilliseconds(fastclockTimeAdvance); + lastTimeTickUsed = newTimeTick; + if (oldMinute != minute) { + Serial.print("*** minute change, tick adv="); Serial.println(fastclockTimeAdvance); + display->setTime(hour, minute); + if (oldDay != weekday) display->setClockWeekday(weekdayString[weekday]); + // time has changed, send an update via rf + // @TODO implement sending radio message + Serial.println("Would send new time"); + } +} + +void Fastclock::begin(void) { + lastTimeTickUsed = millis(); + Serial.print("*** Setting up Fastclock, init lastSentTimeTick="); Serial.println(lastTimeTickUsed); +} diff --git a/src/fastclock.h b/src/fastclock.h new file mode 100644 index 0000000..1a0325a --- /dev/null +++ b/src/fastclock.h @@ -0,0 +1,31 @@ +#ifndef fastclock_h_included +#define fastclock_h_included + +#include "display.h" + +#define MIN_TIME_ms_BETWEEN_CLOCK_UPDATES 200 + +class Fastclock { +public: + Fastclock(Display *d): display(d) { weekday=0; hour=0; minute=0; second=0; millisecond=0; msPerModelSecond=500; }; + void begin(void); + void loop(void); + void incrementClockByMilliseconds(int amount); + void setClockSpeed(unsigned int msPerModelSecond); + void setTime(uint8_t hours, uint8_t minutes) { hour = hours; minute = minutes; second = 0; millisecond = 0; }; + void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds) { hour = hours; minute = minutes; second = seconds; millisecond = 0; }; + void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint16_t milliseconds) { hour = hours; minute = minutes; second = seconds; millisecond = milliseconds; }; + void setWeekday(uint8_t _weekday) { weekday = _weekday; }; +private: + Display *display; + unsigned long lastTimeTickUsed; // used to calculate model time + unsigned long msPerModelSecond; // 500 = twice as fast as real time + uint8_t weekday; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint16_t millisecond; + +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..594ce22 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,336 @@ +#include +#include //this needs to be first, or it all crashes and burns... +#include //https://github.com/esp8266/Arduino + +//needed for library +#include +#include +#include + +#include +#include +#include + +#include "config.h" +#include "display.h" +#include "fastclock.h" + +//define your default values here, if there are different values in config.json, they are overwritten. +//length should be max size + 1 +char mqtt_server[40] = ""; +char mqtt_port[6] = "8080"; +//char blynk_token[33] = "YOUR_BLYNK_TOKEN"; +//default custom static IP +char static_ip[16] = "10.0.1.56"; +char static_gw[16] = "10.0.1.1"; +char static_sn[16] = "255.255.255.0"; + +//flag for saving data +bool shouldSaveConfig = false; + +RF24 radio(PIN_NRF24_CE, PIN_NRF24_CSN); +byte addresses[][6] = {NETWORK_ADDRESS_MASTER_SEND, NETWORK_ADDRESS_MASTER_RECEIVE}; + +// FastClock +bool isMaster = true; + +Display display; +Fastclock fastclock(&display); + +//callback notifying us of the need to save config +void saveConfigCallback () { + Serial.println("Should save config"); + shouldSaveConfig = true; +} + +void setupWifiConnection() { + // The extra parameters to be configured (can be either global or just in the setup) + // After connecting, parameter.getValue() will get you the configured value + // id/name placeholder/prompt default length + //**WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); + //**WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5); + //WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34); + + //WiFiManager + //Local intialization. Once its business is done, there is no need to keep it around + WiFiManager wifiManager; + + //set config save notify callback + wifiManager.setSaveConfigCallback(saveConfigCallback); + + //set static ip + IPAddress _ip,_gw,_sn; + _ip.fromString(static_ip); + _gw.fromString(static_gw); + _sn.fromString(static_sn); + + //wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); + + //add all your parameters here + //**wifiManager.addParameter(&custom_mqtt_server); + //**wifiManager.addParameter(&custom_mqtt_port); + //wifiManager.addParameter(&custom_blynk_token); + + //reset settings - for testing + //wifiManager.resetSettings(); + + //set minimu quality of signal so it ignores AP's under that quality + //defaults to 8% + wifiManager.setMinimumSignalQuality(); + + //sets timeout until configuration portal gets turned off + //useful to make it all retry or go to sleep + //in seconds + //wifiManager.setTimeout(120); + + //fetches ssid and pass and tries to connect + //if it does not connect it starts an access point with the specified name + //and goes into a blocking loop awaiting configuration + Serial.println("Starting autoConnect ..."); + if (!wifiManager.autoConnect("FastclockMasterAP", "password")) { + Serial.println("failed to connect and hit timeout"); + delay(3000); + //reset and try again, or maybe put it to deep sleep + ESP.reset(); + delay(5000); + } + + //if you get here you have connected to the WiFi + Serial.println("connected...yeey :)"); + display.addLogMessage("WLAN connected"); + + //read updated parameters + //**strcpy(mqtt_server, custom_mqtt_server.getValue()); + //**strcpy(mqtt_port, custom_mqtt_port.getValue()); + //strcpy(blynk_token, custom_blynk_token.getValue()); + + //save the custom parameters to FS + if (shouldSaveConfig) { + Serial.println("saving config"); + DynamicJsonBuffer jsonBuffer; + JsonObject& json = jsonBuffer.createObject(); + //**json["mqtt_server"] = mqtt_server; + //**json["mqtt_port"] = mqtt_port; + //json["blynk_token"] = blynk_token; + + json["ip"] = WiFi.localIP().toString(); + json["gateway"] = WiFi.gatewayIP().toString(); + json["subnet"] = WiFi.subnetMask().toString(); + + File configFile = SPIFFS.open("/config.json", "w"); + if (!configFile) { + Serial.println("failed to open config file for writing"); + } + + json.prettyPrintTo(Serial); + json.printTo(configFile); + configFile.close(); + //end save + } + + Serial.print("local ip: "); Serial.println(WiFi.localIP()); + Serial.print("gateway: "); Serial.println(WiFi.gatewayIP()); + Serial.print("subnet: "); Serial.println(WiFi.subnetMask()); +} + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + Serial.println("Starting *** FastclockMasterESP8266"); + display.begin(); + display.showLog(); + + //clean FS, for testing + //SPIFFS.format(); + + //read configuration from FS json + Serial.println("mounting FS..."); + display.addLogMessage("mounting FS ..."); + + if (SPIFFS.begin()) { + Serial.println("mounted file system"); + display.addLogMessage("mounting FS done"); + if (SPIFFS.exists("/config.json")) { + //file exists, reading and loading + Serial.println("reading config file"); + display.addLogMessage("reading config file"); + File configFile = SPIFFS.open("/config.json", "r"); + if (configFile) { + Serial.println("opened config file"); + size_t size = configFile.size(); + // Allocate a buffer to store contents of the file. + std::unique_ptr buf(new char[size]); + + configFile.readBytes(buf.get(), size); + DynamicJsonBuffer jsonBuffer; + JsonObject& json = jsonBuffer.parseObject(buf.get()); + json.printTo(Serial); + if (json.success()) { + Serial.println("\nparsed json"); + + //**strcpy(mqtt_server, json["mqtt_server"]); + //**strcpy(mqtt_port, json["mqtt_port"]); + //strcpy(blynk_token, json["blynk_token"]); + + if (json["ip"]) { + Serial.print("setting custom ip from config: "); + //**strcpy(static_ip, json["ip"]); + //**strcpy(static_gw, json["gateway"]); + //**strcpy(static_sn, json["subnet"]); + Serial.println(static_ip); +/* Serial.println("converting ip"); + IPAddress ip = ipFromCharArray(static_ip); + Serial.println(ip);*/ + } else { + Serial.println("no custom ip in config"); + } + } else { + display.addLogMessage("failed loading json"); + Serial.println("failed to load json config"); + } + } + } + } else { + display.addLogMessage("failed mounting FS"); + Serial.println("failed to mount FS"); + } + //end read + display.addLogMessage(static_ip); + display.addLogMessage(mqtt_server); + Serial.print("static ip: "); Serial.println(static_ip); + //Serial.println(blynk_token); + //**Serial.print("mqtt: "); Serial.println(mqtt_server); + + // setupWifiConnection(); + + // setting up RF24 + #if 0 + display.addLogMessage("Start RF24 radio"); + radio.begin(); + // Open a writing and reading pipe on each radio, with opposite addresses + if (isMaster){ + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); + } else { + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + } + + // Start the radio listening for data + radio.startListening(); + #endif + + fastclock.begin(); +} + +void loop(void) +{ + if (!display.showBootSequenceFinished(1000)) { + return; + } + + fastclock.loop(); + display.showDashboard(); + + #if 0 + // put your main code here, to run repeatedly: + /****************** Ping Out Role ***************************/ + if (isMaster) { + + radio.stopListening(); + + Serial.println(F("Now sending")); + + unsigned long start_time = micros(); + if (!radio.write(&start_time, sizeof(unsigned long))) { + Serial.println(F("failed")); + } + + radio.startListening(); + + unsigned long started_waiting_at = micros(); + boolean timeout = false; + + while (!radio.available()) { + if (micros() - started_waiting_at > 200000 ) { // If waited longer than 200ms, indicate timeout and exit while loop + timeout = true; + break; + } + } + + if (timeout) { + Serial.println(F("Failed, response timed out.")); + } else { + unsigned long got_time; + radio.read( &got_time, sizeof(unsigned long) ); + unsigned long end_time = micros(); + + // Spew it + Serial.print(F("Sent ")); + Serial.print(start_time); + Serial.print(F(", Got response ")); + Serial.print(got_time); + Serial.print(F(", Round-trip delay ")); + Serial.print(end_time-start_time); + Serial.println(F(" microseconds")); + } + + // Try again 1s later + delay(1000); + } + + + + /****************** Pong Back Role ***************************/ + + if (!isMaster) + { + unsigned long got_time; + + if( radio.available()){ + // Variable for the received timestamp + while (radio.available()) { // While there is data ready + radio.read( &got_time, sizeof(unsigned long) ); // Get the payload + } + + radio.stopListening(); // First, stop listening so we can talk + radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. + radio.startListening(); // Now, resume listening so we catch the next packets. + Serial.print(F("Sent response ")); + Serial.println(got_time); + } + } + #endif +} + + +#if 0 +#ifdef RF_RadioHead + if (!Datagram.init()) { + LOG(LL_ERROR, ("*** Datagram init failed")); + } +#endif + +#ifdef RF_RF24 + radio.begin(); + if (radio.isChipConnected()) { LOG(LL_INFO, ("*** RF chip found")); } + else { LOG(LL_ERROR, ("*** ERROR: RF chip not found!")); } + radio.setChannel(1); + radio.setPALevel(RF24_PA_MAX); + radio.setDataRate(RF24_2MBPS); + radio.setAutoAck(0); + //radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries + radio.setCRCLength(RF24_CRC_8); + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1,pipes[1]); + radio.startListening(); + radio.printDetails(); + // @TODO: real random seed! + //randomSeed(analogRead(0)); + //randomSeed(22); + radio.powerUp(); + LOG(LL_INFO, ("*** RF payload size=%d bytes", radio.getPayloadSize())); + if (radio.testCarrier() || radio.testRPD()) { LOG(LL_INFO, ("*** Carrier/RPD seen on radio")); } + if (radio.failureDetected) { LOG(LL_ERROR, ("*** Radio error detected!")); } +#endif +#endif diff --git a/test/README b/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html