low memory version of arduino meeting-clock code, suitable for the arduino nano
This commit is contained in:
parent
222e748fc4
commit
695f738010
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
262
include/fonts.h
Normal file
262
include/fonts.h
Normal file
@ -0,0 +1,262 @@
|
||||
#pragma once
|
||||
#include <MD_MAX72xx.h>
|
||||
|
||||
MD_MAX72XX::fontType_t font_fw_3x5[] PROGMEM =
|
||||
{
|
||||
0, // 0
|
||||
0, // 1
|
||||
0, // 2
|
||||
0, // 3
|
||||
0, // 4
|
||||
0, // 5
|
||||
0, // 6
|
||||
0, // 7
|
||||
0, // 8
|
||||
0, // 9
|
||||
0, // 10
|
||||
0, // 11
|
||||
0, // 12
|
||||
0, // 13
|
||||
0, // 14
|
||||
0, // 15
|
||||
0, // 16
|
||||
0, // 17
|
||||
0, // 18
|
||||
0, // 19
|
||||
0, // 20
|
||||
0, // 21
|
||||
0, // 22
|
||||
0, // 23
|
||||
0, // 24
|
||||
0, // 25
|
||||
0, // 26
|
||||
0, // 27
|
||||
0, // 28
|
||||
0, // 29
|
||||
0, // 30
|
||||
0, // 31
|
||||
1, 0, // 32
|
||||
0, // 33
|
||||
0, // 34
|
||||
0, // 35
|
||||
0, // 36
|
||||
3, 25, 4, 19, // 37
|
||||
0, // 38
|
||||
1, 3, // 39
|
||||
3, 0, 14, 17, // 40
|
||||
3, 17, 14, 0, // 41
|
||||
3, 5, 2, 5, // 42
|
||||
3, 4, 14, 4, // 43
|
||||
1, 24, // 44
|
||||
3, 4, 4, 4, // 45
|
||||
1, 16, // 46
|
||||
3, 24, 4, 3, // 47
|
||||
3, 31, 17, 31, // 48
|
||||
3, 0, 0, 31, // 49
|
||||
3, 29, 21, 23, // 50
|
||||
3, 21, 21, 31, // 51
|
||||
3, 7, 4, 31, // 52
|
||||
3, 23, 21, 29, // 53
|
||||
3, 31, 21, 29, // 54
|
||||
3, 1, 1, 31, // 55
|
||||
3, 31, 21, 31, // 56
|
||||
3, 23, 21, 31, // 57
|
||||
1, 10, // 58
|
||||
1, 26, // 59
|
||||
0, // 60
|
||||
0, // 61
|
||||
0, // 62
|
||||
0, // 63
|
||||
0, // 64
|
||||
0, // 65
|
||||
0, // 66
|
||||
3, 31, 17, 17, // 67
|
||||
0, // 68
|
||||
0, // 69
|
||||
3, 31, 5, 1, // 70
|
||||
0, // 71
|
||||
0, // 72
|
||||
0, // 73
|
||||
0, // 74
|
||||
0, // 75
|
||||
0, // 76
|
||||
0, // 77
|
||||
0, // 78
|
||||
0, // 79
|
||||
0, // 80
|
||||
0, // 81
|
||||
0, // 82
|
||||
0, // 83
|
||||
0, // 84
|
||||
0, // 85
|
||||
0, // 86
|
||||
0, // 87
|
||||
0, // 88
|
||||
0, // 89
|
||||
0, // 90
|
||||
0, // 91
|
||||
0, // 92
|
||||
0, // 93
|
||||
0, // 94
|
||||
0, // 95
|
||||
0, // 96
|
||||
0, // 97
|
||||
0, // 98
|
||||
0, // 99
|
||||
0, // 100
|
||||
0, // 101
|
||||
0, // 102
|
||||
0, // 103
|
||||
0, // 104
|
||||
0, // 105
|
||||
0, // 106
|
||||
0, // 107
|
||||
0, // 108
|
||||
0, // 109
|
||||
0, // 110
|
||||
0, // 111
|
||||
0, // 112
|
||||
0, // 113
|
||||
3, 28, 4, 4, // 114
|
||||
0, // 115
|
||||
3, 16, 16, 16, // 116
|
||||
0, // 117
|
||||
3, 12, 16, 12, // 118
|
||||
0, // 119
|
||||
0, // 120
|
||||
0, // 121
|
||||
2, 3, 3, // 122
|
||||
0, // 123
|
||||
0, // 124
|
||||
0, // 125
|
||||
0, // 126
|
||||
0, // 127
|
||||
0, // 128
|
||||
0, // 129
|
||||
0, // 130
|
||||
0, // 131
|
||||
0, // 132
|
||||
0, // 133
|
||||
0, // 134
|
||||
0, // 135
|
||||
0, // 136
|
||||
0, // 137
|
||||
0, // 138
|
||||
0, // 139
|
||||
0, // 140
|
||||
0, // 141
|
||||
0, // 142
|
||||
0, // 143
|
||||
0, // 144
|
||||
0, // 145
|
||||
0, // 146
|
||||
0, // 147
|
||||
0, // 148
|
||||
0, // 149
|
||||
0, // 150
|
||||
0, // 151
|
||||
0, // 152
|
||||
0, // 153
|
||||
0, // 154
|
||||
0, // 155
|
||||
0, // 156
|
||||
0, // 157
|
||||
0, // 158
|
||||
0, // 159
|
||||
0, // 160
|
||||
0, // 161
|
||||
0, // 162
|
||||
0, // 163
|
||||
0, // 164
|
||||
0, // 165
|
||||
0, // 166
|
||||
0, // 167
|
||||
0, // 168
|
||||
0, // 169
|
||||
0, // 170
|
||||
0, // 171
|
||||
0, // 172
|
||||
0, // 173
|
||||
0, // 174
|
||||
0, // 175
|
||||
2, 3, 3, // 176
|
||||
0, // 177
|
||||
0, // 178
|
||||
0, // 179
|
||||
0, // 180
|
||||
0, // 181
|
||||
0, // 182
|
||||
0, // 183
|
||||
0, // 184
|
||||
0, // 185
|
||||
0, // 186
|
||||
0, // 187
|
||||
0, // 188
|
||||
0, // 189
|
||||
0, // 190
|
||||
0, // 191
|
||||
0, // 192
|
||||
0, // 193
|
||||
0, // 194
|
||||
0, // 195
|
||||
0, // 196
|
||||
0, // 197
|
||||
0, // 198
|
||||
0, // 199
|
||||
0, // 200
|
||||
0, // 201
|
||||
0, // 202
|
||||
0, // 203
|
||||
0, // 204
|
||||
0, // 205
|
||||
0, // 206
|
||||
0, // 207
|
||||
0, // 208
|
||||
0, // 209
|
||||
0, // 210
|
||||
0, // 211
|
||||
0, // 212
|
||||
0, // 213
|
||||
0, // 214
|
||||
0, // 215
|
||||
0, // 216
|
||||
0, // 217
|
||||
0, // 218
|
||||
0, // 219
|
||||
0, // 220
|
||||
0, // 221
|
||||
0, // 222
|
||||
0, // 223
|
||||
0, // 224
|
||||
0, // 225
|
||||
0, // 226
|
||||
0, // 227
|
||||
0, // 228
|
||||
0, // 229
|
||||
0, // 230
|
||||
0, // 231
|
||||
0, // 232
|
||||
0, // 233
|
||||
0, // 234
|
||||
0, // 235
|
||||
0, // 236
|
||||
0, // 237
|
||||
0, // 238
|
||||
0, // 239
|
||||
0, // 240
|
||||
0, // 241
|
||||
0, // 242
|
||||
0, // 243
|
||||
0, // 244
|
||||
0, // 245
|
||||
0, // 246
|
||||
0, // 247
|
||||
0, // 248
|
||||
0, // 249
|
||||
0, // 250
|
||||
0, // 251
|
||||
0, // 252
|
||||
0, // 253
|
||||
0, // 254
|
||||
0, // 255
|
||||
};
|
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:nanoatmega328]
|
||||
platform = atmelavr
|
||||
board = nanoatmega328
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
majicdesigns/MD_MAX72XX@^3.2.3
|
||||
adafruit/RTClib@^1.12.4
|
630
src/main.cpp
Normal file
630
src/main.cpp
Normal file
@ -0,0 +1,630 @@
|
||||
#include <Arduino.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RTClib.h>
|
||||
#include "fonts.h"
|
||||
|
||||
#define VERSION F("v. 1.0.0")
|
||||
|
||||
#define SERIAL_SPEED 9600
|
||||
#define SERIAL_BT_SPEED 9600
|
||||
#define SERIAL_BT_STATE_PIN 3
|
||||
#define SERIAL_BT_TX_PIN 4
|
||||
#define SERIAL_BT_RX_PIN 5
|
||||
#define LED_HW_TYPE MD_MAX72XX::FC16_HW
|
||||
#define LED_CS_PIN 6
|
||||
#define LED_MODULES 4
|
||||
|
||||
#define STATE_TIME 0
|
||||
#define STATE_DATE 1
|
||||
#define STATE_TEMP 2
|
||||
|
||||
// config addresses
|
||||
#define ADDR_CHECKSUM 0x0
|
||||
#define ADDR_INTENSITY 0x1
|
||||
#define ADDR_TIME_ENABLED_INTERVAL 0x2
|
||||
#define ADDR_DATE_ENABLED_INTERVAL 0x3
|
||||
#define ADDR_TEMP_ENABLED_INTERVAL 0x4
|
||||
#define ADDR_DATE_ENABLED 0x5
|
||||
#define ADDR_TEMP_ENABLED 0x6
|
||||
#define ADDR_SCROLL_SPEED 0x7
|
||||
#define ADDR_SCROLL_WAIT 0x8
|
||||
|
||||
// config default values
|
||||
#define CFG_CHECKSUM 0x2
|
||||
#define CFG_INTENSITY_DEFAULT 0xf
|
||||
#define CFG_TIME_ENABLED_INTERVAL_DEFAULT 35
|
||||
#define CFG_DATE_ENABLED_INTERVAL_DEFAULT 3
|
||||
#define CFG_TEMP_ENABLED_INTERVAL_DEFAULT 3
|
||||
#define CFG_DATE_ENABLED_DEFAULT 1
|
||||
#define CFG_TEMP_ENABLED_DEFAULT 1
|
||||
#define CFG_SCROLL_SPEED_DEFAULT 5
|
||||
#define CFG_SCROLL_WAIT_DEFAULT 40
|
||||
|
||||
// config shortcut macros
|
||||
#define CFG_INTENSITY EEPROM.read(ADDR_INTENSITY)
|
||||
#define CFG_TIME_ENABLED_INTERVAL (((uint16_t)EEPROM.read(ADDR_TIME_ENABLED_INTERVAL)) * 1000)
|
||||
#define CFG_DATE_ENABLED_INTERVAL (((uint16_t)EEPROM.read(ADDR_DATE_ENABLED_INTERVAL)) * 1000)
|
||||
#define CFG_TEMP_ENABLED_INTERVAL (((uint16_t)EEPROM.read(ADDR_TEMP_ENABLED_INTERVAL)) * 1000)
|
||||
#define CFG_DATE_ENABLED EEPROM.read(ADDR_DATE_ENABLED)
|
||||
#define CFG_TEMP_ENABLED EEPROM.read(ADDR_TEMP_ENABLED)
|
||||
#define CFG_SCROLL_SPEED (((uint16_t)EEPROM.read(ADDR_SCROLL_SPEED)) * 10)
|
||||
#define CFG_SCROLL_WAIT (((uint16_t)EEPROM.read(ADDR_SCROLL_WAIT)) * 100)
|
||||
|
||||
// global variables
|
||||
SoftwareSerial btSerial(SERIAL_BT_RX_PIN, SERIAL_BT_TX_PIN);
|
||||
MD_MAX72XX led(LED_HW_TYPE, LED_CS_PIN, LED_MODULES);
|
||||
RTC_DS3231 rtc;
|
||||
|
||||
#define BUFFER_SIZE 20
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
uint8_t state = STATE_TIME;
|
||||
unsigned long lastClockCall = 0;
|
||||
unsigned long lastScrollCall = 0;
|
||||
|
||||
// functions
|
||||
uint8_t conv2d(const char *p, uint8_t maxLen)
|
||||
{
|
||||
uint8_t v = 0;
|
||||
for (uint8_t i = 0; *(p + i) != '\0' && maxLen-- > 0; i++)
|
||||
{
|
||||
v = (v * 10) + (*(p + i) - '0');
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// setup pins
|
||||
pinMode(SERIAL_BT_RX_PIN, INPUT);
|
||||
pinMode(SERIAL_BT_TX_PIN, OUTPUT);
|
||||
pinMode(LED_CS_PIN, OUTPUT);
|
||||
|
||||
// setup serial
|
||||
Serial.begin(SERIAL_SPEED);
|
||||
|
||||
// setup bluetooth serial
|
||||
btSerial.begin(SERIAL_BT_SPEED);
|
||||
|
||||
// setup RTC
|
||||
rtc.begin();
|
||||
|
||||
// setup led matrix
|
||||
led.begin();
|
||||
|
||||
// clear flash
|
||||
if (EEPROM.read(ADDR_CHECKSUM) != CFG_CHECKSUM)
|
||||
{
|
||||
EEPROM.write(ADDR_CHECKSUM, CFG_CHECKSUM);
|
||||
EEPROM.write(ADDR_INTENSITY, CFG_INTENSITY_DEFAULT);
|
||||
EEPROM.write(ADDR_TIME_ENABLED_INTERVAL, CFG_TIME_ENABLED_INTERVAL_DEFAULT);
|
||||
EEPROM.write(ADDR_DATE_ENABLED_INTERVAL, CFG_DATE_ENABLED_INTERVAL_DEFAULT);
|
||||
EEPROM.write(ADDR_TEMP_ENABLED_INTERVAL, CFG_TEMP_ENABLED_INTERVAL_DEFAULT);
|
||||
EEPROM.write(ADDR_DATE_ENABLED, CFG_DATE_ENABLED_DEFAULT);
|
||||
EEPROM.write(ADDR_TEMP_ENABLED, CFG_TEMP_ENABLED_DEFAULT);
|
||||
EEPROM.write(ADDR_SCROLL_SPEED, CFG_SCROLL_SPEED_DEFAULT);
|
||||
EEPROM.write(ADDR_SCROLL_WAIT, CFG_SCROLL_WAIT_DEFAULT);
|
||||
}
|
||||
|
||||
// clear led
|
||||
led.clear();
|
||||
led.control(MD_MAX72XX::INTENSITY, CFG_INTENSITY);
|
||||
led.update(MD_MAX72XX::OFF); // no automatic updates wanted
|
||||
|
||||
lastClockCall = lastScrollCall = millis();
|
||||
}
|
||||
|
||||
// command processing
|
||||
#define COMMAND_SIZE 255
|
||||
char command[COMMAND_SIZE];
|
||||
bool clearCommand = true;
|
||||
|
||||
char *readCommand()
|
||||
{
|
||||
// if clearCommand flag was set, clear the command buffer before we receive new data
|
||||
if (clearCommand)
|
||||
{
|
||||
clearCommand = false;
|
||||
memset(command, 0, sizeof(command) / sizeof(command[0]));
|
||||
}
|
||||
|
||||
// current length of the command
|
||||
uint8_t commandLength = strnlen(command, COMMAND_SIZE);
|
||||
|
||||
// receive available bytes
|
||||
while (btSerial.available() > 0)
|
||||
{
|
||||
// check for command overflow
|
||||
if (commandLength == COMMAND_SIZE)
|
||||
{
|
||||
clearCommand = true; // clear the command buffer and pointers next time
|
||||
return NULL; // no command is available for processing
|
||||
}
|
||||
|
||||
command[commandLength] = btSerial.read(); // receive one byte
|
||||
if (command[commandLength] == '\r' || command[commandLength] == '\n') // the received byte is end-of-command identifier
|
||||
{
|
||||
// end of command was received, null terminate the string, the \r or \n is not needed as part of the command
|
||||
command[commandLength] = '\0';
|
||||
if (strnlen(command, COMMAND_SIZE) == 0) // if the command length is 0, we did not receive anything else but the \r or \n, ignore
|
||||
{
|
||||
clearCommand = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// first 3 bytes are the command (e.g. SET, ADJ, ), then 0 terminate, this is just for convenience
|
||||
// possible arguments to the command will be from command[4] onwards. Maybe all of command[4] and onwards will be NULL if the command
|
||||
// had no parameters. This needs to be checked in code consuming the command
|
||||
command[3] = '\0';
|
||||
|
||||
// next time we need to start with a fresh command buffer
|
||||
clearCommand = true;
|
||||
|
||||
// return that we received a command
|
||||
return command;
|
||||
}
|
||||
|
||||
commandLength++; // the command buffer is now one character longer
|
||||
}
|
||||
|
||||
// no complete command was received yet
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t charBuf[8];
|
||||
#define SCROLL_BUFF_SIZE 255
|
||||
char scrollBuf[SCROLL_BUFF_SIZE];
|
||||
bool showText(char *text, MD_MAX72XX::fontType_t *font, uint8_t tsd, uint16_t scrollSkip = 0)
|
||||
{
|
||||
led.setFont(font);
|
||||
uint16_t position = led.getColumnCount() - 1;
|
||||
bool center = scrollSkip == 0;
|
||||
|
||||
// render the text
|
||||
while (*text != '\0')
|
||||
{
|
||||
uint8_t width = led.getChar((uint8_t)*text, 8, charBuf);
|
||||
for (uint8_t i = 0; i < width; i++)
|
||||
{
|
||||
if (scrollSkip > 0)
|
||||
{
|
||||
// if we are still about to skip columns, reduce the scrollSkip and do nothing else
|
||||
scrollSkip--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are not skipping characters to scroll, so now we can actually draw
|
||||
led.setColumn(position, charBuf[i]);
|
||||
if (position == 0)
|
||||
{
|
||||
break; // there is no more space on the led matrix
|
||||
}
|
||||
else
|
||||
{
|
||||
position--; // move to the next column
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (position == 0)
|
||||
{
|
||||
break; // there is no more space on the led matrix
|
||||
}
|
||||
|
||||
text++; // go to next char
|
||||
|
||||
if (scrollSkip > 0)
|
||||
{
|
||||
scrollSkip--;
|
||||
}
|
||||
else
|
||||
{
|
||||
position--; // move to the next column (one column space between characters)
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollSkip > 0)
|
||||
{
|
||||
// we are done scrolling, but we had not enough text to draw anything (text completely scrolled out of the screen)
|
||||
return true;
|
||||
}
|
||||
|
||||
// center the text if it is shorter than the display (centering is only enabled when not scrolling)
|
||||
while (position > 0 && center)
|
||||
{
|
||||
led.transform(MD_MAX72XX::TSR);
|
||||
position = min(position - 1, position - 2); // avoid underflow of position
|
||||
}
|
||||
|
||||
// translate downwards if requested
|
||||
while (tsd-- > 0)
|
||||
{
|
||||
led.transform(MD_MAX72XX::TSD);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void showClock()
|
||||
{
|
||||
if (rtc.lostPower())
|
||||
{
|
||||
buffer[0] = buffer[1] = buffer[2] = buffer[3] = '-';
|
||||
buffer[4] = '\0';
|
||||
showText(buffer, NULL, 0);
|
||||
lastClockCall = millis();
|
||||
return;
|
||||
}
|
||||
unsigned long diff = millis() - lastClockCall;
|
||||
DateTime now = rtc.now();
|
||||
|
||||
if (state == STATE_TIME) // display the time
|
||||
{
|
||||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%02d:%02d:%02d"), now.hour(), now.minute(), now.second());
|
||||
showText(buffer, font_fw_3x5, 1);
|
||||
|
||||
if (diff >= CFG_TIME_ENABLED_INTERVAL)
|
||||
{
|
||||
lastClockCall = millis();
|
||||
if (CFG_DATE_ENABLED)
|
||||
{
|
||||
state = STATE_DATE;
|
||||
}
|
||||
else if (CFG_TEMP_ENABLED)
|
||||
{
|
||||
state = STATE_TEMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = STATE_TIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state == STATE_DATE) // display the date
|
||||
{
|
||||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%02d.%02d."), now.day(), now.month());
|
||||
showText(buffer, font_fw_3x5, 1);
|
||||
|
||||
if (diff >= CFG_DATE_ENABLED_INTERVAL)
|
||||
{
|
||||
lastClockCall = millis();
|
||||
if (CFG_TEMP_ENABLED)
|
||||
{
|
||||
state = STATE_TEMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = STATE_TIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state == STATE_TEMP) // display the temperature
|
||||
{
|
||||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%02d °C"), (int)rtc.getTemperature());
|
||||
showText(buffer, font_fw_3x5, 1);
|
||||
|
||||
if (diff >= CFG_TEMP_ENABLED_INTERVAL)
|
||||
{
|
||||
lastClockCall = millis();
|
||||
state = STATE_TIME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool scrollEnabled = false;
|
||||
uint16_t scrollSkip;
|
||||
uint16_t scrollWait;
|
||||
|
||||
void beginScrollText(const char *txt)
|
||||
{
|
||||
|
||||
strncpy(scrollBuf, txt, SCROLL_BUFF_SIZE);
|
||||
scrollEnabled = true;
|
||||
scrollSkip = 0;
|
||||
scrollWait = CFG_SCROLL_WAIT;
|
||||
lastScrollCall = millis();
|
||||
showText(scrollBuf, NULL, 0);
|
||||
}
|
||||
|
||||
void endScrollText()
|
||||
{
|
||||
scrollEnabled = false;
|
||||
memset(scrollBuf, 0, sizeof(scrollBuf) / sizeof(scrollBuf[0]));
|
||||
}
|
||||
|
||||
void scrollText()
|
||||
{
|
||||
if (!scrollEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long diff = millis() - lastScrollCall;
|
||||
if (scrollWait > 0)
|
||||
{
|
||||
lastScrollCall = millis();
|
||||
scrollWait = scrollWait - min(scrollWait, diff);
|
||||
if (scrollWait > 0)
|
||||
{
|
||||
showText(scrollBuf, NULL, 0, scrollSkip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (diff >= CFG_SCROLL_SPEED)
|
||||
{
|
||||
bool scrollDone = showText(scrollBuf, NULL, 0, scrollSkip++);
|
||||
if (scrollDone)
|
||||
{
|
||||
scrollWait = CFG_SCROLL_WAIT;
|
||||
scrollSkip = 0;
|
||||
showText(scrollBuf, NULL, 0);
|
||||
}
|
||||
lastScrollCall = millis();
|
||||
}
|
||||
else
|
||||
{
|
||||
showText(scrollBuf, NULL, 0, scrollSkip);
|
||||
}
|
||||
}
|
||||
|
||||
bool blink = false;
|
||||
bool blinkState = false;
|
||||
unsigned long lastBlinkCall;
|
||||
|
||||
void startBlink()
|
||||
{
|
||||
if (blink == false)
|
||||
{
|
||||
blink = true;
|
||||
lastBlinkCall = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void stopBlink()
|
||||
{
|
||||
blink = false;
|
||||
}
|
||||
|
||||
void doBlink()
|
||||
{
|
||||
if (!blink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (blinkState)
|
||||
{
|
||||
led.transform(MD_MAX72XX::TINV);
|
||||
}
|
||||
|
||||
unsigned long diff = millis() - lastBlinkCall;
|
||||
if (diff > 1000)
|
||||
{
|
||||
blinkState = !blinkState;
|
||||
lastBlinkCall = millis();
|
||||
}
|
||||
}
|
||||
|
||||
DateTime *nextTime = 0;
|
||||
|
||||
void loop()
|
||||
{
|
||||
// clear the output
|
||||
led.clear();
|
||||
|
||||
if (!digitalRead(SERIAL_BT_STATE_PIN)) // BT is not connected
|
||||
{
|
||||
showClock();
|
||||
|
||||
// indicate that there is no bluetooth connection
|
||||
led.setPoint(7, 0, true);
|
||||
}
|
||||
else // BT is connected
|
||||
{
|
||||
// read command
|
||||
char *cmd = readCommand();
|
||||
if (cmd != NULL) // command received?
|
||||
{
|
||||
if (strncmp_P(cmd, PSTR("MTC"), 3) == 0)
|
||||
{
|
||||
btSerial.print(F("MTC "));
|
||||
btSerial.println(VERSION);
|
||||
}
|
||||
else if (strncmp_P(cmd, PSTR("ADJ"), 3) == 0)
|
||||
{
|
||||
// Adjust the rtc clock, arguments from position 4 "2000-01-01T00:00:00"
|
||||
cmd[24] = '\0';
|
||||
rtc.adjust(DateTime(&cmd[4]));
|
||||
btSerial.println(F("ADJ"));
|
||||
}
|
||||
else if (strncmp_P(cmd, PSTR("SET"), 3) == 0) // SET a config value
|
||||
{
|
||||
// Set a setting value, arguments:
|
||||
// - form position 4 to 5 contains the setting name (6 is the \0 byte)
|
||||
// - from position 7 the new value begins
|
||||
cmd[6] = '\0';
|
||||
if (strncmp_P(&cmd[4], PSTR("IN"), 2) == 0) // intensity
|
||||
{
|
||||
uint8_t intensity = conv2d(&cmd[7], 2);
|
||||
intensity = (intensity == 0) ? intensity = 1 : ((intensity > MAX_INTENSITY) ? MAX_INTENSITY : intensity);
|
||||
EEPROM.update(ADDR_INTENSITY, intensity);
|
||||
led.control(MD_MAX72XX::INTENSITY, intensity);
|
||||
btSerial.println(F("SET IN"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("TI"), 2) == 0) // time interval
|
||||
{
|
||||
uint8_t interval = conv2d(&cmd[7], 3);
|
||||
EEPROM.update(ADDR_TIME_ENABLED_INTERVAL, interval);
|
||||
btSerial.println(F("SET TI"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("DI"), 2) == 0) // date interval
|
||||
{
|
||||
uint8_t interval = conv2d(&cmd[7], 3);
|
||||
EEPROM.update(ADDR_DATE_ENABLED_INTERVAL, interval);
|
||||
btSerial.println(F("SET TI"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("CI"), 2) == 0) // temperature interval
|
||||
{
|
||||
uint8_t interval = conv2d(&cmd[7], 3);
|
||||
EEPROM.update(ADDR_TEMP_ENABLED_INTERVAL, interval);
|
||||
btSerial.println(F("SET CI"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("DE"), 2) == 0) // date enabled
|
||||
{
|
||||
EEPROM.update(ADDR_DATE_ENABLED, cmd[7] == '1');
|
||||
btSerial.println(F("SET DE"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("CE"), 2) == 0) // temperature enabled
|
||||
{
|
||||
EEPROM.update(ADDR_TEMP_ENABLED, cmd[7] == '1');
|
||||
btSerial.println(F("SET CE"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("SS"), 2) == 0) // scroll speed
|
||||
{
|
||||
uint8_t speed = conv2d(&cmd[7], 3);
|
||||
EEPROM.update(ADDR_SCROLL_SPEED, speed);
|
||||
btSerial.println(F("SET SS"));
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("SW"), 2) == 0) // scroll wait
|
||||
{
|
||||
uint8_t interval = conv2d(&cmd[7], 3);
|
||||
EEPROM.update(ADDR_SCROLL_WAIT, interval);
|
||||
btSerial.println(F("SET SW"));
|
||||
}
|
||||
else
|
||||
{
|
||||
btSerial.println(F("ERR"));
|
||||
}
|
||||
}
|
||||
else if (strncmp_P(cmd, PSTR("GET"), 3) == 0) // GET a config value
|
||||
{
|
||||
// Get a setting value, arguments:
|
||||
// - form position 4 to 5 contains the setting name (6 is the \0 byte)
|
||||
cmd[6] = '\0';
|
||||
if (strncmp_P(&cmd[4], PSTR("IN"), 2) == 0) // intensity
|
||||
{
|
||||
btSerial.print(F("GET IN "));
|
||||
btSerial.println(CFG_INTENSITY);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("TI"), 2) == 0) // time interval
|
||||
{
|
||||
btSerial.print(F("GET TI "));
|
||||
btSerial.println(CFG_TIME_ENABLED_INTERVAL / 1000);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("DI"), 2) == 0) // date interval
|
||||
{
|
||||
btSerial.print(F("GET DI "));
|
||||
btSerial.println(CFG_DATE_ENABLED_INTERVAL / 1000);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("CI"), 2) == 0) // temperature interval
|
||||
{
|
||||
btSerial.print(F("GET CI "));
|
||||
btSerial.println(CFG_TEMP_ENABLED_INTERVAL / 1000);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("DE"), 2) == 0) // date enabled
|
||||
{
|
||||
btSerial.print(F("GET DE "));
|
||||
btSerial.println(CFG_DATE_ENABLED);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("CE"), 2) == 0) // temperature enabled
|
||||
{
|
||||
btSerial.print(F("GET CE "));
|
||||
btSerial.println(CFG_TEMP_ENABLED);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("SS"), 2) == 0) // scroll speed
|
||||
{
|
||||
btSerial.print(F("GET SS "));
|
||||
btSerial.println(CFG_SCROLL_SPEED / 10);
|
||||
}
|
||||
else if (strncmp_P(&cmd[4], PSTR("SW"), 2) == 0) // scroll wait
|
||||
{
|
||||
btSerial.print(F("GET SW "));
|
||||
btSerial.println(CFG_TEMP_ENABLED_INTERVAL / 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
btSerial.println(F("ERR"));
|
||||
}
|
||||
}
|
||||
else if (strncmp_P(cmd, PSTR("SCR"), 3) == 0) // Scroll Text
|
||||
{
|
||||
// position 4 is set to 0 and from position 5 the text to scroll starts
|
||||
// it might be empty when we want to stop the scroll
|
||||
if (cmd[4] == '\0')
|
||||
{
|
||||
endScrollText(); // do not scroll text anymore
|
||||
}
|
||||
else
|
||||
{
|
||||
beginScrollText(&cmd[4]);
|
||||
}
|
||||
btSerial.println(F("SCR"));
|
||||
}
|
||||
else if (strncmp_P(cmd, PSTR("NXT"), 3) == 0) // Next Time
|
||||
{
|
||||
// position 4 is set to 0 and from position 5 the time will start
|
||||
// Next appointmen starts at this time. Format "2000-01-01T00:00:00"
|
||||
if (nextTime != 0)
|
||||
{
|
||||
delete nextTime;
|
||||
}
|
||||
cmd[24] = '\0';
|
||||
nextTime = new DateTime(&cmd[4]);
|
||||
|
||||
btSerial.println(F("NXT"));
|
||||
}
|
||||
else // everything else is unknown (ERR)
|
||||
{
|
||||
btSerial.println(F("ERR"));
|
||||
}
|
||||
}
|
||||
|
||||
if (strnlen(scrollBuf, SCROLL_BUFF_SIZE) > 0)
|
||||
{
|
||||
scrollText();
|
||||
}
|
||||
else
|
||||
{
|
||||
showClock();
|
||||
}
|
||||
|
||||
if (nextTime != 0)
|
||||
{
|
||||
TimeSpan ts = *nextTime - rtc.now();
|
||||
uint8_t devices = led.getDeviceCount();
|
||||
if (ts.totalseconds() < -30)
|
||||
{
|
||||
// time is up
|
||||
// 30 seconds past the time, stop blinking and delete time
|
||||
delete nextTime;
|
||||
nextTime = 0;
|
||||
stopBlink();
|
||||
// also now we can stop scrolling
|
||||
memset(scrollBuf, 0, sizeof(scrollBuf) / sizeof(scrollBuf[0]));
|
||||
}
|
||||
else if (ts.totalseconds() < 30)
|
||||
{
|
||||
// only 30 seconds left, alarm by blinking
|
||||
startBlink();
|
||||
}
|
||||
else if (ts.totalseconds() < ((devices + 1) * 60))
|
||||
{
|
||||
// only some minutes left, start warning
|
||||
for (uint16_t device = 0; device < devices; device++)
|
||||
{
|
||||
if (ts.totalseconds() < (device + 1) * 60)
|
||||
{
|
||||
led.transform(device, device, MD_MAX72XX::TINV);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doBlink();
|
||||
led.update();
|
||||
delay(5); // sleep some tme
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user