Initial commit.
This commit is contained in:
		
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
.pio
 | 
			
		||||
.pioenvs
 | 
			
		||||
.piolibdeps
 | 
			
		||||
.clang_complete
 | 
			
		||||
.gcc-flags.json
 | 
			
		||||
.bak
 | 
			
		||||
.tmp
 | 
			
		||||
							
								
								
									
										67
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							@@ -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 <Foo.h>
 | 
			
		||||
#include <Bar.h>
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										17
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										24
									
								
								src/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/config.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										194
									
								
								src/display.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								src/display.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,194 @@
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#include <U8g2lib.h>
 | 
			
		||||
#include <Wire.h>
 | 
			
		||||
 | 
			
		||||
#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<MAX_NUMBER_CLIENTS_DISPLAYED; ++i) setClientName(i, "---");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Display::begin(void) {
 | 
			
		||||
  u8g2.begin();
 | 
			
		||||
  u8g2.setPowerSave(0);
 | 
			
		||||
  setLargeTextSize();
 | 
			
		||||
  u8g2.drawStr(0,16,"Booting FastClock");
 | 
			
		||||
  u8g2.sendBuffer();
 | 
			
		||||
  delay(200);
 | 
			
		||||
  //addLogMessage("Display initialized");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Display::showBootSequenceFinished(unsigned int ms_per_step) {
 | 
			
		||||
  static int step = 0;
 | 
			
		||||
  static unsigned long lastStep_ms = 0;
 | 
			
		||||
 | 
			
		||||
  if (step > 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; ++i) {
 | 
			
		||||
    u8g2.setCursor(0, i * getTextHeight());
 | 
			
		||||
    u8g2.print(logLine[i]);
 | 
			
		||||
  }
 | 
			
		||||
  u8g2.sendBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Display::addLogMessage(const char *message) {
 | 
			
		||||
  if (numberLogLines >= MAX_NUMBER_LOG_LINES) {
 | 
			
		||||
    for (int i=0; i<MAX_NUMBER_LOG_LINES-1; ++i) memcpy(logLine[i], logLine[i+1], MAX_LOG_MESSAGE_LEN);
 | 
			
		||||
    --numberLogLines;
 | 
			
		||||
  }
 | 
			
		||||
  strncpy(logLine[numberLogLines++], message, MAX_LOG_MESSAGE_LEN);
 | 
			
		||||
  if (currentScreen == LogScreen) showLog();
 | 
			
		||||
  Serial.println(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Display::showDashboard(void) {
 | 
			
		||||
  static unsigned long lastDisplayUpdate_ms = 0;
 | 
			
		||||
 | 
			
		||||
  currentScreen = DashboardScreen;
 | 
			
		||||
  // avoid flickering of the display:
 | 
			
		||||
  if (millis() - lastDisplayUpdate_ms < TIME_BETWEEN_DISPLAY_UPDATES_ms) return;
 | 
			
		||||
  lastDisplayUpdate_ms = millis();
 | 
			
		||||
  
 | 
			
		||||
  u8g2.clearBuffer();
 | 
			
		||||
  u8g2.setDrawColor(1);
 | 
			
		||||
 | 
			
		||||
  // ***** clock name *****
 | 
			
		||||
  setNormalTextSize();
 | 
			
		||||
  u8g2.setCursor(0, getTextHeight()-1);
 | 
			
		||||
  u8g2.print(clockName);
 | 
			
		||||
 | 
			
		||||
  // ****** speed *****
 | 
			
		||||
  setNormalTextSize();
 | 
			
		||||
  u8g2.setCursor(55, 2*getTextHeight()-1);
 | 
			
		||||
  u8g2.print(clockSpeed);
 | 
			
		||||
 | 
			
		||||
  // ***** time *****
 | 
			
		||||
  setLargeTextSize();
 | 
			
		||||
  u8g2.setCursor(0, u8g2.getDisplayHeight()-1);
 | 
			
		||||
  if (clockHour < 10) u8g2.print("0");
 | 
			
		||||
  u8g2.print(clockHour);
 | 
			
		||||
  u8g2.print(":");
 | 
			
		||||
  if (clockMinute < 10) u8g2.print("0");
 | 
			
		||||
  u8g2.print(clockMinute);
 | 
			
		||||
 | 
			
		||||
  // ***** halt/go *****
 | 
			
		||||
  if (clockHalted) {
 | 
			
		||||
    setSmallTextSize();
 | 
			
		||||
    u8g2.setDrawColor(1);
 | 
			
		||||
    u8g2.drawBox(55, u8g2.getDisplayHeight() - 2*getTextHeight()-3, 5*4+2, getTextHeight());
 | 
			
		||||
    u8g2.setDrawColor(0);
 | 
			
		||||
    u8g2.setCursor(57, u8g2.getDisplayHeight() - getTextHeight()-3);
 | 
			
		||||
    u8g2.print("HALT");
 | 
			
		||||
    u8g2.setDrawColor(1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // **** weekday *****
 | 
			
		||||
  setSmallTextSize();
 | 
			
		||||
  u8g2.setCursor(60, u8g2.getDisplayHeight());
 | 
			
		||||
  u8g2.print(clockWeekday);
 | 
			
		||||
 | 
			
		||||
  // ***** # of clients *****
 | 
			
		||||
  setSmallTextSize();
 | 
			
		||||
  u8g2.setCursor(55, getTextHeight());
 | 
			
		||||
  u8g2.print(numberKnownClients); u8g2.print(" -->");
 | 
			
		||||
 | 
			
		||||
  // ***** 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();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/display.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										75
									
								
								src/fastclock.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/fastclock.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								src/fastclock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/fastclock.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										336
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#include <FS.h>                   //this needs to be first, or it all crashes and burns...
 | 
			
		||||
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
 | 
			
		||||
 | 
			
		||||
//needed for library
 | 
			
		||||
#include <DNSServer.h>
 | 
			
		||||
#include <ESP8266WebServer.h>
 | 
			
		||||
#include <WiFiManager.h>
 | 
			
		||||
 | 
			
		||||
#include <ArduinoJson.h>
 | 
			
		||||
#include <SPI.h>
 | 
			
		||||
#include <RF24.h>
 | 
			
		||||
 | 
			
		||||
#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<char[]> 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
 | 
			
		||||
							
								
								
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user