Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Copyright (C) Andrew Spangler 2018
- //Feel free to use this, just credit me.
- #define VERSION "0.8.9" //version 8 was working independent graphs, version .9 is serial input enabled, 1 is graph number, size, location instructed over serial, 2 is library
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- #include <Wire.h>
- /*-----Role Selector-----*/
- #define ROLE_SEND 0
- #define ROLE_RECEIVE 1
- #define ROLE_PIN 4
- bool ROLE;
- /*-----Serial Stuff-----*/
- String inputString = ""; // a String to hold incoming data
- bool stringComplete = false; // whether the string is complete
- #define enableDebugSpew false // Set to true to enable debug spew into the serial console
- String screenString = "";
- //Serial Mode Switching
- #define MODE_GRAPH 0
- #define PORTABLE_DEBUG 1
- #define enableSerialSetup 1
- int mode[2] = {0, enableSerialSetup}; //second value tracks if setup has run.
- /*-----OLED Stuff-----*/
- #define OLED_RESET LED_BUILTIN //My LCD doesn't support a reset pin (wish it did for esp8266, this code needs a full power cycle to work properly otherwise the screen gets stuck on reset)
- Adafruit_SSD1306 display(OLED_RESET); //this makes the led flash when the display would normally reset, most I2C SSD1306's don't have a reset pin but it must be defined to set up the display.
- #define TEXT_SMALL 1 //Personal Ease-of-reading definitions
- #define TEXT_BIG 2
- #define TEXT_HUGE 3
- /*-----Graph Stuff-----*/
- #define graphBufferSize 33 //Set buffer size, SET TO (WIDTH OF YOUR WIDEST GRAPH + 1) OR YOU WILL EXCEED THE ARRAY.
- #define overflowProtect true //If set to true will prevent graph function from running if the passed graph width is grater than the buffer
- int graphMax = 1023; //max value to pass to the graph, exceeding this value will display at the top of the graph
- struct graphStruct {
- uint8_t gx;
- uint8_t gy;
- uint8_t gw;
- uint8_t gh;
- int gVal;
- int graphBuffer[graphBufferSize];
- bool isReady;
- };
- struct setupPacketStruct { //NO STRINGS IN HERE. GARBAGE OTHERWISE;
- uint8_t gx;
- uint8_t gy;
- uint8_t gw; //Graph buffer size is |TO BE| determined by receiver as gw+2 |NYI|
- uint8_t gh;
- uint8_t gn;
- };
- #define graphNum 4 //Set this to the number of Graphs you want.
- graphStruct graph[graphNum] = { //Each set of brackets is an instance of a graph, one for each specified in graphNum
- //Graph 1 //Usage: {LeftX, TopY, width, height}
- {0, 0, 31, 32},
- //Graph 2
- {32, 0, 31, 32},
- //Graph 3
- {64, 0, 31, 32},
- //Graph 4
- {96, 0, 31, 32},
- };
- /*-------FPS/LPS Counter-------*/
- unsigned long timer; /////DO NOT CALL VARIABLE "time" on ESP8266, CAUSES PROBLEMS W/ COMPILER, works on the trinket 3v. nano also.
- int loops[2]; //counts loops, 0 for current number of loops this second, 1 to store the last value to reprint on the I2C LCD
- unsigned long timerA, timerB, timerC, timerD;
- void setup() {
- Serial.begin(9600); // Start Serial
- delay(40);
- //Determine Role:
- pinMode(ROLE_PIN, INPUT_PULLUP);
- ROLE = digitalRead(ROLE_PIN);
- display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32)
- display.display();
- delay(1000);
- display.clearDisplay(); //To reduce program size you can edit the header to remove the adafruit logo but then you may not redistribute it
- displayCredits();
- display.clearDisplay();
- }
- void loop() {
- if (mode[1]) {
- graphSetup();
- }
- if (mode[0] == MODE_GRAPH) {
- graphLoop();
- }
- fps(0, 0);
- display.display();
- }
- void graphLoop() {
- //-----------------------------------
- //Multi Rate Random Data Maker TEST//
- if (timerA + 1000 <= (millis() )) {
- graphAdd(0, random(1023));
- timerA = millis();
- }
- if (timerB + 35 <= (millis() )) {
- graphAdd(1, random(1023));
- timerB = millis();
- }
- if (timerC + 350 <= (millis() )) {
- graphAdd(2, random(1023));
- timerC = millis();
- }
- if (timerD + 800 <= (millis() )) {
- graphAdd(3, random(1023));
- timerD = millis();
- }
- //-----------------------------------
- for (int i = 0; i < graphNum; i++) {
- if (graph[i].isReady == true) {
- graph[i].isReady = false;
- grapher(graph[i].gx, graph[i].gy, graph[i].gw, graph[i].gh, graph[i].gVal, i);
- }
- }
- }
- void graphAdd(int graphNumber, int newVal) {
- graph[graphNumber].gVal = newVal;
- graph[graphNumber].isReady = true;
- }
- void grapher(int gx, int gy, int gw, int gh, int inVal, int bufferNumber) { //Pass the leftmost pixel (gx), topmost pixel (gy), graph width (gw), graph height (gh), and new value to add (inVal)
- if (overflowProtect) {
- display.drawRect(gx, gy, gw, gh, WHITE); //Draw a rectangle aroung the graph
- display.fillRect(gx + 1, gy + 1, gw - 2, gh - 2, BLACK);
- if (gw + 1 < graphBufferSize) {
- graph[bufferNumber].graphBuffer[0] = ((inVal * gh) / graphMax); //Set the first value of the graphBuffer array to the input value scaled to the graph height and max input value
- for (int i = gw - 2; i >= 0; i--) { //Draw the graph, shifting the array down one notch so the last value is lost and the first value is duplicated between the first and second location in the array, making room for new data on next call and shifting it down
- display.drawLine((gx + i + 1), (gy + (gh) - graph[bufferNumber].graphBuffer[i + 1] + 1), (gx + i), (gy + (gh) - graph[bufferNumber].graphBuffer[i] + 1), WHITE);
- graph[bufferNumber].graphBuffer[i + 1] = graph[bufferNumber].graphBuffer[i];
- }
- } else {
- display.setTextSize(1);
- display.setCursor(gx + 2, gy + 1);
- display.println("Buff");
- display.setCursor(gx + 2, gy + 9);
- display.println("Too");
- display.setCursor(gx + 2, gy + 17);
- display.println("Small");
- }
- } else {
- /*
- * once I have the whole grapher fleshed out I'll add in the non-overflow proteced code with #defined if statements to
- * prevent the compiler from adding anything unneeded
- graph[bufferNumber].graphBuffer[0] = ((inVal * gh) / graphMax);
- display.drawRect(gx, gy, gw, gh, WHITE);
- for (int i = gw - 2; i >= 0; i--) {
- display.drawLine((gx + i + 1), (gy + (gh) - graph[bufferNumber].graphBuffer[i + 1] + 1), (gx + i), (gy + (gh) - graph[bufferNumber].graphBuffer[i] + 1), WHITE);
- graph[bufferNumber].graphBuffer[i + 1] = graph[bufferNumber].graphBuffer[i];
- }
- */
- }
- }
- //FPS Counter, basically updates once a second and displays how many times the program has looped since then
- void fps(int xpos, int ypos) {
- if (timer + 1000 <= (millis() )) {
- loops[1] = loops[0];
- timer = millis();
- loops[0] = 0;
- } else {
- loops[0]++;
- }
- display.setTextSize(1); //set text size
- display.fillRect(xpos, ypos, xpos + 12, ypos + 7, WHITE);
- display.setTextColor(BLACK);
- display.setCursor(xpos, ypos); //sets text line, left aligned,
- display.println(loops[1]);
- }
- void displayCredits() {
- display.setCursor(0, 0);
- display.setTextSize(1);
- display.setTextColor(WHITE);
- display.println("Lyfe's Serial Grapher");
- display.setCursor(0, 9);
- switch (ROLE) {
- case ROLE_SEND:
- display.println("ROLE: TX");
- break;
- case ROLE_RECEIVE:
- display.println("ROLE: RX");
- break;
- default:
- display.println("ROLE: ERROR");
- display.display();
- while (1);
- break;
- }
- display.setCursor(0, 17);
- String versionString = "Version: " + String(VERSION);
- display.println(versionString);
- display.display();
- delay(1000);
- }
- /*---Display Print Functions, structured for different data types, also prints t/f for booleans---*/
- //Pass String
- void displayPrint(String instring, int line, int textSize, bool clear) {
- if (clear) {
- display.clearDisplay(); //only clear if specified
- }
- display.setTextSize(textSize); //set text size
- display.setTextColor(WHITE); //one-color displays are always "white" even if the oled is a different color
- display.setCursor(0, line * 8 * textSize); //sets text line, left aligned,
- display.println(instring); //print data
- }
- //Pass Int
- void displayPrint(int instring, int line, int textSize, bool clear) {
- if (clear) {
- display.clearDisplay();
- }
- display.setTextSize(textSize);
- display.setTextColor(WHITE);
- display.setCursor(0, line * 8 * textSize);
- display.println(instring);
- }
- //Pass Bool
- void displayPrint(bool instring, int line, int textSize, bool clear) {
- if (clear) {
- display.clearDisplay();
- }
- display.setTextSize(textSize);
- display.setTextColor(WHITE);
- display.setCursor(0, line * 8 * textSize);
- if ( instring ) {
- display.println("True");
- } else {
- display.println("False");
- }
- }
- //Pass Float
- void displayPrint(float instring, int line, int textSize, bool clear) {
- if (clear) {
- display.clearDisplay();
- }
- display.setTextSize(textSize);
- display.setTextColor(WHITE);
- display.setCursor(0, line * 8 * textSize); //character line is 7 pixels high
- display.println(instring);
- }
- void serialEvent() {
- while (Serial.available()) {
- // get the new byte:
- char inChar = (char)Serial.read();
- if (inChar == '\n') {
- stringComplete = true;
- if (enableDebugSpew) {
- Serial.println("\n\n_______________________________");
- Serial.print("Received via Serial: ");
- Serial.println(inputString);
- }
- } else {
- inputString += inChar;
- }
- }
- }
- //CODE IN PROGRESS
- #define SEND_REQUEST 0x60
- #define ACK 0x61
- #define MAX_RETRIES 10
- #define ACK_ERR 0x40
- #define TIMEOUT_ERR 0x41
- void graphSetup() {
- if (ROLE == ROLE_RECEIVE) {
- mode[1] = false;
- displayPrint(String("Waiting"), 1, 2, true);
- display.display();
- int waitingDots = 0;
- unsigned long dotTimer = millis();
- String waitString = "Waiting";
- while (!stringComplete) {
- if (dotTimer + 500 <= (millis() )) {
- String waitString = "Waiting";
- for (int i = waitingDots; i > 0; i--) {
- waitString += ".";
- }
- if (waitingDots == 3) {
- waitingDots = 0;
- }
- else {
- waitingDots++;
- }
- displayPrint(waitString, 1, 2, true);
- display.display();
- dotTimer = millis();
- }
- serialEvent();
- mode[1] = !mode[1];
- }
- switch ((inputString.toInt())) {
- case SEND_REQUEST: //Request to set up graph;
- mode[0] = MODE_GRAPH;
- displayPrint(String("Ready"), 0, 2, true);
- displayPrint(inputString, 1, 2, false);
- display.display();
- graphSetupReceive();
- while(true);
- break;
- default:
- displayPrint(String("ERROR"), 0, 2, true);
- display.setTextColor(WHITE);
- display.setTextSize(TEXT_SMALL);
- /* Wrote this because I though the displayPrint function wasn't printing the error code properly, It was.
- for ( int i = 0; i < sizeof(inputString); i++){
- display.setCursor(7 * i, 21);
- display.println(inputString.charAt(i));
- }
- */
- displayPrint(String(inputString), 3, 1, false);
- display.display();
- while (true);
- break;
- }
- }
- if (ROLE == ROLE_SEND) {
- stringComplete = false;
- displayPrint(String("SENDING"), 0, 2, true);
- display.display();
- String packetString; //Used to send the bytes instructing the receiver to go into graph mode and prepare to receive graph setup instructions |NYI|
- Serial.println(SEND_REQUEST);
- displayPrint(SEND_REQUEST, 0, 2, true);
- display.display();
- graphSetupSend();
- }
- }
- bool errorHandler(int errByte){
- display.clearDisplay();
- switch(errByte){
- case ACK_ERR:
- displayPrint(String("ACK_ERR"), 0, 2, true);
- display.display();
- break;
- case TIMEOUT_ERR:
- displayPrint(String("TIMEOUT_ERR"), 0, 2, true);
- display.display();
- break;
- default:
- displayPrint(String("MISSINGNO."), 0, 2, true);
- display.display();
- break;
- while(true);
- }
- }
- void graphSetupReceive() {
- serialWaitWithTimout();
- setupPacketStruct packet[inputString.toInt()]; //Receive the number of graphs and set up struct array
- displayPrint(inputString, 0, 2, true);
- serialWaitWithTimout();
- for (int i = 0; i < graphNum; i++ ){
- delete graph[i];
- }
- }
- void graphSetupSend() {
- //Starts after first ACK in receive
- Serial.println(graphNum); //Send number of graphs to initiate graphs
- waitForACK();
- setupPacketStruct packet[graphNum];
- for (int i = 0; i < graphNum; i++) {
- packet[i].gx = graph[i].gx;
- packet[i].gy = graph[i].gy;
- packet[i].gw = graph[i].gw;
- packet[i].gh = graph[i].gh;
- packet[i].gn = i;
- Serial.write((uint8_t *)&packet[i], sizeof(packet[i]));
- }
- }
- bool waitForACK(){ //checks for ack and reports either timeout or ack error
- inputString = "";
- unsigned long timeOut = millis();
- while (!stringComplete){
- serialEvent();
- if(timeOut + 1000 <= millis()){
- errorHandler(TIMEOUT_ERR);
- }
- stringComplete = false;
- }
- int tempString = inputString.toInt();
- inputString = "";
- if (tempString == ACK){
- return true;
- } else {
- errorHandler(ACK_ERR);
- }
- }
- void serialWaitWithTimout() {
- inputString = "";
- unsigned long timeOut = millis();
- while (!stringComplete){
- serialEvent();
- if(timeOut + 1000 <= millis()){
- errorHandler(TIMEOUT_ERR);
- }
- stringComplete = false;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement