add buttons: backlight+msg history; bug fixes

This commit is contained in:
LowPowerLab 2016-01-22 14:39:51 -05:00
parent d33a4dfc9c
commit 9793c033e0
1 changed files with 106 additions and 29 deletions

View File

@ -44,11 +44,11 @@
#define NODEID 1 //the gateway has ID=1 #define NODEID 1 //the gateway has ID=1
#define NETWORKID 100 //all nodes on the same network can talk to each other #define NETWORKID 100 //all nodes on the same network can talk to each other
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) #define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
#define FREQUENCY_EXACT 917000000 //uncomment and set to a specific frequency in Hz, if commented the center frequency is used //#define FREQUENCY_EXACT 917000000 //uncomment and set to a specific frequency in Hz, if commented the center frequency is used
#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! #define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! #define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL //more here: http://lowpowerlab.com/blog/2015/11/11/rfm69_atc-automatic-transmission-control/ #define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL //more here: http://lowpowerlab.com/blog/2015/11/11/rfm69_atc-automatic-transmission-control/
#define ENABLE_WIRELESS_PROGRAMMING //comment out this line to disable Wireless Programming of this gateway node //#define ENABLE_WIRELESS_PROGRAMMING //comment out this line to disable Wireless Programming of this gateway node
#define ENABLE_LCD //comment this out if you don't have or don't want to use the LCD #define ENABLE_LCD //comment this out if you don't have or don't want to use the LCD
//***************************************************************************************************************************** //*****************************************************************************************************************************
#define ACK_TIME 30 // # of ms to wait for an ack #define ACK_TIME 30 // # of ms to wait for an ack
@ -68,6 +68,8 @@
#define BUZZER 5 // Buzzer attached to D5 (PWM pin required for tones) #define BUZZER 5 // Buzzer attached to D5 (PWM pin required for tones)
#define BUTTON A2 // Power button pin #define BUTTON A2 // Power button pin
#define BUTTON1 A4 // Backlight control button
#define BUTTON2 A5 // Backlight control button
#define LATCH_EN 4 #define LATCH_EN 4
#define LATCH_VAL 7 #define LATCH_VAL 7
#define SIG_SHUTOFF A3 // Signal to Pi to ask for a shutdown #define SIG_SHUTOFF A3 // Signal to Pi to ask for a shutdown
@ -110,13 +112,10 @@
byte ackCount=0; byte ackCount=0;
String inputstr; String inputstr;
byte inputLen=0; byte inputLen=0;
char BATstr[5];
char BATvstr[6];
char RSSIstr[] = "-100dBm"; char RSSIstr[] = "-100dBm";
char input[64]; char temp[64];
byte temp[61]; //used for serial input
int lastValidReading = 1; byte lastValidReading = 1;
unsigned long lastValidReadingTime = 0; unsigned long lastValidReadingTime = 0;
unsigned long NOW=0; unsigned long NOW=0;
byte PowerState = OFF; byte PowerState = OFF;
@ -143,7 +142,9 @@ char lcdbuff[80];
#define PIN_LCD_LIGHT 3 //Backlight pin #define PIN_LCD_LIGHT 3 //Backlight pin
#define xbmp_logo_width 30 #define xbmp_logo_width 30
#define xbmp_logo_height 27 #define xbmp_logo_height 27
#define LCD_BACKLIGHT(x) { if (x) analogWrite(PIN_LCD_LIGHT, 100); else analogWrite(PIN_LCD_LIGHT, 0); } #define BACKLIGHTLEVELS 5 //5 levels gives a nice round number that allows full brightness
void LCD_BACKLIGHT(byte level) { if (level>BACKLIGHTLEVELS) level=BACKLIGHTLEVELS; analogWrite(PIN_LCD_LIGHT, 255-level*255/BACKLIGHTLEVELS); }
byte backlightLevel=BACKLIGHTLEVELS; //max at startup
const uint8_t xbmp_logo[] PROGMEM = { const uint8_t xbmp_logo[] PROGMEM = {
0xe0, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0x08, 0x00, 0x00, 0x04, 0xe0, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0x08, 0x00, 0x00, 0x04,
@ -193,8 +194,7 @@ void clearDisplay() {
} }
void refreshLCD() { void refreshLCD() {
noInterrupts(); noInterrupts(); //while messing with LCD need to pause interrups from radio to avoid SPI conflicts!
//SPI.setClockDivider(SPI_CLOCK_DIV16);
byte lcdwidth = lcd.getWidth(); byte lcdwidth = lcd.getWidth();
byte lcdheight = lcd.getHeight(); byte lcdheight = lcd.getHeight();
char c; char c;
@ -216,14 +216,14 @@ void refreshLCD() {
//this section splits the textp string into chunks that fit on the screen width and prints each to a new line //this section splits the textp string into chunks that fit on the screen width and prints each to a new line
while(textLength && !done) while(textLength && !done)
{ {
//DEBUGln(textLength);
for (i=1;i<=textLength;i++) for (i=1;i<=textLength;i++)
{ {
c = textp[i]; c = textp[i];
textp[i]=0; textp[i]=0;
swidth = lcd.getStrWidth(textp); swidth = lcd.getStrWidth(textp);
textp[i] = c; textp[i] = c;
if (swidth > lcdwidth || c=='\n') { pos = i-1; break; } if (c=='\n') { pos = i; break; } //newline char found, skip it and go to next line
if (swidth > lcdwidth) { pos = i-1; break; } //line is full, go to next line
else if (i==textLength) { done = true; } else if (i==textLength) { done = true; }
} }
if (!done) if (!done)
@ -257,6 +257,18 @@ void refreshLCD() {
lcd.print("CHRG"); lcd.print("CHRG");
else else
lcd.print(systemVoltage); //sprintf(BATvstr, "%sv", BATstr); lcd.print(systemVoltage); //sprintf(BATvstr, "%sv", BATstr);
lcd.setPrintPos(0, 40);
uint16_t uptimeSeconds = millis()/1000;
if (uptimeSeconds<60)
sprintf(temp, "up:%us", uptimeSeconds);
else
sprintf(temp, "up:%um", uptimeSeconds/60);
lcd.print(temp);
lcd.setPrintPos(45, 40);
sprintf(temp, "RAM:%u", checkFreeRAM());
lcd.print(temp);
//print rssi and icon //print rssi and icon
if (rssi > -70) bmpPtr = (byte*)xbmp_rssi_3; if (rssi > -70) bmpPtr = (byte*)xbmp_rssi_3;
@ -266,23 +278,50 @@ void refreshLCD() {
lcd.drawXBMP(0, lcdheight-xbmp_rssi_height, xbmp_rssi_width, xbmp_rssi_height, bmpPtr); lcd.drawXBMP(0, lcdheight-xbmp_rssi_height, xbmp_rssi_width, xbmp_rssi_height, bmpPtr);
lcd.drawStr(xbmp_rssi_width+1, 48, RSSIstr); lcd.drawStr(xbmp_rssi_width+1, 48, RSSIstr);
} while(lcd.nextPage()); } while(lcd.nextPage());
//SPI.setClockDivider(SPI_CLOCK_DIV4);
digitalWrite(PIN_LCD_CS, HIGH); digitalWrite(PIN_LCD_CS, HIGH);
interrupts(); interrupts(); //re-enable interrupts
} }
#endif #endif
//******************************************** END LCD STUFF ******************************************************************************** //******************************************** END LCD STUFF ********************************************************************************
//******************************************** MESSAGE HISTORY ******************************************************************************
#define MSG_MAX_LEN 32 //truncate message at 32 chars since most are shorter than that anyway
#define HISTORY_LEN 10 //hold this many past messages (IMPORTANT: 10 records needs about 330 bytes of RAM so be careful about making this too large)
typedef struct {
char data[MSG_MAX_LEN];
int rssi;
} Message;
Message * messageHistory = new Message[HISTORY_LEN];
byte lastMessageIndex = HISTORY_LEN;
byte currMessageIndex = HISTORY_LEN;
byte historyLength = 0;
void saveToHistory(char * msg, int rssi)
{
byte length = strlen(msg);
byte i = 0;
if (lastMessageIndex >= HISTORY_LEN-1) lastMessageIndex = 0;
else lastMessageIndex++;
if (historyLength < HISTORY_LEN) historyLength++;
currMessageIndex = historyLength; //currMessageIndex = lastMessageIndex;
for (; i<(MSG_MAX_LEN-1) && (i < length); i++)
messageHistory[lastMessageIndex].data[i] = msg[i];
messageHistory[lastMessageIndex].data[i] = '\0'; //terminate string
messageHistory[lastMessageIndex].rssi = rssi;
}
//******************************************** END MESSAGE HISTORY **************************************************************************
//parse through any serial commands from the host (Pi) //parse through any serial commands from the host (Pi)
void handleSerialInput() { void handleSerialInput() {
inputLen = readSerialLine(input, 10, 64, 10); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10); inputLen = readSerialLine(temp, 10, 64, 10); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10);
if (inputLen > 0) if (inputLen > 0)
{ {
inputstr = String(input); inputstr = String(temp);
inputstr.toUpperCase(); inputstr.toUpperCase();
if (inputstr.equals("BEEP")) Beep(10, false); if (inputstr.equals("BEEP")) Beep(5, false);
if (inputstr.equals("BEEP2")) Beep(10, true); if (inputstr.equals("BEEP2")) Beep(10, true);
if (inputstr.equals("RAM")) { DEBUG(F("Free RAM bytes: "));DEBUGln(checkFreeRAM()); } if (inputstr.equals("RAM")) { DEBUG(F("Free RAM bytes: "));DEBUGln(checkFreeRAM()); }
@ -297,8 +336,8 @@ void handleSerialInput() {
if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any
if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0) if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0)
{ {
inputstr.getBytes(temp, 61); inputstr.getBytes((byte*)temp, 61);
if (radio.sendWithRetry(targetId, temp, inputstr.length())) if (radio.sendWithRetry(targetId, (byte*)temp, inputstr.length()))
Serial.println(F("ACK:OK")); Serial.println(F("ACK:OK"));
else else
Serial.println(F("ACK:NOK")); Serial.println(F("ACK:NOK"));
@ -325,12 +364,14 @@ void setupPowerControl(){
pinMode(PIN_LCD_CS, OUTPUT); pinMode(PIN_LCD_CS, OUTPUT);
digitalWrite(PIN_LCD_CS, HIGH); digitalWrite(PIN_LCD_CS, HIGH);
pinMode(LATCH_VAL, OUTPUT); pinMode(LATCH_VAL, OUTPUT);
pinMode(BUTTON1, INPUT_PULLUP);
pinMode(BUTTON2, INPUT_PULLUP);
pinMode(BATTERYSENSE, INPUT); pinMode(BATTERYSENSE, INPUT);
digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE! digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
} }
void handlePowerControl() { void handlePowerControl() {
int reading = digitalRead(BUTTON); byte reading = digitalRead(BUTTON);
NOW = millis(); NOW = millis();
digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE! digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
@ -530,8 +571,42 @@ void handlePowerControl() {
} }
} }
uint32_t buttonsLastChanged;
void handle2Buttons()
{
if (millis() - buttonsLastChanged < 200) return; //basic button debouncing & prevent changing level too fast
//button 1 - backlight
if (digitalRead(BUTTON1)==LOW)
{
buttonsLastChanged=millis();
Beep(3, false);
if (backlightLevel==BACKLIGHTLEVELS) backlightLevel=0;
else backlightLevel++;
LCD_BACKLIGHT(backlightLevel);
sprintf(lcdbuff, "LCDlight:%d/100", 100*backlightLevel/BACKLIGHTLEVELS);
refreshLCD();
}
//button 2 - message history
if (digitalRead(BUTTON2)==LOW)
{
buttonsLastChanged=millis();
Beep(3, false);
if (historyLength > 0) //if at least 1 data packet was received and saved to history...
{
if (currMessageIndex==0) currMessageIndex=historyLength-1; else currMessageIndex--; //this makes it cycle from the latest message towards oldest as you press BTN2
sprintf(RSSIstr, "%ddBm", messageHistory[currMessageIndex].rssi); //paint the history rssi string for the LCDRefresh
rssi = messageHistory[currMessageIndex].rssi; //save the history rssi for the LCDRefresh signal icon
sprintf(lcdbuff, "<HISTORY[%d/%d]>\n%s", currMessageIndex+1, historyLength, messageHistory[currMessageIndex].data); //fill the LCD string buffer with the history data string
refreshLCD(); //paint the screen
}
}
}
boolean BOOTOK() { boolean BOOTOK() {
return analogRead(SIG_BOOTOK) > 800; return analogRead(SIG_BOOTOK) > 800; //the BOOTOK signal is on an analog pin because a digital may not always pick it up (its less than 3.3v)
} }
void POWER(uint8_t ON_OFF) { void POWER(uint8_t ON_OFF) {
@ -607,32 +682,34 @@ void setup() {
DEBUG(F("Free RAM bytes: "));DEBUG(checkFreeRAM()); DEBUG(F("Free RAM bytes: "));DEBUG(checkFreeRAM());
#ifdef ENABLE_LCD #ifdef ENABLE_LCD
//LCD backlight pinMode(PIN_LCD_LIGHT, OUTPUT); //LCD backlight, LOW = backlight ON
pinMode(PIN_LCD_LIGHT, OUTPUT); lcd.setRot180(); //rotate screen 180 degrees
LCD_BACKLIGHT(1); lcd.setContrast(140); //120-160 seems to be usable range
lcd.setRot180(); //rotate screen 180 degrees
drawLogo(); drawLogo();
LCD_BACKLIGHT(backlightLevel);
delay(2000); delay(2000);
refreshLCD(); refreshLCD();
delay(1500); delay(1000);
#endif #endif
} }
boolean newPacketReceived; boolean newPacketReceived;
void loop() { void loop() {
handlePowerControl(); //checks any button presses and takes action handlePowerControl(); //checks any button presses and takes action
handle2Buttons(); //checks the general purpose buttons next to the LCD (R2+)
handleSerialInput(); //checks for any serial input from the Pi computer handleSerialInput(); //checks for any serial input from the Pi computer
//process any received radio packets //process any received radio packets
if (radio.receiveDone()) if (radio.receiveDone())
{ {
rssi = radio.RSSI; rssi = radio.RSSI;
if (radio.DATALEN > 0) if (radio.DATALEN > 0) //data packets have a payload
{ {
sprintf(lcdbuff, "[%d] %s", radio.SENDERID, radio.DATA); sprintf(lcdbuff, "[%d] %s", radio.SENDERID, radio.DATA);
sprintf(RSSIstr, "%ddBm", rssi); sprintf(RSSIstr, "%ddBm", rssi);
Serial.print(lcdbuff); Serial.print(lcdbuff); //this passes data to MightyHat / RaspberryPi
Serial.print(F(" [RSSI:"));Serial.print(rssi);Serial.print(']'); Serial.print(F(" [RSSI:"));Serial.print(rssi);Serial.print(']');
saveToHistory(lcdbuff, rssi);
} }
//check if the packet is a wireless programming request //check if the packet is a wireless programming request
@ -664,6 +741,6 @@ void loop() {
newPacketReceived = false; newPacketReceived = false;
refreshLCD(); refreshLCD();
} }
LCD_BACKLIGHT(batteryLow); LCD_BACKLIGHT(batteryLow ? 0 : backlightLevel);
#endif #endif
} }