-
-
Save focalintent/17430c45a9ca4d19e979 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Darrenlloyd Gent 2013-2014 | |
// This version 26/06/2014 | |
// Under a whatever, do what you want licence. | |
// Most of this has been cobbled together from various places and I wasn't diligent enough to make notes. | |
// Fastled has been updated since I did all this. http://fastled.io/ | |
// They deserve way more credit. | |
#include <SD.h> //SD Library | |
#include "FastLED.h" // FastSPI_LED2 library | |
#include <avr/pgmspace.h> | |
#include <SPI.h> // SPI library | |
#include <Ethernet.h> // Ethernet Library | |
//#include <MemoryFree.h> // comment out | |
#define NUM_LEDS 300 // Defining the number of LEDs in the strip | |
CRGB leds[NUM_LEDS]; // Create the led Array which will contain the RGB values for each pixel 0 -299 | |
typedef const char prog_char; | |
typedef const uint16_t prog_uint16_t; | |
// The offsets for the splash radius. Stored in Progmem as there wasn't enough space to store in normal memory | |
// Each splash 1-10 gets larger and larger needing more pixels.LEDs. | |
// This was much quicker than calculating the radius in realtime. | |
prog_char splash1[4][2] PROGMEM={{0,0},{0,1},{1,0},{1,1}}; | |
prog_char splash2[8][2] PROGMEM = {{0,-1},{0,2},{-1,0},{1,-1},{-1,1},{1,2},{2,0},{2,1}}; | |
prog_char splash3[12][2] PROGMEM = {{0,-2},{0,3},{-1,-1},{1,-2},{-1,2},{1,3},{-2,0},{2,-1},{-2,1},{2,2},{3,0},{3,1}}; | |
prog_char splash4[16][2] PROGMEM = {{0,-3},{0,4},{-1,-2},{1,-3},{-1,3},{1,4},{-2,-1},{2,-2},{-2,2},{2,3},{-3,0},{3,-1},{-3,1},{3,2},{4,0},{4,1}}; | |
prog_char splash5[36][2] PROGMEM = {{0,-4},{0,5},{-1,-3},{1,-4},{-1,4},{-1,-4},{1,5},{-1,5},{-2,-2},{2,-3},{-2,3},{-2,-3},{2,4},{2,-4},{-2,4},{2,5},{-3,-1},{3,-2},{-3,2},{-3,-2},{3,3},{3,-3},{-3,3},{3,4},{-4,0},{4,-1},{-4,1},{-4,-1},{4,2},{4,-2},{-4,2},{4,3},{5,0},{5,1},{5,-1},{5,2}}; | |
prog_char splash6[28][2] PROGMEM = {{0,-5},{0,6},{1,-5},{-1,-5},{1,6},{-1,6},{-2,-4},{2,-5},{-2,5},{2,6},{-3,-3},{3,-4},{-3,4},{3,5},{-4,-2},{4,-3},{-4,3},{4,4},{-5,0},{-5,1},{-5,-1},{5,-2},{-5,2},{5,3},{6,0},{6,1},{6,-1},{6,2}}; | |
prog_char splash7[32][2] PROGMEM= {{0,-6},{0,7},{1,-6},{-1,-6},{1,7},{-1,7},{-2,-5},{2,-6},{-2,6},{2,7},{-3,-4},{3,-5},{-3,5},{3,6},{-4,-3},{4,-4},{-4,4},{4,5},{-5,-2},{5,-3},{-5,3},{5,4},{-6,0},{-6,1},{-6,-1},{6,-2},{-6,2},{6,3},{7,0},{7,1},{7,-1},{7,2}}; | |
prog_char splash8[36][2] PROGMEM= {{0,-7},{0,8},{1,-7},{-1,-7},{1,8},{-1,8},{-2,-6},{2,-7},{-2,7},{2,8},{-3,-5},{3,-6},{-3,6},{3,7},{-4,-4},{4,-5},{-4,5},{4,6},{-5,-3},{5,-4},{-5,4},{5,5},{-6,-2},{6,-3},{-6,3},{6,4},{-7,0},{-7,1},{-7,-1},{7,-2},{-7,2},{7,3},{8,0},{8,1},{8,-1},{8,2}}; | |
prog_char splash9[68][2] PROGMEM= {{0,-8},{0,9},{1,-8},{-1,-8},{1,9},{-1,9},{-2,-7},{2,-8},{-2,8},{-2,-8},{2,9},{-2,9},{-3,-6},{3,-7},{-3,7},{-3,-7},{3,8},{3,-8},{-3,8},{3,9},{-4,-5},{4,-6},{-4,6},{-4,-6},{4,7},{4,-7},{-4,7},{4,8},{-5,-4},{5,-5},{-5,5},{-5,-5},{5,6},{5,-6},{-5,6},{5,7},{-6,-3},{6,-4},{-6,4},{-6,-4},{6,5},{6,-5},{-6,5},{6,6},{-7,-2},{7,-3},{-7,3},{-7,-3},{7,4},{7,-4},{-7,4},{7,5},{-8,0},{-8,1},{-8,-1},{8,-2},{-8,2},{-8,-2},{8,3},{8,-3},{-8,3},{8,4},{9,0},{9,1},{9,-1},{9,2},{9,-2},{9,3}}; | |
prog_char splash10[48][2] PROGMEM= {{0,10},{0,-9},{1,10},{-1,10},{1,-9},{-1,-9},{10,0},{10,1},{10,-1},{10,2},{10,-2},{10,3},{2,10},{-2,10},{2,-9},{-2,-9},{3,10},{-3,-8},{3,-9},{-3,9},{-4,-7},{4,-8},{-4,8},{4,9},{-5,-6},{5,-7},{-5,7},{5,8},{-6,-5},{6,-6},{-6,6},{6,7},{-7,-4},{7,-5},{-7,5},{7,6},{-8,-3},{8,-4},{-8,4},{8,5},{-9,0},{-9,1},{-9,-1},{-9,2},{-9,-2},{9,-3},{-9,3},{9,4}}; | |
// My characters for each ASCII character, stored in ASCII order, hence the first 30 odd blank. | |
// A binary representation of the individual columns is a 10bit interger. | |
// 1024 indicates end of the character so then the updatescroll moves onto the next letter | |
prog_uint16_t myChars[126][8] PROGMEM={ | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 0 , 0 , 0 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 382 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 14 , 0 , 14 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 160 , 496 , 160 , 496 , 160 , 1024 , 1024 , 1024 }, | |
{ 288 , 336 , 1016 , 336 , 144 , 1024 , 1024 , 1024 }, | |
{ 136 , 64 , 32 , 16 , 136 , 1024 , 1024 , 1024 }, | |
{ 118 , 153 , 169 , 70 , 160 , 1024 , 1024 , 1024 }, | |
{ 7 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 60 , 66 , 129 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 129 , 66 , 60 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 17 , 10 , 31 , 10 , 17 , 1024 , 1024 , 1024 }, | |
{ 32 , 32 , 248 , 32 , 32 , 1024 , 1024 , 1024 }, | |
{ 256 , 128 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 32 , 32 , 32 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 256 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 448 , 48 , 14 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 252 , 322 , 290 , 274 , 252 , 1024 , 1024 , 1024 }, //0 | |
{ 8 , 4 , 510 , 1024 , 1024 , 1024 , 1024 , 1024 }, //1 | |
{ 396 , 322 , 290 , 274 , 268 , 1024 , 1024 , 1024 }, //2 | |
{ 258 , 290 , 290 , 290 , 220 , 1024 , 1024 , 1024 }, //3 | |
{ 62 , 32 , 32 , 504 , 32 , 1024 , 1024 , 1024 }, //4 | |
{ 318 , 290 , 290 , 290 , 194 , 1024 , 1024 , 1024 }, //5 | |
{ 252 , 290 , 290 , 290 , 194 , 1024 , 1024 , 1024 }, //6 | |
{ 2 , 258 , 194 , 50 , 14 , 1024 , 1024 , 1024 }, //7 | |
{ 220 , 290 , 290 , 290 , 220 , 1024 , 1024 , 1024 }, //8 | |
{ 28 , 290 , 290 , 290 , 252 , 1024 , 1024 , 1024 }, //9 | |
{ 0 , 144 , 0 , 1024 , 1024 , 1024 , 1024 , 1024 }, //: | |
{ 256 , 144 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, //; | |
{ 32 , 80 , 136 , 1024 , 1024 , 1024 , 1024 , 1024 }, //< | |
{ 80 , 80 , 80 , 80 , 1024 , 1024 , 1024 , 1024 }, //= | |
{ 136 , 80 , 32 , 1024 , 1024 , 1024 , 1024 , 1024 }, //> | |
{ 2 , 1 , 177 , 9 , 6 , 1024 , 1024 , 1024 }, //? | |
{ 72 , 180 , 330 , 330 , 50 , 68 , 56 , 1024 }, //@ | |
{ 508 , 34 , 34 , 34 , 508 , 1024 , 1024 , 1024 }, //A | |
{ 510 , 290 , 290 , 290 , 200 , 1024 , 1024 , 1024 }, //B | |
{ 120 , 132 , 258 , 258 , 258 , 1024 , 1024 , 1024 }, //C | |
{ 510 , 258 , 258 , 132 , 120 , 1024 , 1024 , 1024 }, //D | |
{ 510 , 290 , 290 , 290 , 290 , 1024 , 1024 , 1024 }, //E | |
{ 510 , 34 , 34 , 34 , 34 , 1024 , 1024 , 1024 }, //F | |
{ 120 , 132 , 258 , 290 , 482 , 1024 , 1024 , 1024 }, //G | |
{ 510 , 32 , 32 , 32 , 510 , 1024 , 1024 , 1024 }, //H | |
{ 258 , 258 , 510 , 258 , 258 , 1024 , 1024 , 1024 }, //I | |
{ 226 , 258 , 254 , 2 , 2 , 1024 , 1024 , 1024 }, //J | |
{ 510 , 32 , 80 , 136 , 262 , 1024 , 1024 , 1024 }, //K | |
{ 510 , 256 , 256 , 256 , 256 , 1024 , 1024 , 1024 }, //L | |
{ 510 , 4 , 24 , 4 , 510 , 1024 , 1024 , 1024 }, //M | |
{ 508 , 2 , 2 , 2 , 508 , 1024 , 1024 , 1024 }, //M | |
{ 252 , 258 , 258 , 258 , 252 , 1024 , 1024 , 1024 }, //O | |
{ 510 , 34 , 34 , 34 , 28 , 1024 , 1024 , 1024 }, //P | |
{ 252 , 258 , 386 , 258 , 764 , 1024 , 1024 , 1024 }, //Q | |
{ 510 , 34 , 34 , 100 , 408 , 1024 , 1024 , 1024 }, //R | |
{ 284 , 290 , 290 , 290 , 194 , 1024 , 1024 , 1024 }, //S | |
{ 2 , 2 , 510 , 2 , 2 , 1024 , 1024 , 1024 }, //T | |
{ 254 , 256 , 256 , 256 , 254 , 1024 , 1024 , 1024 }, //U | |
{ 126 , 128 , 256 , 128 , 126 , 1024 , 1024 , 1024 }, //V | |
{ 254 , 256 , 224 , 256 , 254 , 1024 , 1024 , 1024 }, //W | |
{ 398 , 80 , 32 , 80 , 398 , 1024 , 1024 , 1024 }, //X | |
{ 6 , 24 , 480 , 24 , 6 , 1024 , 1024 , 1024 }, //Y | |
{ 386 , 322 , 290 , 274 , 270 , 1024 , 1024 , 1024 }, //Z | |
{ 255 , 129 , 129 , 129 , 1024 , 1024 , 1024 , 1024 }, //( | |
{ 3 , 12 , 48 , 192 , 1024 , 1024 , 1024 , 1024 }, //backslash | |
{ 129 , 129 , 129 , 255 , 1024 , 1024 , 1024 , 1024 }, //) | |
{ 4 , 2 , 1 , 2 , 4 , 1024 , 1024 , 1024 }, // | |
{ 128 , 128 , 128 , 128 , 128 , 1024 , 1024 , 1024 }, //_ | |
{ 1 , 2 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, //` | |
{ 112 , 136 , 136 , 136 , 112 , 128 , 1024 , 1024 }, //a | |
{ 255 , 136 , 136 , 136 , 112 , 1024 , 1024 , 1024 }, //b | |
{ 112 , 136 , 136 , 136 , 1024 , 1024 , 1024 , 1024 },//c | |
{ 112 , 136 , 136 , 136 , 127 , 1024 , 1024 , 1024 },//d | |
{ 112 , 168 , 168 , 168 , 16 , 1024 , 1024 , 1024 },//e | |
{ 8 , 254 , 9 , 9 , 1024 , 1024 , 1024 , 1024 },//f | |
{ 112 , 648 , 648 , 648 , 496 , 1024 , 1024 , 1024 },//g | |
{ 255 , 8 , 8 , 8 , 240 , 1024 , 1024 , 1024 },//h | |
{ 250 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 },//i | |
{ 384 , 512 , 506 , 1024 , 1024 , 1024 , 1024 , 1024 },//j | |
{ 255 , 32 , 80 , 136 , 1024 , 1024 , 1024 , 1024 },//k | |
{ 127 , 128 , 128 , 1024 , 1024 , 1024 , 1024 , 1024 },//l | |
{ 240 , 8 , 48 , 8 , 240 , 1024 , 1024 , 1024 },//m | |
{ 240 , 8 , 8 , 8 , 240 , 1024 , 1024 , 1024 },//n | |
{ 112 , 136 , 136 , 136 , 112 , 1024 , 1024 , 1024 },//o | |
{ 1016 , 136 , 136 , 136 , 112 , 1024 , 1024 , 1024 },//p | |
{ 112 , 136 , 136 , 1016 , 256 , 1024 , 1024 , 1024 },//q | |
{ 240 , 8 , 8 , 8 , 1024 , 1024 , 1024 , 1024 },//r | |
{ 144 , 168 , 168 , 72 , 1024 , 1024 , 1024 , 1024 },//s | |
{ 16 , 124 , 144 , 1024 , 1024 , 1024 , 1024 , 1024 },//t | |
{ 120 , 128 , 128 , 120 , 1024 , 1024 , 1024 , 1024 },//u | |
{ 120 , 128 , 120 , 1024 , 1024 , 1024 , 1024 , 1024 },//v | |
{ 120 , 128 , 112 , 128 , 120 , 1024 , 1024 , 1024 },//w | |
{ 136 , 80 , 32 , 80 , 136 , 1024 , 1024 , 1024 },//x | |
{ 120 , 640 , 640 , 640 , 504 , 1024 , 1024 , 1024 },//y | |
{ 136 , 200 , 168 , 152 , 136 , 1024 , 1024 , 1024 },//z | |
{ 16 , 126 , 129 , 129 , 1024 , 1024 , 1024 , 1024 }, | |
{ 255 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 }, | |
{ 129 , 129 , 126 , 16 , 1024 , 1024 , 1024 , 1024 }, | |
{ 32 , 16 , 8 , 16 , 32 , 64 , 32 , 1024 } }; | |
// general variables | |
CRGB currBackCol = CRGB(64,64,0); // A global variable to keep a note of the current background GRB value (Some strips may have Red and Green switched | |
CRGB currTextCol = CRGB(0,0,255); // a global variable to keep a track of the current text colour. | |
/* | |
1 = Message | |
2 = Time | |
3 = Date | |
4 = Temp | |
5 = Ripples | |
6 = Matrix | |
7 = Snake | |
8 = Eyes | |
9 = Pac | |
*/ | |
char stateOrder[] = {9,1,2,3,4,5,6,7,8,9};// an array indicating the order that each feature or state should run in. | |
// | |
char stateX = 0; // Related to the stateOrder array. Indicates the current state that should be run | |
// variables for ethernet and getting data from website | |
boolean connectNow = true; // boolean, set to true after x millisencds have passed since the last website retrieval | |
boolean readyToRead = false; // if the data has been retrieved from the webpage and if the first character is an * then this will become true and the data will be stored. Used as error checking | |
char comma = 0; // used to read through how many fields have been read from the web page. | |
char c,cc; // c is used to store the character being read in the parseData function. cc is used to keep track of which index in the myData array is it inserting. | |
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // A mac address for the ethernet client. | |
EthernetClient client; // The ethernet client | |
long sinceLastConnect = 0; // the number of millisencds since the last update from the website | |
char postcode[5]; // used for future plans to read postcode from sd card and send to WWO API via website to allow for custom users | |
char message[60]; // A short message to display. Will store line from txt file on SD card | |
char myData[15][4]; // stores data retrieved from webpage. | |
char iSecond,iMinute, iHour, iDay, iMonth, iYear; // data for time once extracted from myData | |
// variables for State 1. Scrolling Message | |
char currLetter =0; //a variable used to track the current letter that the scrolling message should be processing | |
int cl =0; // cl is the current line (column) that is to be processed by the scrolling text. Each character's column defined by a 10 bit interger. lower case i has one column, m has 5 | |
int h; // something to with counting characters... | |
int endScroll = 0; // Once the final character from the scrolling message passes, this will increment until 30, when all the characters have left the left of the display | |
/// variables for states 2,3 &4 Time, Date and Temp | |
char myTime[5]; // a char array used for time and date. Might not need to be global... "hh:mm" or "dd/mm"; | |
char myTemp; //char used for the current temp "10c" "-5c". Not sure if negative works. Will check next winter. | |
long sinceLastSecond = 0; // a variable used to check if one second has passed since the last time calcTime was called. | |
boolean blinkX = true; // should a : be used to blink the seconds? | |
// variables for state 5, ripples | |
int dropletA[2] = {-1,-1}; // For the dropletCycle. There can be four droplets at a time and this tracks the centre for each. | |
int dropletB[2] = {-1,-1}; | |
int dropletC[2] = {-1,-1}; | |
int dropletD[2] = {-1,-1}; | |
char dropCount = 0; //How many droplets are in action | |
char dropRandom = 0; // a global variable used to countdown to the next droplet | |
unsigned long sinceStateStarted; // used to count howlong in milliseconds since the sinceStateStarted function started. Stupidly used and not renamed as it's used by other states. | |
// variables for state 6, matrix | |
boolean matStart = false; // A boolean used to see if the Matrix effect has been started | |
int mats[30]; // an array used to track the individual Matrix Slivers | |
// variables for state 7, snake | |
char lastMove = 0; // char used for the snake to retain the last direction the snake moved in. | |
boolean snakeStart = false; // boolean to check if the snake has or hasn't started | |
unsigned char snakeHue = 0; // what value is the hue currently for the snake? | |
int snakePos=0; // pixel that the snake is. | |
//variables for state 8 & 9 Bitmaps | |
File bmpFile2; // file for the bitmap for the temp stored in | |
///////////////////////////// | |
void setup() { | |
LEDS.setBrightness(32); // sets the brightness of the LEDs | |
LEDS.addLeds<WS2811, 6>(leds, NUM_LEDS); // Adds the leds colour array to the LEDS array with chip type on data pin 6, with the number of leds. | |
digitalWrite(10,HIGH); // Deselect the Wiznet Chip | |
digitalWrite(4,HIGH); // Deselect the SD Card | |
if (!SD.begin(4)) { // ensure the SD card is working | |
return; | |
} | |
File myData; //local variable used for reading contents of memory card. As local, doesn't conflict with other myData. | |
int lineCount=0; // set the counter for reading in lines to 0 | |
myData = SD.open("myData.txt"); // open the myData.txt | |
int charCount=0; // set the character counter to 0 | |
while (myData.available()) { // while there is data to be read | |
char cx = myData.read(); // store the next character as cx | |
if(cx==10){ // if cx == 10 which is line feed | |
switch(lineCount){ // which line is this? | |
// Previously when the wifi shield was used, the SD card was used to store SSID and Password. This is a bit overkill just for a string, but can be used for future customisation. | |
case 0: // if it's the first line | |
h = charCount; // store the number of characters we've readed as h | |
message[charCount]='\0'; // append onto the last char in the message array a Nul teminator | |
break; | |
case 1: // if it's the second line | |
postcode[charCount]='\0'; // append onto the last char in the postcode array a Nul teminator | |
break; | |
} | |
lineCount++; //increment the line count | |
charCount=0; // rest the char count to 0 | |
}else if(cx==13){ // if a carridge return, ignore it. | |
}else { // if not a carriage return or a nul terminator | |
switch(lineCount){ // check the line | |
case 0: // if the first line | |
message[charCount]=cx; // add a character onto the message variable | |
break; | |
case 1:// if the next line | |
postcode[charCount]=cx; // add a character onto the postcode variable | |
break; | |
} | |
charCount++; // incremement the character count | |
} | |
} | |
myData.close(); // once done close the file | |
setupLetters(); // clean up variables, wipe screen | |
delay(100); // pause has been added to give the ethernet a moment to kick in | |
if (Ethernet.begin(mac) == 0) { // if the ethernet hasn't begun | |
Ethernet.begin(mac); // begin | |
} | |
connectToData(); // call the data from the website | |
} | |
void loop(){ | |
if(millis()>(sinceLastConnect+600000)){ // if it's been 10 minutes since the last time we checked the website for data | |
connectNow = true; // set this to true | |
} | |
if(connectNow == true){ // if this is true and it's time to check for data | |
connectToData(); // call this function to check | |
connectNow = false; // turn off the boolean checking for data | |
sinceLastConnect = millis(); // store the time in millis since the last check | |
} | |
while (client.available()) { // if the ethernet client is available | |
parseData(); // parse the data | |
} | |
if (!client.connected() && comma ==15) { // if the datat has been read in and the 15th item has been identified. Must consider a variable to identify how many items are coming in as this might change. | |
readyToRead = false; // We're not ready to read. | |
outputResults(); // Doesn't output anything, but does sort the data and save into variable | |
sinceStateStarted = millis(); // generic counter to ID the last time a state changed | |
client.stop(); // stop the ethernet client | |
comma++; // increment comma to 16 to prevent this if statement from running again | |
} | |
if(sinceLastConnect != 0) // if we've connected at some point | |
{ | |
if(sinceLastSecond == 0){ | |
sinceLastSecond = sinceLastConnect; /// not sure about this, but not going to remove it... | |
} | |
else | |
{ | |
checkSecond(); // check if a second has passed since the last time | |
} | |
} | |
if(stateX>=sizeof(stateOrder)){ // if we've gone through more states than we have listed | |
stateX=0; // go back to the first state | |
} | |
char currState = stateOrder[stateX]; // what state are we in? | |
switch(currState){ // lets do something for each | |
case 1: // Message | |
updateScroll(); // scroll the text | |
if(currLetter>=h){ // if the current letter we are checking is the length of the message we read from the SD card | |
endScroll++; //, start counting the number of updates since it passed | |
if(endScroll>30){ //Finished Scrolling | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis(); // record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
} | |
break; | |
case 2: | |
showTime(); // errr.... run this function | |
if(millis()-sinceStateStarted>10000){ // if 10 seconds has past since we started this. | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 3: | |
showDate(); | |
if(millis()-sinceStateStarted>5000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); | |
} | |
break; | |
case 4: | |
showTemp(); | |
if(millis()-sinceStateStarted>5000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 5: | |
setRandomDrop(); | |
dropletCycle(); | |
if(millis()-sinceStateStarted>10000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 6: | |
matrixStyle(); | |
if(millis()-sinceStateStarted>10000){ | |
// Serial.println("End"); | |
stateX++;// move to the next state in the list. This will force the next loop to use the next state | |
//writeLog("Finished Matrix"); | |
sinceStateStarted = millis();// record the time of this change | |
matStart = false; // set the boolean that is check when this first starts to false | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 7: | |
snake(); | |
if(millis()-sinceStateStarted>30000){ | |
stateX++;// move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
snakeStart = false; // set Snake so that it hasn't started | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 8: | |
bmpDraw("VID002/", 0, 0); | |
if(millis()-sinceStateStarted>15000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis(); // record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 9: | |
bmpDraw("VID001/", 0, 0); | |
if(millis()-sinceStateStarted>8000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
case 10: | |
//memCheck(); | |
if(millis()-sinceStateStarted>3000){ | |
stateX++; // move to the next state in the list. This will force the next loop to use the next state | |
sinceStateStarted = millis();// record the time of this change | |
setupLetters(); //wipe, clean, change... | |
} | |
break; | |
} | |
delay(1); | |
} | |
void checkSecond(){ // has a second passed? | |
if(millis()>(sinceLastSecond+1000)) // if a second has passed since the last time we checked | |
{ | |
calcTime(); // calculate the new time | |
sinceLastSecond+=1000; // add 1000 millis to the last sencond checkpoint | |
} | |
} | |
void snake(){ // The snake generator | |
CHSV temphsv;// This is a varaible that stored Hue Saturation and brightness instead of RGB | |
if(!snakeStart){ // if we haven't already started | |
snakeHue=random(256); // create a random hue 0-255 | |
snakePos=random(300); // create a random start point | |
for(int v=0;v<300;v++){ // for each pixel, | |
temphsv.h = snakeHue; // the temp hue to the snake hue | |
temphsv.s = 187; //medium saturation | |
temphsv.v = 255; // full brightness | |
hsv2rgb_rainbow( temphsv, leds[v]); // Converts HSV to RGB annd sets the LED | |
snakeStart = true; // set this to true so this first bit doesn't run again | |
} | |
LEDS.show(); // send all of the LED data through to the strip | |
} | |
snakeHue++; // adjust the snake hue by 1. As it's an unsigned character it will automatically become 0 when it goes over 255 | |
temphsv.h = snakeHue; // do the set up of the HSV | |
temphsv.s = 187; | |
temphsv.v = 255; | |
hsv2rgb_rainbow( temphsv, leds[snakePos]); // This time only make the snake pos the new colour | |
boolean goodMove = false; // set this to false so that it sets this to think no good move has been made | |
char diceRoll = random(4); // a random number 0 -3 sets the char also | |
while(!goodMove){ // whislt no good move has been made | |
diceRoll = random(4); // make a new random number... | |
/// 0 moves left, 1 moves right, 2 moves up, 3 moves down | |
if(diceRoll == 0 && lastMove!=1){goodMove = true;} // if this move is left and the last move was not right (back on itself) then this is a good move | |
if(diceRoll == 1 && lastMove!=0){goodMove = true;} // if this move is right and the last move was not left (back on itself) then this is a good move | |
if(diceRoll == 2 && lastMove!=3){goodMove = true;} // if this move is up and the last move was not moving down (back on itself) then this is a good move | |
if(diceRoll == 3 && lastMove!=2){goodMove = true;} // if this move is down and the last move was not up (back on itself) then this is a good move | |
} | |
lastMove = diceRoll; // set the last move to the current move | |
switch(diceRoll){ // act on the random number | |
case 0: // left | |
if(snakePos%30==0){ //if the snake position is right on the left so that the LED number is whole divisable by 0 | |
snakePos+=29; // move the pixel to the far right of the display (so it wraps around) | |
}else{ | |
snakePos--; // otherwise move it to the LED to the left | |
} | |
break; | |
case 1: // right | |
if(snakePos%30==29){ // if the remainder from this is 29, it means the snake is at the far right of the display | |
snakePos-=29; // substract 29 moves it to the other side of the screen | |
}else{ | |
snakePos++; // otherwise just move it to the pixel on the right | |
} | |
break; | |
case 2: // up | |
if(snakePos<29){ //if the current LED is less than 29, it is already at the top | |
snakePos+=270; // so adding 270 moves it to the bottom | |
}else{ | |
snakePos-=30; // otherwise substract 30 will move it directly to the line above | |
} | |
break; | |
case 3: // down | |
if(snakePos>269){ // if it's greater than 269 then the snake is already on the bottom line | |
snakePos-=270; // subtracting 270 will move it to the top | |
}else{ | |
snakePos+=30; // otherwise, adding 30 will move it to the next line down | |
} | |
break; | |
} | |
LEDS.show(); // Once everything is done, send it through to the strip | |
} | |
void setupLetters(){ // cleans up the variables for messages and text, calls the random colour chooser, wipes background, | |
endScroll = 0; // reset the endscroll to 0, otherwise the next scrolling message will think it's already completed | |
currLetter = 0; // set the current letter back to 0 so that it starts with the first character next time | |
cl=0; // set the current line to 0 so that the first column of the letter is rendered first | |
randomColourPicker(); // chooses a new colour from a selection | |
wipeBG(currBackCol); // wipes everything with the new background colour | |
} | |
void randomColourPicker(){ // for picking a random colour scheme from a selection | |
char randChar = random(7); // pick a random number | |
// thinking about this, an array in progmem might be better for this? | |
switch(randChar){ // what's our number? | |
case 0: | |
currBackCol = CRGB(0,0,0); // set backgroun to black | |
currTextCol = CRGB(255,0,255); // set the text to whatever | |
break; | |
case 1: | |
currBackCol = CRGB(0,0,0);// rinse and repeat | |
currTextCol = CRGB(255,255,255); | |
break; | |
case 2: | |
currBackCol = CRGB(0,0,0); | |
currTextCol = CRGB(255,255,0); | |
break; | |
case 3: | |
currBackCol = CRGB(0,0,0); | |
currTextCol = CRGB(0,255,255); | |
break; | |
case 4: | |
currBackCol = CRGB(0,0,0); | |
currTextCol = CRGB(0,0,255); | |
break; | |
case 5: | |
currBackCol = CRGB(0,0,0); | |
currTextCol = CRGB(0,255,0); | |
break; | |
case 6: | |
currBackCol = CRGB(0,0,0); | |
currTextCol = CRGB(255,0,0); | |
break; | |
// case 7: // not using these are the moment as they didn't work that well | |
// currBackCol = CRGB(255,0,0); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 8: | |
// currBackCol = CRGB(0,255,0); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 9: | |
// currBackCol = CRGB(0,0,255); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 10: | |
// currBackCol = CRGB(0,255,255); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 11: | |
// currBackCol = CRGB(255,255,0); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 12: | |
// currBackCol = CRGB(255,0,255); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
// case 13: | |
// currBackCol = CRGB(255,255,255); | |
// currTextCol = CRGB(0,0,0); | |
// break; | |
} | |
} | |
void wipeBG(CRGB thisCol){ // with this colour | |
for(int v=0; v<300; v++){ // every LED in the house | |
leds[v] = thisCol;// change to this colour; | |
} | |
LEDS.show(); //update the strip | |
} | |
void showTime(){ //showTime, really, not the TV channel | |
char buffer[2]; // creates a buffer so that we can get around a single digit for numbers less than 10 | |
itoa(iHour,buffer,10); // converts iHour, an integer to a string in the char buffer, to base 10 | |
if(iHour<10){ //if less than ten | |
myTime[0] = '0'; //set the first char in myTime to '0' | |
myTime[1] = buffer[0]; // set the send char to the number | |
}else{ | |
myTime[0] = buffer[0]; //if greater than 9 then just take the hour to the respective index. | |
myTime[1] = buffer[1]; | |
} | |
if(blinkX){ // the third char is a blinking divider | |
myTime[2] = ':'; // which is either on... | |
}else{ | |
myTime[2] = ' ';// or not on | |
} | |
itoa(iMinute,buffer,10); // do the same conversion and check for minutes | |
if(iMinute<10){ | |
myTime[3] = '0'; // enter a zero for 'tens' of minutes into the 4th char | |
myTime[4] = buffer[0]; //the then the rest | |
}else{ | |
myTime[3] = buffer[0]; | |
myTime[4] = buffer[1]; | |
} | |
blinkX^=true; //reverse blink. | |
delay(500); // pause for half a second | |
showStillText(myTime); // call the function to display the time | |
} | |
void showDate(){ // pretty much as the showTime function. Read that for the same | |
char buffer[2]; | |
itoa(iDay,buffer,10); | |
if(iDay<10){ | |
myTime[0] = '0'; | |
myTime[1] = buffer[0]; | |
}else{ | |
myTime[0] = buffer[0]; | |
myTime[1] = buffer[1]; | |
} | |
myTime[2] = '/'; | |
itoa(iMonth,buffer,10); | |
if(iMonth<10){ | |
myTime[3] = '0'; | |
myTime[4] = buffer[0]; | |
}else{ | |
myTime[3] = buffer[0]; | |
myTime[4] = buffer[1]; | |
} | |
delay(500); | |
showStillText(myTime); | |
} | |
void showTemp(){//Simliar to the previous two functions. | |
char myTemp[5]; | |
for(int l=0;l<5;l++){ | |
if(myData[0][l]!='\0'){ // if this isn't the end of the data | |
myTemp[l] = myData[0][l]; // add it to the char array | |
}else{ | |
myTemp[l++] = 'c'; // if it is, then add celius on the end | |
while(l<5){ | |
myTemp[l++] = ' '; // if still less than 5 chars, add a space | |
} | |
} | |
} | |
showStillText(myTemp); // show the text | |
delay(500); // pause | |
} | |
void showStillText(char newText[5]){ // only take five characters | |
int updateLine,vv,i, k, y; | |
for(i=0;i<29;i++){ // for each column | |
if(i==0){ | |
vv=0; // which character are we dealing with? | |
cl=0; // which column in the character are we dealing with | |
updateLine = 0; | |
}else{ | |
y =newText[vv]; // y is the current chracter we need to process | |
updateLine = findLine(y); // checks for the binary 10 bit column data. | |
if(vv>4){ // if we've checked all the chars in the newText | |
updateLine = 0; | |
} | |
if(updateLine==1024){ //if 1024 indicates that all columns in the character have been rendered | |
for(char pp=0;pp<10;pp++){ // for each pixel in this column | |
leds[((270+i)-(pp*30))] = currBackCol; // wipe all to the background colour before we begin | |
} | |
cl=0; // set the current column to process to 0 | |
vv++; //increment the variable counting which character we are processing | |
}else{ /// see the bottom of the script for an ASCII explaination | |
if(updateLine/512==1){ // If the data can be divided by 512 and is 1 (integers are whole), then the the bottom LED is lit | |
leds[270+i] = currTextCol; // The bottom LED is set to the the text colour. | |
updateLine-=512; // Remove 512, otherwise everything else can divide into it | |
}else{ | |
leds[270+i] = currBackCol; // otherwise set this LED to off | |
} | |
if(updateLine/256==1){ // If divisable by 256 | |
leds[240+i] = currTextCol; // then go to the second to bottom LED and set | |
updateLine-=256; // remove | |
}else{ | |
leds[240+i] = currBackCol; | |
} | |
if(updateLine/128==1) //rinse and repeat | |
{ | |
leds[210+i] = currTextCol; | |
updateLine-=128; | |
}else{ | |
leds[210+i] = currBackCol; | |
} | |
if(updateLine/64==1) | |
{ | |
leds[180+i] = currTextCol; | |
updateLine-=64; | |
}else{ | |
leds[180+i] = currBackCol; | |
} | |
if(updateLine/32==1){ | |
leds[150+i] = currTextCol; | |
updateLine-=32; | |
}else{ | |
leds[150+i] = currBackCol; | |
} | |
if(updateLine/16==1) | |
{ | |
leds[120+i] = currTextCol; | |
updateLine-=16; | |
}else{ | |
leds[120+i] = currBackCol; | |
} | |
if(updateLine/8==1) | |
{ | |
leds[90+i] = currTextCol; | |
updateLine-=8; | |
}else{ | |
leds[90+i] = currBackCol; | |
} | |
if(updateLine/4==1) | |
{ | |
leds[60+i] = currTextCol; | |
updateLine-=4; | |
}else{ | |
leds[60+i] = currBackCol; | |
} | |
if(updateLine/2==1) | |
{ | |
leds[30+i] = currTextCol; | |
updateLine-=2; | |
}else{ | |
leds[30+i] = currBackCol; | |
} | |
if(updateLine==1) | |
{ | |
leds[i] = currTextCol; | |
}else{ | |
leds[i] = currBackCol; | |
} | |
} | |
} | |
} | |
LEDS.show(); | |
} | |
void matrixStyle(){ | |
int v; // holding integer for the current "sliver" running down the screen | |
if(matStart == false){ //If this is the start of the cycle... | |
for(v=0;v<30;v++){ // Set up 30 "slivers" | |
mats[v] = random(420)-120; // between -120 and 300 | |
} | |
//writeLog("Start Martix"); | |
matStart = true; // switch the boolean so the above won't run each time. | |
} | |
for(int v=0; v<300; v++){ // for every pixel on the display, wipe all and | |
leds[v] = CRGB(16,0,0); // set to 16 green. | |
} | |
// each silver is 5 pixels long, and the start postion is from the top (screen starts top left) | |
//so the following if statements checks | |
for(v=0;v<30;v++){ // each silver in the mats array | |
int pv = mats[v]; // temp store the top position in pv | |
if(pv>-120 && pv < 179){ // if the start position is at least more than four lines from the bottom of the display | |
leds[pv+120] = CRGB(255,0,0); // make the pixel four lines down the brightest green it can. | |
} | |
if(pv>-90 && pv < 209){ // if the start position is at least more than three lines from the bottom of the display | |
leds[pv+90] = CRGB(200,0,0); // make the pixel three lines down the 200 green. | |
} | |
if(pv>-60 && pv < 239){ // if the start position is at least more than two lines from the bottom of the display | |
leds[pv+60] = CRGB(150,0,0); // make the pixel two lines down the 150 green. | |
} | |
if(pv>-30 && pv < 269){// if the start position is at least more than one line from the bottom of the display | |
leds[pv+30] = CRGB(100,0,0); // make the pixel one line down the 100 green. | |
} | |
pv+=30; //add 30 to the sliver position so the next cycle it is one line down | |
if(pv>300){ // if the srat position is past the bottom of the screen | |
mats[v] = random(30)-120; // set the new position between -120 and -91 | |
}else{ | |
mats[v]=pv; // otherwise set it to one line down | |
} | |
} | |
LEDS.show(); //push this data to the strip | |
delay(50); //pause for 1/20th second | |
} | |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Start of the code dealing with the droplets. | |
// Made up of four functions. | |
// setRandomDrop | |
// dropletCycle | |
// droplets | |
// ripple1, ripple2, ripple3. ripple4, ripple5, ripple6, ripple7, ripple8, ripple9, ripple 10 | |
// setRipPix | |
// | |
// setRandomDrop(); and dropletCycle(); are called from the update loop every loop that char currState = stateOrder[stateX]; = 5 | |
// setRandomDrop times the creation of new drops and gives them a random position | |
// dropletCycle makes the ripple effect and for each active drop, calls droplets | |
// droplets works out the age of the droplet and calls one to three of the ripple(1-10) functions that make up the size of the ripple | |
// ripple(1-10) accesses the splash(1-10) arrays that holds the offsets for every pixel that makes up the ripple. Calls setRipPix | |
// setRipPix uses the offsets for each pixel in each ripple to set the colour of each. | |
void setRandomDrop(){ | |
if(dropRandom<0){ // dropRandom allows a random number of frame updates before it creates another droplet. | |
int r = random(300); // create a random pixel to start the droplet at. | |
switch(dropCount){ // depending on which droplet should be created.... | |
case 0: | |
dropletA[0] = r; // set the position of the new droplet | |
dropletA[1] = 0; // set the age of the new droplet to 0 | |
break; | |
case 1: | |
dropletB[0] = r; | |
dropletB[1] = 0; | |
break; | |
case 2: | |
dropletC[0] = r; | |
dropletC[1] = 0; | |
break; | |
case 3: | |
dropletD[0] = r; | |
dropletD[1] = 0; | |
break; | |
} | |
dropRandom = random(20); // Create a new random amount of cycles until the next droplet is generated | |
dropCount++; // Increment the order of droplets | |
} | |
if(dropCount>3){ //if the order of droplets has gone beyond 3, switch to 0 so that it can't have mroe than 4. | |
dropCount = 0; | |
} | |
dropRandom--; //decrement the counter countingdown to the next droplet | |
} | |
void dropletCycle(){ | |
for(int v=0; v<300; v++){ // for all pixels | |
int blueRand = random(25); // a random number | |
leds[v] = CRGB(0,0,25+blueRand); // this will create a rippling effect as each pixel will be set to a blue between 25 and 50 | |
} | |
if(dropletA[1] != -1){ // if dropletA's age is -1, it hasn't been created, so only run this if it exists. | |
dropletA[1] = droplets(dropletA); // call the droplets function for dropletA. The returned value will increment the age of the ripple. | |
} | |
if(dropletB[1] != -1){ | |
dropletB[1] = droplets(dropletB); | |
} | |
if(dropletC[1] != -1){ | |
dropletC[1] = droplets(dropletC); | |
} | |
if(dropletD[1] != -1){ | |
dropletD[1] = droplets(dropletD); | |
} | |
LEDS.show(); | |
} | |
int droplets(int x[2]){ // from above. This will expect an integer array with two values | |
// int c = 85; | |
int stage = x[1]; // stage = age of droplet | |
int q = x[0]; // centre of the droplet. Pixel | |
switch(stage){ // depending on the age of the droplet | |
case 1: | |
ripple1(q, 1); // only run the smallest ripple, first variable sent through is position, second is the brightness of the part of the ripple 1*85 = 85, 3*85 is 255 | |
break; | |
case 2: | |
ripple1(q,3); // Ripple 1 (smallest) will be 3 times brighter than the larger ripple. | |
ripple2(q,1); // Ripple 2 will be one third of the brightness of ripple 1. | |
break; | |
case 3: | |
ripple1(q,1); | |
ripple2(q,3); | |
ripple3(q,1); | |
break; | |
case 4: | |
ripple2(q,1); | |
ripple3(q,3); | |
ripple4(q,1); | |
break; | |
case 5: | |
ripple3(q,1); | |
ripple4(q,3); | |
ripple5(q,1); | |
break; | |
case 6: | |
ripple4(q,1); | |
ripple5(q,3); | |
ripple6(q,1); | |
break; | |
case 7: | |
ripple5(q,1); | |
ripple6(q,3); | |
ripple7(q,1); | |
break; | |
case 8: | |
ripple6(q,1); | |
ripple7(q,3); | |
ripple8(q,1); | |
break; | |
case 9: | |
ripple7(q,1); | |
ripple8(q,3); | |
ripple9(q,1); | |
break; | |
case 10: | |
ripple8(q,1); | |
ripple9(q,2); | |
ripple10(q,1); | |
break; | |
case 11: | |
ripple9(q,1); | |
ripple10(q,2); | |
break; | |
case 12: | |
ripple10(q,1); | |
break; | |
} | |
stage++; | |
if(stage>14){ | |
stage = -1; // if the ripple is past the age of 14, then set it to -1, which indcates non-existance. | |
} | |
return stage; // return the age | |
} | |
void ripple1(int w, int f){ | |
for(int p=0;p<4;p++){ //splash1 which is in progMem has 4 pixels, hence looping 4 times | |
char ax = pgm_read_byte_near(&(splash1[p][0])); // retrive the x offset for this pixel of the ripple | |
char ay = pgm_read_byte_near(&(splash1[p][1])); // retrive the y offset for this pixel of the ripple | |
setRipPix(w,f,ax,ay); // send the centre position of the ripple, the intensity of the brightness, x offset and y offet to setRipPix.... | |
} | |
} | |
void ripple2(int w, int f){ | |
for(int p=0;p<8;p++){ //splash2 which is in progMem has 8 pixels, hence looping 8 times | |
char ax = pgm_read_byte_near(&(splash2[p][0])); | |
char ay = pgm_read_byte_near(&(splash2[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple3(int w, int f){ | |
for(int p=0;p<12;p++){ | |
char ax = pgm_read_byte_near(&(splash3[p][0])); | |
char ay = pgm_read_byte_near(&(splash3[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple4(int w, int f){ | |
for(int p=0;p<16;p++){ | |
char ax = pgm_read_byte_near(&(splash4[p][0])); | |
char ay = pgm_read_byte_near(&(splash4[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple5(int w, int f){ | |
for(int p=0;p<36;p++){ | |
char ax = pgm_read_byte_near(&(splash5[p][0])); | |
char ay = pgm_read_byte_near(&(splash5[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple6(int w, int f){ | |
for(int p=0;p<28;p++){ | |
char ax = pgm_read_byte_near(&(splash6[p][0])); | |
char ay = pgm_read_byte_near(&(splash6[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple7(int w, int f){ | |
for(int p=0;p<32;p++){ | |
char ax = pgm_read_byte_near(&(splash7[p][0])); | |
char ay = pgm_read_byte_near(&(splash7[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple8(int w, int f){ | |
for(int p=0;p<36;p++){ | |
char ax = pgm_read_byte_near(&(splash8[p][0])); | |
char ay = pgm_read_byte_near(&(splash8[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple9(int w, int f){ | |
for(int p=0;p<68;p++){ | |
char ax = pgm_read_byte_near(&(splash9[p][0])); | |
char ay = pgm_read_byte_near(&(splash9[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void ripple10(int w, int f){ | |
for(int p=0;p<48;p++){ | |
char ax = pgm_read_byte_near(&(splash10[p][0])); | |
char ay = pgm_read_byte_near(&(splash10[p][1])); | |
setRipPix(w,f,ax,ay); | |
} | |
} | |
void setRipPix(int w, int f, char ax, char ay){ | |
int pix = w + ax + (ay*30); //calculate the individual pixel sent that makes up part of the current ripple by taking the centre (w), adding the x offset, and adding the yOffset by multiplying it by 30 to get the Y position | |
if(pix > -1 && pix < 300){ // ensure that this pixel is in the display range | |
leds[pix] = CRGB(0,0,85*f); // set that pixel to the intestity. | |
} | |
} | |
void updateScroll(){ | |
int i, k, l; | |
//////////////////////////////////////////// | |
for(i=0;i<29;i++) // | |
{ // This nested loop will just budge each pixel/LED value | |
for(k=0;k<10;k++) // back one The value of LED[10] will become LED[9], | |
{ // LED[234] becomes LED[233]. This means the only LEDs that | |
l = i+(k*30); // have to be recalculated are 29,59,89,119,149,179,209,239,269 | |
leds[l] = leds[l+1]; // | |
} // | |
} // | |
////////////////////////////////////////// | |
int updateLine; // See the function showStillText for the rest of this function explaination as they are very much the same | |
// This one just budges the LEDs left once and calculates the far right LEDs. | |
char y =message[currLetter]; | |
if(currLetter>h-1){ | |
updateLine=0; | |
currLetter++; | |
}else{ | |
updateLine = findLine(y); | |
} | |
if(updateLine==1024) | |
{ | |
for(char pp=0;pp<10;pp++){ | |
leds[(299-(pp*30))] = currBackCol; | |
} | |
cl=0; | |
currLetter++; | |
} | |
else | |
{ | |
if(updateLine/512==1) | |
{ | |
leds[299] = currTextCol; | |
updateLine-=512; | |
} | |
else | |
{ | |
leds[299] = currBackCol; | |
} | |
if(updateLine/256==1) | |
{ | |
leds[269] = currTextCol; | |
updateLine-=256; | |
} | |
else | |
{ | |
leds[269] = currBackCol;; | |
} | |
if(updateLine/128==1) | |
{ | |
leds[239] = currTextCol; | |
updateLine-=128; | |
} | |
else | |
{ | |
leds[239] = currBackCol; | |
} | |
if(updateLine/64==1) | |
{ | |
leds[209] = currTextCol; | |
updateLine-=64; | |
} | |
else | |
{ | |
leds[209] = currBackCol; | |
} | |
if(updateLine/32==1) | |
{ | |
leds[179] = currTextCol; | |
updateLine-=32; | |
} | |
else | |
{ | |
leds[179] = currBackCol; | |
} | |
if(updateLine/16==1) | |
{ | |
leds[149] = currTextCol; | |
updateLine-=16; | |
} | |
else | |
{ | |
leds[149] = currBackCol; | |
} | |
if(updateLine/8==1) | |
{ | |
leds[119] = currTextCol; | |
updateLine-=8; | |
} | |
else | |
{ | |
leds[119] = currBackCol; | |
} | |
if(updateLine/4==1) | |
{ | |
leds[89] = currTextCol; | |
updateLine-=4; | |
} | |
else | |
{ | |
leds[89] = currBackCol; | |
} | |
if(updateLine/2==1) | |
{ | |
leds[59] = currTextCol; | |
updateLine-=2; | |
} | |
else | |
{ | |
leds[59] = currBackCol; | |
} | |
if(updateLine==1) | |
{ | |
leds[29] = currTextCol; | |
} | |
else | |
{ | |
leds[29] = currBackCol; | |
} | |
} | |
LEDS.show(); | |
delay(50); | |
} | |
int findLine(char x){ // identifies the 10bit integer that indicates the LEDs in the column of the character. X is the character/ASCII code | |
int p; // | |
p = pgm_read_word(&(myChars[x-1][cl])); //Accesss the ProgMem array myChars. Minus 1 for zero index. CL is the current line(column) of the character to be processed | |
cl++; //increments the current line (column) for the next time | |
return p; // returns the 10 bit column information. | |
} | |
void calcTime(){ //Some of this is overkill due to the 10 minute check, but it might look stupid if you have a March 32 at 00.01 | |
iSecond++; //Add one to iSecond | |
if(iSecond>59) // if we have 60 or more seconds | |
{ | |
iSecond=0; // set seconds to 0 | |
iMinute++; // add one to minutes | |
if(iMinute>59) // if we now have more than 60 minutes | |
{ | |
iMinute=0; // set minutes to 0 | |
iHour++;// and add one to the hour | |
if(iHour>23)// if we have more than 23 hours | |
{ | |
iHour=0; // set hours to 0 | |
iDay++; // add a day | |
if(iMonth==2) // if feb | |
{ | |
if(iDay>=28)// if days over 28 | |
{ | |
if(iYear%4==0)//if a leap year | |
{ | |
if(iDay==29) // if over 29 | |
{ | |
iMonth++; // add a month | |
iDay=1; // set day to 1 | |
} | |
} | |
else // else must be 28 days | |
{ | |
iMonth++; // add a month | |
iDay=1; // set day to 1 | |
} | |
} | |
} | |
if(iMonth==1,3,5,7,8,10,12) // if jan, march, July, August, October or December | |
{ | |
if(iDay>31) // if the day is over 31 | |
{ | |
iMonth++; // add a month | |
iDay=1; // set day to 1 | |
} | |
} | |
if(iMonth==4,6,9,11) // if April, June, Septmeber or November | |
{ | |
if(iDay>30)// if day is greater than 30 | |
{ | |
iMonth++; // add a month | |
iDay=1; // set day to 1 | |
} | |
} | |
if(iMonth==13)// if month is 13 | |
{ | |
iMonth==1; /// set to 1 (Jan) | |
iYear++; // add a year | |
} | |
} | |
} | |
} | |
} | |
void connectToData(){ // This is the function that checks for data from a website. See the php files for how this works | |
for(int p=0;p<15;p++){ // for 15 bits of data, this should be in a variable rather than hardcoded.... | |
for(int o=0;o<4;o++){ // for five characters | |
myData[p][o] = '\0'; // blitz the lot with Nul terminators. | |
} | |
} | |
comma = 0; //set the comma count to 0 | |
delay(2000); // The delay allows the Enternet client time to settle, otherwise data might not be reached.... | |
if (client.connect("your.wesbite.com", 80)) { // The website | |
client.println("GET /ardData.php HTTP/1.1"); // The URL | |
client.println("Host: your.wesbite.com"); // The host | |
client.println("Connection: close"); // Not sure, but needed.... | |
client.println(); // No idea, but not going to mess with it. | |
delay(2000); // Another delay to also the client time.... | |
} | |
} | |
void parseData(){ // Reading in the data from the website | |
// Example | |
// *19,116,8,ESE,21,10,8,E,116,06,26,14,13,28,43 | |
// * indidcates the start and is used to check the data is mine. | |
// Each bit of data is delimited with a comma | |
// Check youtube video for more info. | |
c = client.read(); // read in the next (or first if we've just started) | |
if(c=='*'){ // if the first character is an * then it's my data. An error checker of sorts | |
readyToRead = true; // Ready to read the data in | |
} | |
if(c!=',' && readyToRead == true && c!='*' && c!=-1){ // If the character is not a comma, and not an * or dead, and we're ready to read | |
myData[comma-1][cc]+=c; // add the character read into c appropate field | |
cc++; //increment the character counter | |
} | |
if(c==','){ // if we've read in a comma, then it's the next bit of data | |
myData[comma-1][cc]= '\0';; // end the current bit of data we're reading with a Nul Terminator | |
cc=0; // Reset the character | |
comma++; //increment the counter counting the different bits of data. | |
} | |
} | |
void outputResults(){ // this will save the data from the website into various variables | |
iSecond = atoi(myData[14]); //Convert chars to integers and save | |
iMinute = atoi(myData[13]); | |
iHour = atoi(myData[12]); | |
iDay = atoi(myData[10]); | |
if(iDay==0){ | |
connectNow=true; // if iDay = 0 then something is wrong with my website so try again. | |
} | |
iMonth = atoi(myData[9]); | |
if(iMonth==0){ | |
connectNow=true; | |
} | |
iYear = atoi(myData[11]); | |
if(iYear==0){ | |
connectNow=true; | |
} | |
/* Serial.print("currTemp "); //1,1 | |
Serial.println(myData[0]); //1,1 | |
Serial.print("currWeathercode "); //1,2 | |
Serial.println(myData[1]); //1,2 | |
Serial.print("currWindSpeed "); //1,5 | |
Serial.println(myData[2]); //1,5 | |
Serial.print("currWindDirection "); //1,8 | |
Serial.println(myData[3]); //1,8 | |
Serial.print("futTempHigh "); //2,1 | |
Serial.println(myData[4]); //2,1 | |
Serial.print("futTempLow "); //2,3 | |
Serial.println(myData[5]); //2,3 | |
Serial.print("futWindSpeed "); //2,5 | |
Serial.println(myData[6]); //2,5 | |
Serial.print("futWeatherCode "); //2,9 | |
Serial.println(myData[7]); //2,9 | |
Serial.print("futWindDirection "); //2,8 | |
Serial.println(myData[8]); //2,8 | |
printTime();*/ | |
} | |
void bmpDraw(char *filename, uint8_t x, uint8_t y) { // This is slightly complex | |
int bmpWidth, bmpHeight; // W+H in pixels | |
uint8_t bmpDepth; // Bit depth (currently must be 24) | |
uint32_t bmpImageoffset; // Start of image data in file | |
uint32_t rowSize; // Not always = bmpWidth; may have padding | |
uint8_t sdbuffer[3*20]; // pixel buffer (R+G+B per pixel) | |
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer | |
boolean goodBmp = false; // Set to true on valid header parse | |
boolean flip = true; // BMP is stored bottom-to-top | |
int w, h, row, col; // setting up integers for width, height, row and column. | |
uint8_t r, g, b,lc; // unsigned 8 bit integers.... | |
bmpFile2 = SD.open(filename); // open the folder | |
bmpFile2.rewindDirectory(); // go to the start of the directory | |
while(true) { | |
delay(1); | |
lc++; //? | |
File bmpFile = bmpFile2.openNextFile(); // read in the next file | |
if (! bmpFile) { //If no file | |
break; // stop | |
} | |
uint32_t pos = 0; | |
if(read16(bmpFile) == 0x4D42) { // If this has a BMP signature | |
//Going through the header data, there are things we can read and ignore.... | |
(void)read32(bmpFile); //ignore this | |
(void)read32(bmpFile); // Read & ignore creator bytes | |
bmpImageoffset = read32(bmpFile); // Start of image data | |
(void)read32(bmpFile); // Ignore | |
bmpWidth = read32(bmpFile); //This retrieves the width of the bitmap in pixels | |
bmpHeight = read32(bmpFile); //This retrieves the height of the bitmap in pixels | |
if(read16(bmpFile) == 1) { // # planes -- must be '1' | |
bmpDepth = read16(bmpFile); // bits per pixel | |
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed | |
goodBmp = true; // Supported BMP format -- proceed! | |
rowSize = (bmpWidth * 3 + 3) & ~3; | |
if(bmpHeight < 0) { | |
bmpHeight = -bmpHeight; | |
flip = false; | |
} | |
w = bmpWidth; | |
h = bmpHeight; | |
for (row=0; row<h; row++) { // For each scanline... | |
if(flip) // Bitmap is stored bottom-to-top order (normal BMP) | |
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize; | |
else // Bitmap is stored top-to-bottom | |
pos = bmpImageoffset + row * rowSize; | |
if(bmpFile.position() != pos) { // Need seek? | |
bmpFile.seek(pos); | |
buffidx = sizeof(sdbuffer); // Force buffer reload | |
} // not sure about these bits.... | |
for (col=0; col<w; col++) { // For each pixel... | |
// Time to read more pixel data? | |
if (buffidx >= sizeof(sdbuffer)) { // Indeed | |
bmpFile.read(sdbuffer, sizeof(sdbuffer)); | |
buffidx = 0; // Set index to beginning | |
} | |
b = sdbuffer[buffidx++]; //blue first | |
g = sdbuffer[buffidx++]; // then green | |
r = sdbuffer[buffidx++]; // then red | |
leds[(row*30)+col] = CRGB(g,r,b); // set led | |
} // end pixel | |
} // end scanline | |
} // end goodBmp | |
} | |
} | |
bmpFile.close(); // close file | |
if(!goodBmp) { | |
} else { | |
LEDS.show(); | |
if(lc==10){ | |
lc = 0; | |
checkSecond(); | |
} | |
} | |
} | |
bmpFile2.close(); | |
} | |
/// These bits are not mine, from somewhere.... | |
uint16_t read16(File f) { | |
uint16_t result; | |
((uint8_t *)&result)[0] = f.read(); // LSB | |
((uint8_t *)&result)[1] = f.read(); // MSB | |
return result; | |
} | |
uint32_t read32(File f) { | |
uint32_t result; | |
((uint8_t *)&result)[0] = f.read(); // LSB | |
((uint8_t *)&result)[1] = f.read(); | |
((uint8_t *)&result)[2] = f.read(); | |
((uint8_t *)&result)[3] = f.read(); // MSB | |
return result; | |
} | |
/// I've left the next in just incase you need to debug in some way | |
// The serial monitor seems to be broken when running this script | |
//void //writeLog(String debug){ | |
// File myLog = SD.open("MyLog.txt", FILE_WRITE); | |
//if(myLog){ | |
// char buffer[2]; | |
// itoa(iHour,buffer,10); | |
// myLog.print(itoa(iHour,buffer,10)); | |
// myLog.print(":"); | |
// myLog.print(itoa(iMinute,buffer,10)); | |
// myLog.print(":"); | |
// myLog.print(itoa(iSecond,buffer,10)); | |
// myLog.print(" --- "); | |
// myLog.println(debug); | |
// myLog.print("freeMemory()="); | |
// myLog.println(freeMemory()); | |
//} | |
//myLog.close(); | |
// | |
//delay(500); | |
//} | |
//void memCheck(){ | |
// char buff[5] =" "; | |
// | |
// itoa(freeMemory(),buff,10); | |
// showStillText(buff); | |
//} | |
//void showMem(){ | |
// Serial.print("freeMemory()="); | |
// Serial.println(freeMemory()); | |
//} | |
//////// Text rendering explaination | |
/* The display is ten pixels high, so for a character there is a width that is dependent on the character width, these are refered | |
to in this script as columns. Each column has ten pixels. This script uses values between 0 and 1024 to indicate which pixels should | |
be lit. 1024 is a sort of Nul terminator, so when this is read in, the functions leave a gap and move to the next character | |
A lower case 'i' has { 250 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 , 1024 } | |
2+8+16+32+64+128 = 250 | |
An uppercase 'N' is { 508 , 2 , 2 , 2 , 508 , 1024 , 1024 , 1024 } | |
4+8+16+32+64+128+256 = 508 | |
0001 | |
0002 X XXX | |
0004 X X | |
0008 X X X | |
0016 X X X | |
0032 X X X | |
0064 X X X | |
0128 X X X | |
0256 X X | |
0512 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment