360 lines
11 KiB
C++
360 lines
11 KiB
C++
//<App !Start!>
|
|
// FILE: [_controller.ino]
|
|
// Created by GUIslice Builder version: [0.15.b004]
|
|
//
|
|
// GUIslice Builder Generated File
|
|
//
|
|
// For the latest guides, updates and support view:
|
|
// https://github.com/ImpulseAdventure/GUIslice
|
|
//
|
|
//<App !End!>
|
|
|
|
// ------------------------------------------------
|
|
// Headers to include
|
|
// ------------------------------------------------
|
|
//<Includes !Start!>
|
|
// Varous system includes
|
|
#include <Arduino.h>
|
|
|
|
// Various library includes
|
|
#include <Adafruit_NeoPixel.h>
|
|
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_ILI9341.h>
|
|
#include <BBQ10Keyboard.h>
|
|
#include <CircularBuffer.h>
|
|
|
|
// Various local includes
|
|
#include "_controller_GSLC.h"
|
|
|
|
//<Includes !End!>
|
|
|
|
// ------------------------------------------------
|
|
// Program Globals
|
|
// ------------------------------------------------
|
|
|
|
// Battery level measurement
|
|
#define VBATPIN A6
|
|
float measuredVBat;
|
|
int batteryPercent;
|
|
|
|
// TFT Setup
|
|
#define TFT_CS 9
|
|
#define TFT_DC 10
|
|
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
|
#define CHARS_HORIZONTAL 29
|
|
#define CHARS_ROWS 11
|
|
#define CHARS_TOTAL CHARS_HORIZONTAL * CHARS_ROWS
|
|
CircularBuffer<char,CHARS_TOTAL> textBuffer;
|
|
|
|
// Keyboard
|
|
BBQ10Keyboard keyboard;
|
|
#define KBD_BTN_1 0x06
|
|
#define KBD_BTN_2 0x11
|
|
#define KBD_BTN_3 0x07
|
|
#define KBD_BTN_4 0x12
|
|
#define KBD_SW_UP 0x01
|
|
#define KBD_SW_DN 0x02
|
|
#define KBD_SW_LF 0x03
|
|
#define KBD_SW_RT 0x04
|
|
#define KBD_SW_OK 0x05
|
|
CircularBuffer<int16_t,8> uiKeyBuffer;
|
|
|
|
// Upstream keyboard definitions that will be really important later
|
|
#define _REG_CFG 2
|
|
#define CFG_OVERFLOW_INT (1 << 1)
|
|
#define CFG_KEY_INT (1 << 4)
|
|
#define CFG_USE_MODS (1 << 7) // Should Alt, Sym and Shifts modify the keys reported
|
|
#define CFG_REPORT_MODS (1 << 6) // Should Alt, Sym and Shifts be reported as well
|
|
|
|
// NeoPixels
|
|
#define PIXELS_NUM_BOARD 1
|
|
#define PIXELS_NUM_WING 1
|
|
#define PIXELS_WING_PIN 11
|
|
Adafruit_NeoPixel pixels_board(PIXELS_NUM_BOARD, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
|
Adafruit_NeoPixel pixels_wing(PIXELS_NUM_WING, PIXELS_WING_PIN, NEO_GRB + NEO_KHZ800);
|
|
|
|
// GUI state globals
|
|
bool textChanged = false;
|
|
|
|
// Various loop handlers
|
|
void handlerKeyboard();
|
|
void handlerBatteryLevel();
|
|
void processRingBuffer();
|
|
|
|
// Save some element references for direct access
|
|
//<Save_References !Start!>
|
|
gslc_tsElemRef* m_pElemBatteryLevel= NULL;
|
|
gslc_tsElemRef* m_pElemRd1152 = NULL;
|
|
gslc_tsElemRef* m_pElemRd96 = NULL;
|
|
gslc_tsElemRef* m_pElemRdUART0 = NULL;
|
|
gslc_tsElemRef* m_pElemRdUART5 = NULL;
|
|
gslc_tsElemRef* m_pElemSDInfo = NULL;
|
|
gslc_tsElemRef* m_pElemStatusText = NULL;
|
|
gslc_tsElemRef* m_pElemText = NULL;
|
|
//<Save_References !End!>
|
|
|
|
// Keyboard map related
|
|
#define MAX_INPUT_MAP 5
|
|
gslc_tsInputMap m_asInputMap[MAX_INPUT_MAP];
|
|
|
|
// Define debug message function
|
|
static int16_t DebugOut(char ch) { if (ch == (char)'\n') Serial.println(""); else Serial.write(ch); return 0; }
|
|
|
|
// ------------------------------------------------
|
|
// Callback Methods
|
|
// ------------------------------------------------
|
|
// Common Button callback
|
|
bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY)
|
|
{
|
|
// Typecast the parameters to match the GUI and element types
|
|
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
|
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
|
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
|
|
|
if ( eTouch == GSLC_TOUCH_UP_IN ) {
|
|
// From the element's ID we can determine which button was pressed.
|
|
switch (pElem->nId) {
|
|
//<Button Enums !Start!>
|
|
case E_ELEM_BTN_SD_FMT:
|
|
break;
|
|
//<Button Enums !End!>
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//<Checkbox Callback !Start!>
|
|
//<Checkbox Callback !End!>
|
|
//<Keypad Callback !Start!>
|
|
//<Keypad Callback !End!>
|
|
//<Spinner Callback !Start!>
|
|
//<Spinner Callback !End!>
|
|
//<Listbox Callback !Start!>
|
|
//<Listbox Callback !End!>
|
|
//<Draw Callback !Start!>
|
|
//<Draw Callback !End!>
|
|
//<Slider Enums !Start!>
|
|
//<Slider Enums !End!>
|
|
//<Tick Callback !Start!>
|
|
//<Tick Callback !End!>
|
|
|
|
// Keyboard Input polling callback function
|
|
bool CbKbdPoll(void* pvGui, int16_t* pnPinInd, int16_t* pnPinVal) {
|
|
// Check for new keyboard events just in case
|
|
handlerKeyboard();
|
|
|
|
// If the key buffer is empty no events to process
|
|
if (uiKeyBuffer.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Process a key that's on the key buffer for the UI event(s)
|
|
*pnPinInd = uiKeyBuffer.pop();
|
|
*pnPinVal = 1;
|
|
|
|
return true;
|
|
}
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
|
|
// If GUI Slice debug of drivers is turned on, wait for serial so we get proper debug output
|
|
#if defined(DBG_LOG) || defined(DBG_TOUCH) || defined(DBG_FRAME_RATE) || defined(DBG_DRAW_IMM) || defined(DBG_DRIVER)
|
|
while (!Serial) {
|
|
;
|
|
}
|
|
#endif
|
|
|
|
// GUI Slice debugging
|
|
gslc_InitDebug(&DebugOut);
|
|
|
|
// Setup red LED to indicate device is on (in case we disable NeoPixel battery level later)
|
|
pinMode(3, OUTPUT);
|
|
digitalWrite(3, HIGH);
|
|
|
|
// Setup NeoPixels
|
|
pixels_board.begin();
|
|
pixels_wing.begin();
|
|
pixels_board.clear();
|
|
pixels_wing.clear();
|
|
pixels_board.setBrightness(10);
|
|
pixels_wing.setBrightness(5);
|
|
|
|
// Setup neopixels to indicate we are initializing gui slice
|
|
// This can serve as an indication something has gone wrong like the sd card is missing
|
|
pixels_wing.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
|
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
|
pixels_wing.show();
|
|
pixels_board.show();
|
|
|
|
// Setup BBQ10Keyboard
|
|
Wire.begin();
|
|
keyboard.begin();
|
|
keyboard.writeRegister(_REG_CFG, CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS | CFG_REPORT_MODS);
|
|
keyboard.setBacklight(0.5f);
|
|
|
|
// Init GUI Slicle
|
|
InitGUIslice_gen();
|
|
|
|
// Set the pin poll callback function
|
|
gslc_SetPinPollFunc(&m_gui, CbKbdPoll);
|
|
|
|
// Create the GUI input mapping (pin event to GUI action)
|
|
gslc_InitInputMap(&m_gui, m_asInputMap, MAX_INPUT_MAP);
|
|
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_UP, GSLC_ACTION_FOCUS_NEXT, 0);
|
|
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_DN, GSLC_ACTION_FOCUS_PREV, 0);
|
|
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_LF, GSLC_ACTION_FOCUS_NEXT, 0);
|
|
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_RT, GSLC_ACTION_FOCUS_PREV, 0);
|
|
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_OK, GSLC_ACTION_SELECT, 0);
|
|
|
|
// Set neopixels to standard start state
|
|
pixels_wing.clear();
|
|
pixels_wing.show();
|
|
|
|
pixels_board.setPixelColor(0, pixels_board.Color(0, 0, 255));
|
|
pixels_board.show();
|
|
}
|
|
|
|
// -----------------------------------
|
|
// Main event loop
|
|
// -----------------------------------
|
|
void loop() {
|
|
// Reset text changed state (processing methods will update if needed)
|
|
textChanged = false;
|
|
|
|
// Handle keyboard events
|
|
handlerKeyboard();
|
|
|
|
// Update battery level as appropriate
|
|
handlerBatteryLevel();
|
|
|
|
// Update UI
|
|
if (textChanged) {
|
|
processRingBuffer();
|
|
}
|
|
|
|
gslc_Update(&m_gui);
|
|
}
|
|
|
|
// Move text from buffer -> text box on screen
|
|
void processRingBuffer() {
|
|
// Add keycodes to text box
|
|
char* textForDisplay = (char*) calloc(textBuffer.size(), sizeof(char));
|
|
for (int i=0; i<textBuffer.size(); i++) {
|
|
textForDisplay[i] = textBuffer[i];
|
|
}
|
|
gslc_ElemXTextboxAdd(&m_gui, m_pElemText, textForDisplay);
|
|
}
|
|
|
|
// Keyboard handler
|
|
void handlerKeyboard() {
|
|
// Don't do anything if there are no key presses to process
|
|
if (keyboard.keyCount() == 0) {
|
|
return;
|
|
}
|
|
|
|
// Check if keys were pressed and drain queue of pressed keys
|
|
while (keyboard.keyCount() > 0) {
|
|
// Get keyboard event
|
|
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
|
|
|
|
// Process key press events
|
|
if (key.state == BBQ10Keyboard::StatePress) {
|
|
// Move right through screens
|
|
if (key.key == KBD_BTN_4) {
|
|
// Main Screen Flip
|
|
if (gslc_GetPageCur(&m_gui) == E_PG_MAIN) {
|
|
gslc_ElemSetTxtStr(&m_gui, m_pElemStatusText, "Raspberry Pi");
|
|
gslc_SetPageCur(&m_gui, E_CONF_RPI);
|
|
}
|
|
// Raspberry Pi Screen Flip
|
|
else if (gslc_GetPageCur(&m_gui) == E_CONF_RPI) {
|
|
gslc_ElemSetTxtStr(&m_gui, m_pElemStatusText, "SD Card");
|
|
gslc_SetPageCur(&m_gui, E_SD_CARD);
|
|
}
|
|
// SD Card Info screen Flip
|
|
else if (gslc_GetPageCur(&m_gui) == E_SD_CARD) {
|
|
gslc_ElemSetTxtStr(&m_gui, m_pElemStatusText, "Serial Console");
|
|
gslc_SetPageCur(&m_gui, E_PG_MAIN);
|
|
}
|
|
}
|
|
// Add keys to the key buffer that are mapped to UI functions (only for config screens)
|
|
else if (key.key == KBD_SW_UP
|
|
|| key.key == KBD_SW_DN
|
|
|| key.key == KBD_SW_LF
|
|
|| key.key == KBD_SW_RT
|
|
|| key.key == KBD_SW_OK) {
|
|
uiKeyBuffer.push(key.key);
|
|
}
|
|
// Process keys 'normally'
|
|
else {
|
|
char output[28];
|
|
snprintf(output, 28, "key: '%c' (dec %d, hex %02x)", key.key, key.key, key.key);
|
|
textChanged = true;
|
|
for (int i=0; i<sizeof(output); i++) {
|
|
char toPush = output[i];
|
|
if (toPush != '\0') {
|
|
textBuffer.push(toPush);
|
|
}
|
|
else if (toPush == '\0') {
|
|
textBuffer.push('\n');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pick color for signaling a key was pressed (short or long press)
|
|
uint32_t keyboard_pixel_color = pixels_wing.Color(0, 0, 255);
|
|
if (key.state == BBQ10Keyboard::StateLongPress) {
|
|
keyboard_pixel_color = pixels_wing.Color(0, 255, 255);
|
|
}
|
|
|
|
// Display indicator accordingly
|
|
if (key.state == BBQ10Keyboard::StatePress || key.state == BBQ10Keyboard::StateLongPress) {
|
|
pixels_wing.setPixelColor(0, keyboard_pixel_color);
|
|
pixels_wing.show();
|
|
}
|
|
else {
|
|
pixels_wing.clear();
|
|
pixels_wing.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Measure battery level and change NeoPixel accordingly
|
|
void handlerBatteryLevel() {
|
|
measuredVBat = analogRead(VBATPIN);
|
|
measuredVBat *= 2; // we divided by 2, so multiply back
|
|
measuredVBat *= 3.3; // Multiply by 3.3V, our reference voltage
|
|
measuredVBat /= 1024; // convert to voltage
|
|
batteryPercent = (measuredVBat / 3.3) * 100;
|
|
|
|
gslc_tsColor colorForHeaderElements;
|
|
if (batteryPercent >= 75) {
|
|
pixels_board.setPixelColor(0, pixels_board.Color(0, 255, 0));
|
|
colorForHeaderElements = GSLC_COL_GREEN;
|
|
}
|
|
else if (batteryPercent >= 50) {
|
|
colorForHeaderElements = GSLC_COL_YELLOW;
|
|
pixels_board.setPixelColor(0, pixels_board.Color(255, 255, 0));
|
|
}
|
|
else if (batteryPercent >= 25) {
|
|
colorForHeaderElements = GSLC_COL_ORANGE;
|
|
pixels_board.setPixelColor(0, pixels_board.Color(255, 128, 0));
|
|
}
|
|
else {
|
|
colorForHeaderElements = GSLC_COL_RED;
|
|
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
|
}
|
|
|
|
gslc_ElemXProgressSetVal(&m_gui, m_pElemBatteryLevel, batteryPercent);
|
|
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(&m_gui,m_pElemBatteryLevel,GSLC_TYPEX_PROGRESS,__LINE__);
|
|
pGauge->colGauge = colorForHeaderElements;
|
|
gslc_ElemSetTxtCol(&m_gui, m_pElemStatusText, colorForHeaderElements);
|
|
|
|
// Update GUI and NeoPixel with battery status information
|
|
pixels_board.show();
|
|
}
|