Skip to content

Instantly share code, notes, and snippets.

@focalintent
Created December 7, 2015 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save focalintent/17430c45a9ca4d19e979 to your computer and use it in GitHub Desktop.
Save focalintent/17430c45a9ca4d19e979 to your computer and use it in GitHub Desktop.
// 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