Update uno-stats-monitor/monitor_uno.ino

added an 8 x 8 LED matrix and IR receiver
LED shows CPU load as a bar graph
IR receiver reports key press events back through serial connection
general code cleanup
This commit is contained in:
RLF
2023-12-28 03:24:39 -05:00
parent 0852deae18
commit f19e5d17b0

View File

@@ -1,54 +1,136 @@
/* /*
* UNO Monitor Receiver (4-bit LCD Version) * UNO Monitor Receiver (4-bit LCD Version)
* kidacro@archamedis.net * Kidacro <kidacro@archamedis.net>
* *
* Waits for input over serial connection and displays on LCD * Waits for input over serial connection and displays on LCD & LED
* Receives IR events and reports them over serial connection to a daemon
* *
* Input Schema: * Input Schema:
* Start char is: '#' * Start char is: '#'
* End char is: '@' * End char is: '@'
* 2nd char denotes which line number to use * 2nd char denotes which line number/mode to use
* *
* Example: * Example:
* Line 1: #1Archamedis Status@ * Line 1: #1Archamedis Status@
* Line 2: #299% free / etc.@ * Line 2: #299% free / etc.@
* * LAVG 3: #324@
*
* Output Schema:
* Multimedia Controls use single characters to denote which button was pressed
* P power
* M mute
* m mode
* p pause/play
* b back
* f forward
* e eq
* - vol down
* + vol up
* r return
* u usb scan
* 0 number 0
* 1 number 1
* 2 number 2
* 3 number 3
* 4 number 4
* 5 number 5
* 6 number 6
* 7 number 7
* 8 number 8
* 9 number 9
* R repeat
* Z other button pressed
*/ */
// include the library code:
#include <LiquidCrystal.h> #include <LiquidCrystal.h>
#include <LedControl.h>
#include <IRremote.h>
// LCD Pinout: /* LCD Pinout:
// LCD RS pin to digital pin 12 * LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11 * LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5 * LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
// LCD R/W pin to ground * LCD R/W pin to ground
// LCD VSS pin to ground * LCD VSS pin to ground
// LCD VCC pin to 5V * LCD VCC pin to 5V
// 10K resistor: * 10K resistor:
// ends to +5V and ground * ends to +5V and ground
// wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
*/
/* LED Pinout:
* LED DataIn(DIN) to digital pin 10
* LED LOAD(CS) to digital pin 9
* LED CLK to digital pin 8
* LED VSS pin to 5V
* LED GND to ground
*/
/* IR Pinout
* IR Signal to digital pin 13
* IR VSS pin to 5V
* IR GND to ground
*/
// Variable Init
// LCD vars // LCD vars
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int LCDRS = 12, LCDEN = 11, LCDD4 = 5, LCDD5 = 4, LCDD6 = 3, LCDD7 = 2; const int LCDRS = 12, LCDEN = 11, LCDD4 = 5, LCDD5 = 4, LCDD6 = 3, LCDD7 = 2;
int LCDLength = 16; int LCDLength = 16;
LiquidCrystal LCD(LCDRS, LCDEN, LCDD4, LCDD5, LCDD6, LCDD7); LiquidCrystal LCD(LCDRS, LCDEN, LCDD4, LCDD5, LCDD6, LCDD7);
// LED vars
const int LEDIN = 10, LEDCS = 9, LEDCLK = 8;
LedControl LEDlc=LedControl(LEDIN,LEDCLK,LEDCS,1);
unsigned long LEDdelaytime1=5;
unsigned long LEDdelaytime2=5;
// IR vars
const int IRSIG = 13;
IRrecv Irrecv(IRSIG);
decode_results IRresults;
// Serial vars // Serial vars
const byte numChars = 32; const byte SERnumChars = 32;
char receivedChars[numChars]; // an array to store the received data char SERrecvChars[SERnumChars];
boolean newData = false; boolean SERnewData = false;
// Debugging (serial console must be connected) // Debugging
bool DEBUG = 1; boolean DEBUG = false;
void LcdL1(boolean wipe = false) { void LEDSetup(void)
{
/*
The MAX72XX is in power-saving mode on startup,
we have to do a wakeup call
*/
LEDlc.shutdown(0,false);
/* Set the brightness to medium values */
LEDlc.setIntensity(0,8);
/* and clear the display */
LEDlc.clearDisplay(0);
}
void LcdSetup(void)
{
// set up the LCD's number of columns and rows:
LCD.begin(LCDLength, 2);
// clear
LCD.clear();
}
void IRSetup(void)
{
// Start the receiver
Irrecv.enableIRIn();
}
void LcdL1(boolean wipe = false)
{
delay(10); delay(10);
LCD.setCursor(0, 0); // Define the cursor position as the 1st position of the 1st line LCD.setCursor(0, 0); // Define the cursor position as the 1st position of the 1st line
@@ -60,7 +142,8 @@ void LcdL1(boolean wipe = false) {
delay(10); delay(10);
} }
void LcdL2(boolean wipe = false) { void LcdL2(boolean wipe = false)
{
delay(10); delay(10);
LCD.setCursor(0, 1); // Define the cursor position as the 1st position of the 2nd line LCD.setCursor(0, 1); // Define the cursor position as the 1st position of the 2nd line
@@ -72,17 +155,8 @@ void LcdL2(boolean wipe = false) {
delay(10); delay(10);
} }
void LcdCls(void) { void LcdIntro(void)
delay(10); {
LCD.clear(); // The screen is empty
LcdL1(); // the cursor position is zeroed
delay(10);
}
void LcdSetup(void) {
// set up the LCD's number of columns and rows:
LCD.begin(LCDLength, 2);
// Print a "waiting" message to the LCD. // Print a "waiting" message to the LCD.
LcdL1(); LcdL1();
LCD.print("Starting Up..."); LCD.print("Starting Up...");
@@ -90,14 +164,25 @@ void LcdSetup(void) {
LCD.print("Waiting for data"); LCD.print("Waiting for data");
} }
/* returns starting position of text void LcdCls(void)
void LcdCenter(int mylen) { {
delay(10);
LCD.clear(); // The screen is empty
LcdL1(); // the cursor position is zeroed
delay(10);
}
/*
TODO: returns starting position of text or 0 for 1st position
void LcdCenter(int mylen)
{
int mypos = 0; int mypos = 0;
return mypos; return mypos;
}*/ }*/
void LcdWrite(String mymessage) { void LcdWrite(String mymessage)
{
int i = 0; int i = 0;
unsigned int mylen = mymessage.length(); unsigned int mylen = mymessage.length();
@@ -127,102 +212,192 @@ void LcdWrite(String mymessage) {
} }
} }
void LcdWriteExample() { void LedIntro() {
LcdCls(); for(int row=0;row<8;row++) {
for(int col=0;col<8;col++) {
LcdL1(); delay(LEDdelaytime2);
LcdWrite("Archamedis Stats"); LEDlc.setLed(0,row,col,true);
delay(LEDdelaytime2);
delay(20); for(int i=0;i<col;i++) {
LEDlc.setLed(0,row,col,false);
LcdL1(true); delay(LEDdelaytime2);
LcdWrite("4.3ghz 89% 68C"); LEDlc.setLed(0,row,col,true);
delay(LEDdelaytime2);
delay(20); }
LcdL2();
LcdWrite("Ryzen 9 5950x");
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '#';
char endMarker = '@';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if(recvInProgress == true) {
if(rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if(rc == startMarker) {
recvInProgress = true;
}
} }
}
LEDlc.clearDisplay(0);
} }
void showNewData() { // FIXME: this is armchair math
if(newData == true) { // this needs to be dynamic and based on available rows
void LedShowLoad(const char *load)
{
int myload = atoi(load);
int segments = 0;
if(DEBUG) {
Serial.print("My input load: ");
Serial.println(load);
Serial.print("My calculated load: ");
Serial.println(myload);
}
LEDlc.clearDisplay(0);
if(myload <= 10) segments = 1;
else if(myload <= 20 && myload > 10) segments = 2;
else if(myload <= 30 && myload > 20) segments = 3;
else if(myload <= 50 && myload > 30) segments = 4;
else if(myload <= 60 && myload > 50) segments = 5;
else if(myload <= 70 && myload > 60) segments = 6;
else if(myload <= 85 && myload > 70) segments = 7;
else if(myload > 84) segments = 8;
// segments as rows
for(int row=0;row<8;row++) {
for(int col=0;col<segments;col++) {
delay(LEDdelaytime2);
LEDlc.setLed(0,row,col,true);
delay(LEDdelaytime2);
for(int i=0;i<col;i++) {
LEDlc.setLed(0,row,col,false);
delay(LEDdelaytime2);
LEDlc.setLed(0,row,col,true);
delay(LEDdelaytime2);
}
}
}
}
// IR translator
void IRtranslate()
{
switch(IRresults.value) {
case 0xFFA25D: Serial.println("P"); break; // power
case 0xFFE21D: Serial.println("M"); break; // mute
case 0xFF629D: Serial.println("m"); break; // mode
case 0xFF22DD: Serial.println("p"); break; // pause/play
case 0xFF02FD: Serial.println("b"); break; // back
case 0xFFC23D: Serial.println("f"); break; // forward
case 0xFFE01F: Serial.println("e"); break; // eq
case 0xFFA857: Serial.println("-"); break; // vol down
case 0xFF906F: Serial.println("+"); break; // vol up
case 0xFF9867: Serial.println("r"); break; // return
case 0xFFB04F: Serial.println("u"); break; // usb scan
case 0xFF6897: Serial.println("0"); break; // number 0
case 0xFF30CF: Serial.println("1"); break; // number 1
case 0xFF18E7: Serial.println("2"); break; // number 2
case 0xFF7A85: Serial.println("3"); break; // number 3
case 0xFF10EF: Serial.println("4"); break; // number 4
case 0xFF38C7: Serial.println("5"); break; // number 5
case 0xFF5AA5: Serial.println("6"); break; // number 6
case 0xFF42BD: Serial.println("7"); break; // number 7
case 0xFF4AB5: Serial.println("8"); break; // number 8
case 0xFF52AD: Serial.println("9"); break; // number 9
case 0xFFFFFFFF: Serial.println("R");break; // repeat
default:
Serial.println("Z"); // other button
}
// Do not get immediate repeat keypress
delay(500);
}
// serial/IR receive
void SERrecv()
{
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '#';
char endMarker = '@';
char rc;
while (Serial.available() > 0 && SERnewData == false) {
// process serial signal
rc = Serial.read();
if(recvInProgress == true) {
if(rc != endMarker) {
SERrecvChars[ndx] = rc;
ndx++;
if (ndx >= SERnumChars) {
ndx = SERnumChars - 1;
}
}
else {
SERrecvChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
SERnewData = true;
}
}
else if(rc == startMarker) {
recvInProgress = true;
}
}
}
// display stats on LCD and load average on LED
void showNewData()
{
if(SERnewData == true) {
if(DEBUG) { if(DEBUG) {
Serial.print("This just in ... "); Serial.print("This just in ... ");
Serial.println(receivedChars); Serial.println(SERrecvChars);
} }
// Print on line 1 or 2 // Print on line 1 or 2
// dev: fucking c and its fixed arrays // dev: fucking c and its fixed arrays
// we have to define 1st character (line number) as BS and when printing, search for that BS character to skip printing that 1 character, grrr // we have to define 1st character (line number) as BS and when printing, search for that BS character to skip printing that 1 character, grrr
if(receivedChars[0] == '1') { if(SERrecvChars[0] == '1') {
LcdL1(true); LcdL1(true);
receivedChars[0] = '\b'; SERrecvChars[0] = '\b';
LcdWrite(receivedChars); LcdWrite(SERrecvChars);
} }
else if(receivedChars[0] == '2') { else if(SERrecvChars[0] == '2') {
LcdL2(true); LcdL2(true);
receivedChars[0] = '\b'; SERrecvChars[0] = '\b';
LcdWrite(receivedChars); LcdWrite(SERrecvChars);
}
else if(SERrecvChars[0] == '3') {
SERrecvChars[0] = ' ';
LedShowLoad(SERrecvChars);
} }
newData = false; SERnewData = false;
} }
} }
void setup (void) { void setup (void)
// Init LCD panel {
// init HW
LcdSetup(); LcdSetup();
LEDSetup();
IRSetup();
// Init Debugging output // open serial port
if(DEBUG) { Serial.begin(9600);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
// Init normal operation // display intros
else { LcdIntro();
Serial.begin(9600); LedIntro();
}
} }
// main() // main()
void loop (void) { void loop (void)
// process input {
recvWithStartEndMarkers(); //process IR signal
if(Irrecv.decode(&IRresults)) {
IRtranslate();
Irrecv.resume(); // receive the next value
}
// process serial input
SERrecv();
// display new data
showNewData(); showNewData();
} }