diff --git a/M5Stack-SAM/APPS.ino b/M5Stack-SAM/APPS.ino index c588049..e01b49b 100644 --- a/M5Stack-SAM/APPS.ino +++ b/M5Stack-SAM/APPS.ino @@ -4,7 +4,7 @@ void appQRPrint(){ while(M5.BtnB.wasPressed()){ M5.update(); } - QRPrint("www.google.com"); + QRPrint("TomSuch|Prague CZ|www.m5stack.com|tomsuch@tomsuch.net"); while(!M5.BtnB.wasPressed()){ M5.update(); } @@ -12,8 +12,6 @@ void appQRPrint(){ menuUpdate(menuidx, menulock); } - - void appBLEBaecon(){ byte beaconIdx = 0; menuDrawMenu(F("BLE BEACON SIMULATOR"),F(""),F("ESC"),F(""),sys_menucolor,sys_windowcolor,sys_menutextcolor); diff --git a/M5Stack-SAM/M5Stack-SAM.ino b/M5Stack-SAM/M5Stack-SAM.ino index 7e30f21..12d9b23 100644 --- a/M5Stack-SAM/M5Stack-SAM.ino +++ b/M5Stack-SAM/M5Stack-SAM.ino @@ -1,13 +1,17 @@ #include +#include + #include "EEPROM.h" #include "utility/DHT12.h" -#include #include "SimpleBeacon.h" #include "qrcode.h" +#include "SerialCommand.h" SimpleBeacon ble; DHT12 dht12; +SerialCommand sCmd; + #define TFT_GREY 0x5AEB #define TFT_BROWN 0x38E0 @@ -48,11 +52,20 @@ void setup(void) { sys_windowcolor = TFT_GREY; menuUpdate(menuidx, menulock); - - + + sCmd.addCommand("eddystoneurl", rcmdEddystoneURL); + sCmd.addCommand("eddystonetlm", rcmdEddystoneTLM); + sCmd.addCommand("ibeacon", rcmdIBeacon); + sCmd.addCommand("sleep", rcmdSleep); + sCmd.addCommand("bright", rcmdBright); + sCmd.addCommand("clr", rcmdClr); + sCmd.addCommand("qrc", rcmdQRC); + sCmd.setDefaultHandler(rcmdDef); + } void loop() { + sCmd.readSerial(); if(M5.BtnA.wasPressed()) { if(menuidx>menuidxmin)menuidx--; menuUpdate(menuidx, menulock); diff --git a/M5Stack-SAM/SYSTEM.ino b/M5Stack-SAM/SYSTEM.ino index 4998a79..6a76967 100644 --- a/M5Stack-SAM/SYSTEM.ino +++ b/M5Stack-SAM/SYSTEM.ino @@ -1,13 +1,152 @@ +void rcmdQRC(){ + int aNumber; + char *arg; + arg = sCmd.next(); + if (arg != NULL) { + QRPrint(arg); + } +} + +void rcmdSleep(){ + M5.setWakeupButton(BUTTON_B_PIN); + M5.powerOFF(); +} + +void rcmdBright(){ + int aNumber; + char *arg; + unsigned int tmpval; + + arg = sCmd.next(); + if (arg != NULL) { + tmpval = atoi(arg); + if(tmpval >= 0 and tmpval <= 255){ + EEPROM.write(0,tmpval); + EEPROM.commit(); + M5.lcd.setBrightness(byte(EEPROM.read(0))); + } + } +} + +void rcmdIBeacon(){ + int aNumber; + char *arg; + + unsigned int tmpmajor; + unsigned int tmpminor; + byte tmppwr; + + arg = sCmd.next(); + if (arg != NULL) { + tmpmajor = atoi(arg); + if(tmpmajor >= 0 and tmpmajor <= 65535){ + arg = sCmd.next(); + if (arg != NULL) { + tmpminor = atoi(arg); + if(tmpminor >= 0 and tmpminor <= 65535){ + arg = sCmd.next(); + if (arg != NULL) { + tmppwr = atoi(arg); + if(tmppwr >= 0 and tmppwr <= 255){ + ble.iBeacon(tmpmajor,tmpminor,tmppwr); + delay(100); + ble.end(); + Serial.println("OK"); + } + } + } + } + } + } +} + +void rcmdEddystoneURL(){ + int aNumber; + char *arg; + + unsigned int tmppref; + unsigned int tmppwr; + + arg = sCmd.next(); + if (arg != NULL) { + tmppref = atoi(arg); + if(tmppref >= 0 and tmppref <= 3){ + arg = sCmd.next(); + if (arg != NULL) { + tmppwr = atoi(arg); + if(tmppwr >= 0 and tmppwr <= 255){ + arg = sCmd.next(); + if (arg != NULL) { + ble.EddystoneURIPlain(tmppref,arg,tmppwr); + delay(100); + ble.end(); + Serial.println("OK"); + } + } + } + } + } +} + +void rcmdEddystoneTLM(){ + int aNumber; + char *arg; + + unsigned int tmpvolt; + unsigned int tmptemp; + unsigned long tmpcount; + unsigned long tmptime; + + arg = sCmd.next(); + if (arg != NULL) { + tmpvolt = atoi(arg); + if(tmpvolt >= 0 and tmpvolt <= 65535){ + arg = sCmd.next(); + if (arg != NULL) { + tmptemp = atoi(arg); + if(tmptemp >= 0 and tmptemp <= 65535){ + arg = sCmd.next(); + if (arg != NULL) { + tmpcount = atol(arg); + if(tmpcount >= 0 and tmpcount <= 4294967295){ + arg = sCmd.next(); + if (arg != NULL) { + tmptime = atol(arg); + if(tmptime >= 0 and tmptime <= 4294967295){ + ble.EddystoneTLM(tmpvolt,tmptemp,tmpcount,tmptime); + delay(100); + ble.end(); + Serial.println("OK"); + } + } + } + } + } + } + } + } +} + + +void rcmdClr() { + menuidx = 0; + menulock = 0; + M5.Lcd.fillScreen(TFT_BLACK); + menuUpdate(menuidx, menulock); +} + +void rcmdDef(const char *command) { + Serial.println(F("ERROR")); +} + void QRPrint(String inStr) { M5.Lcd.setTextColor(TFT_BLACK, TFT_WHITE); M5.Lcd.fillScreen(TFT_WHITE); - uint32_t dt = millis(); QRCode qrcode; uint8_t version = 6; uint8_t qrcodeData[qrcode_getBufferSize(version)]; qrcode_initText(&qrcode, qrcodeData, version, 0, inStr.c_str()); - dt = millis() - dt; uint8_t thickness = 220 / qrcode.size; uint16_t lineLength = qrcode.size * thickness; diff --git a/M5Stack-SAM/SerialCommand.cpp b/M5Stack-SAM/SerialCommand.cpp new file mode 100644 index 0000000..bbea5ba --- /dev/null +++ b/M5Stack-SAM/SerialCommand.cpp @@ -0,0 +1,144 @@ +/** + * SerialCommand - A Wiring/Arduino library to tokenize and parse commands + * received over a serial port. + * + * Copyright (C) 2012 Stefan Rado + * Copyright (C) 2011 Steven Cogswell + * http://husks.wordpress.com + * + * Version 20120522 + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library. If not, see . + */ +#include "SerialCommand.h" + +/** + * Constructor makes sure some things are set. + */ +SerialCommand::SerialCommand() + : commandList(NULL), + commandCount(0), + defaultHandler(NULL), + term('\n'), // default terminator for commands, newline character + last(NULL) +{ + strcpy(delim, " "); // strtok_r needs a null-terminated string + clearBuffer(); +} + +/** + * Adds a "command" and a handler function to the list of available commands. + * This is used for matching a found token in the buffer, and gives the pointer + * to the handler function to deal with it. + */ +void SerialCommand::addCommand(const char *command, void (*function)()) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Adding command ("); + Serial.print(commandCount); + Serial.print("): "); + Serial.println(command); + #endif + + commandList = (SerialCommandCallback *) realloc(commandList, (commandCount + 1) * sizeof(SerialCommandCallback)); + strncpy(commandList[commandCount].command, command, SERIALCOMMAND_MAXCOMMANDLENGTH); + commandList[commandCount].function = function; + commandCount++; +} + +/** + * This sets up a handler to be called in the event that the receveived command string + * isn't in the list of commands. + */ +void SerialCommand::setDefaultHandler(void (*function)(const char *)) { + defaultHandler = function; +} + + +/** + * This checks the Serial stream for characters, and assembles them into a buffer. + * When the terminator character (default '\n') is seen, it starts parsing the + * buffer for a prefix command, and calls handlers setup by addCommand() member + */ +void SerialCommand::readSerial() { + while (Serial.available() > 0) { + char inChar = Serial.read(); // Read single available character, there may be more waiting + #ifdef SERIALCOMMAND_DEBUG + Serial.print(inChar); // Echo back to serial stream + #endif + + if (inChar == term) { // Check for the terminator (default '\r') meaning end of command + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Received: "); + Serial.println(buffer); + #endif + + char *command = strtok_r(buffer, delim, &last); // Search for command at start of buffer + if (command != NULL) { + boolean matched = false; + for (int i = 0; i < commandCount; i++) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Comparing ["); + Serial.print(command); + Serial.print("] to ["); + Serial.print(commandList[i].command); + Serial.println("]"); + #endif + + // Compare the found command against the list of known commands for a match + if (strncmp(command, commandList[i].command, SERIALCOMMAND_MAXCOMMANDLENGTH) == 0) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Matched Command: "); + Serial.println(command); + #endif + + // Execute the stored handler function for the command + (*commandList[i].function)(); + matched = true; + break; + } + } + if (!matched && (defaultHandler != NULL)) { + (*defaultHandler)(command); + } + } + clearBuffer(); + } + else if (isprint(inChar)) { // Only printable characters into the buffer + if (bufPos < SERIALCOMMAND_BUFFER) { + buffer[bufPos++] = inChar; // Put character into buffer + buffer[bufPos] = '\0'; // Null terminate + } else { + #ifdef SERIALCOMMAND_DEBUG + Serial.println("Line buffer is full - increase SERIALCOMMAND_BUFFER"); + #endif + } + } + } +} + +/* + * Clear the input buffer. + */ +void SerialCommand::clearBuffer() { + buffer[0] = '\0'; + bufPos = 0; +} + +/** + * Retrieve the next token ("word" or "argument") from the command buffer. + * Returns NULL if no more tokens exist. + */ +char *SerialCommand::next() { + return strtok_r(NULL, delim, &last); +} diff --git a/M5Stack-SAM/SerialCommand.h b/M5Stack-SAM/SerialCommand.h new file mode 100644 index 0000000..e00dd29 --- /dev/null +++ b/M5Stack-SAM/SerialCommand.h @@ -0,0 +1,75 @@ +/** + * SerialCommand - A Wiring/Arduino library to tokenize and parse commands + * received over a serial port. + * + * Copyright (C) 2012 Stefan Rado + * Copyright (C) 2011 Steven Cogswell + * http://husks.wordpress.com + * + * Version 20120522 + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library. If not, see . + */ +#ifndef SerialCommand_h +#define SerialCommand_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif +#include + +// Size of the input buffer in bytes (maximum length of one command plus arguments) +#define SERIALCOMMAND_BUFFER 32 +// Maximum length of a command excluding the terminating null +#define SERIALCOMMAND_MAXCOMMANDLENGTH 8 + +// Uncomment the next line to run the library in debug mode (verbose messages) +//#define SERIALCOMMAND_DEBUG + + +class SerialCommand { + public: + SerialCommand(); // Constructor + void addCommand(const char *command, void(*function)()); // Add a command to the processing dictionary. + void setDefaultHandler(void (*function)(const char *)); // A handler to call when no valid command received. + + void readSerial(); // Main entry point. + void clearBuffer(); // Clears the input buffer. + char *next(); // Returns pointer to next token found in command buffer (for getting arguments to commands). + + private: + // Command/handler dictionary + struct SerialCommandCallback { + char command[SERIALCOMMAND_MAXCOMMANDLENGTH + 1]; + void (*function)(); + }; // Data structure to hold Command/Handler function key-value pairs + SerialCommandCallback *commandList; // Actual definition for command/handler array + byte commandCount; + + // Pointer to the default handler function + void (*defaultHandler)(const char *); + + char delim[2]; // null-terminated list of character to be used as delimeters for tokenizing (default " ") + char term; // Character that signals end of command (default '\n') + + char buffer[SERIALCOMMAND_BUFFER + 1]; // Buffer of stored characters while waiting for terminator character + byte bufPos; // Current position in the buffer + char *last; // State variable used by strtok_r during processing +}; + +#endif //SerialCommand_h