Skip to content

Instantly share code, notes, and snippets.

@mherweg
Last active August 8, 2017 19:33
Show Gist options
  • Save mherweg/54baf4cb1cfe5066ac396977d6cb84cd to your computer and use it in GitHub Desktop.
Save mherweg/54baf4cb1cfe5066ac396977d6cb84cd to your computer and use it in GitHub Desktop.
firmware for Wifi Enabled LED Display "redshift"
//#include <avr/pgmspace.h>
const uint8_t CHARSET[][5] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // 20 space
{ 0x00, 0x00, 0x5f, 0x00, 0x00 }, // 21 !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // 22 "
{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // 23 #
{ 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // 24 $
{ 0x23, 0x13, 0x08, 0x64, 0x62 }, // 25 %
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // 26 &
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // 27 '
{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, // 28 (
{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, // 29 )
{ 0x14, 0x08, 0x3e, 0x08, 0x14 }, // 2a *
{ 0x08, 0x08, 0x3e, 0x08, 0x08 }, // 2b +
{ 0x00, 0x50, 0x30, 0x00, 0x00 }, // 2c ,
{ 0x08, 0x08, 0x08, 0x08, 0x08 }, // 2d -
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // 2e .
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // 2f /
{ 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 30 0
{ 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 31 1
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 32 2
{ 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 33 3
{ 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 34 4
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 35 5
{ 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 36 6
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 37 7
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 38 8
{ 0x06, 0x49, 0x49, 0x29, 0x1e }, // 39 9
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // 3a :
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // 3b ;
{ 0x08, 0x14, 0x22, 0x41, 0x00 }, // 3c <
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // 3d =
{ 0x00, 0x41, 0x22, 0x14, 0x08 }, // 3e >
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // 3f ?
{ 0x32, 0x49, 0x79, 0x41, 0x3e }, // 40 @
{ 0x7e, 0x11, 0x11, 0x11, 0x7e }, // 41 A
{ 0x7f, 0x49, 0x49, 0x49, 0x36 }, // 42 B
{ 0x3e, 0x41, 0x41, 0x41, 0x22 }, // 43 C
{ 0x7f, 0x41, 0x41, 0x22, 0x1c }, // 44 D
{ 0x7f, 0x49, 0x49, 0x49, 0x41 }, // 45 E
{ 0x7f, 0x09, 0x09, 0x09, 0x01 }, // 46 F
{ 0x3e, 0x41, 0x49, 0x49, 0x7a }, // 47 G
{ 0x7f, 0x08, 0x08, 0x08, 0x7f }, // 48 H
{ 0x00, 0x41, 0x7f, 0x41, 0x00 }, // 49 I
{ 0x20, 0x40, 0x41, 0x3f, 0x01 }, // 4a J
{ 0x7f, 0x08, 0x14, 0x22, 0x41 }, // 4b K
{ 0x7f, 0x40, 0x40, 0x40, 0x40 }, // 4c L
{ 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // 4d M
{ 0x7f, 0x04, 0x08, 0x10, 0x7f }, // 4e N
{ 0x3e, 0x41, 0x41, 0x41, 0x3e }, // 4f O
{ 0x7f, 0x09, 0x09, 0x09, 0x06 }, // 50 P
{ 0x3e, 0x41, 0x51, 0x21, 0x5e }, // 51 Q
{ 0x7f, 0x09, 0x19, 0x29, 0x46 }, // 52 R
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // 53 S
{ 0x01, 0x01, 0x7f, 0x01, 0x01 }, // 54 T
{ 0x3f, 0x40, 0x40, 0x40, 0x3f }, // 55 U
{ 0x1f, 0x20, 0x40, 0x20, 0x1f }, // 56 V
{ 0x3f, 0x40, 0x38, 0x40, 0x3f }, // 57 W
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // 58 X
{ 0x07, 0x08, 0x70, 0x08, 0x07 }, // 59 Y
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // 5a Z
{ 0x00, 0x7f, 0x41, 0x41, 0x00 }, // 5b [
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // 5c backslash
{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, // 5d ]
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // 5e ^
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // 5f _
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // 60 `
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // 61 a
{ 0x7f, 0x48, 0x44, 0x44, 0x38 }, // 62 b
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // 63 c
{ 0x38, 0x44, 0x44, 0x48, 0x7f }, // 64 d
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // 65 e
{ 0x08, 0x7e, 0x09, 0x01, 0x02 }, // 66 f
{ 0x0c, 0x52, 0x52, 0x52, 0x3e }, // 67 g
{ 0x7f, 0x08, 0x04, 0x04, 0x78 }, // 68 h
{ 0x00, 0x44, 0x7d, 0x40, 0x00 }, // 69 i
{ 0x20, 0x40, 0x44, 0x3d, 0x00 }, // 6a j
{ 0x7f, 0x10, 0x28, 0x44, 0x00 }, // 6b k
{ 0x00, 0x41, 0x7f, 0x40, 0x00 }, // 6c l
{ 0x7c, 0x04, 0x18, 0x04, 0x78 }, // 6d m
{ 0x7c, 0x08, 0x04, 0x04, 0x78 }, // 6e n
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // 6f o
{ 0x7c, 0x14, 0x14, 0x14, 0x08 }, // 70 p
{ 0x08, 0x14, 0x14, 0x18, 0x7c }, // 71 q
{ 0x7c, 0x08, 0x04, 0x04, 0x08 }, // 72 r
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // 73 s
{ 0x04, 0x3f, 0x44, 0x40, 0x20 }, // 74 t
{ 0x3c, 0x40, 0x40, 0x20, 0x7c }, // 75 u
{ 0x1c, 0x20, 0x40, 0x20, 0x1c }, // 76 v
{ 0x3c, 0x40, 0x30, 0x40, 0x3c }, // 77 w
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // 78 x
{ 0x0c, 0x50, 0x50, 0x50, 0x3c }, // 79 y
{ 0x44, 0x64, 0x54, 0x4c, 0x44 }, // 7a z
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // 7b {
{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, // 7c |
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // 7d }
{ 0x10, 0x08, 0x08, 0x10, 0x08 }, // 7e ~
{ 0x00, 0x00, 0x00, 0x00, 0x00 } // 7f
};
/*
ESP8266 MQTT
this sketch subscibes 2 MQTT topics:
inTopic = "huette/clubraum/000/redshift/actuators/frame
receive a binary MQTT message and update the whole display
currently: 8 pixel in one byte , 8 x 8 = 64 byte per frame(picture)
later versions: maybe 1 byte per pixel for different level of brightness
inTopic2 = huette/clubraum/000/redshift/actuators/set_pixel
receive a command (ascii)
possible commands:
0-512 #1 (set one pixel)
0-512 #0 (clear one pixel)
text Hello (display Text, max 10 letters)
*/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include "nokia5110_chars.h"
#include "conf.h"
//war:
#define TAKT D5 // D1
#define HIDE D6 // D2
#define DATA D7 // D3
#define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print (x)
#define DEBUG_PRINTDEC(x) Serial.print (x, DEC)
#define DEBUG_PRINTLN(x) Serial.println (x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#endif
#define BIT_S(var,b) ((var&(1<<b))?1:0)
// clear bit
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
// set bit
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
WiFiClient espClient;
PubSubClient client(espClient);
/* position */
uint8_t cursor_x;
uint8_t cursor_y;
int r,g,b;
byte framebuffer[NUMPIXELS];
String stringPixel, stringFrame, stringIntopic ;
// WIP
String scrolltext = " Hello World!";
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
pinMode(DATA, OUTPUT);
pinMode(HIDE, OUTPUT);
pinMode(TAKT, OUTPUT);
Serial.begin(115200);
setup_wifi();
delay(500);
client.setServer(mqtt_server, 1883);
client.subscribe("inTopic");
client.subscribe("inTopic2");
client.setCallback(callback);
stringPixel = String(inTopic2);
stringFrame = String(inTopic);
ArduinoOTA.setHostname("redshift"); // give an name to our module
ArduinoOTA.begin(); // OTA initialization
} //setup
void setup_wifi() {
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
framebuffer[8]=8;
show();
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
framebuffer[8]=4;
show();
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
client.subscribe(inTopic);
client.setCallback(callback);
} //setup_wifi
void set_pixel(int x, int y,int color ){
byte b_index , mybit;
b_index = x/8 + y*8;
mybit = x % 8;
// color= 0 = off, alles andere: on
if (color > 0)
sbi(framebuffer[b_index], mybit);
else
cbi(framebuffer[b_index], mybit);
//Serial.println(b_index);
//Serial.println(mybit);
//Serial.println(image[b_index]);
//Serial.println("-----");
} // set_pixel(x,y,col)
// eindimensional, ueber alle Zeilen
void setPixelColor(int j, char r ){
//nothing todo - it works on all lines
//int x=j%8;
//int y = j/8;
DEBUG_PRINT("setPixelColor:");
DEBUG_PRINTDEC(j);
DEBUG_PRINT(" r:");
DEBUG_PRINTDEC(r);
DEBUG_PRINTLN("");
//DEBUG_PRINTDEC(y);
set_pixel( j, 0 , r );
}
void shiftbyte(byte dat) // wird von show() benutzt
{
unsigned char p;
int i;
p=0x01;
for(i=0;i<8;i++)
{
if (dat & p)
digitalWrite(DATA, 1);
else
digitalWrite(DATA, 0);
digitalWrite(TAKT, 0);
digitalWrite(TAKT, 1);
p<<=1;
}
}
void show()
{
int line,j;
int offset=0;
byte val;
digitalWrite(HIDE, 1) ; //hide
//for (line=0;line<8;line++)
for (line=8;line>=0;line--)
{
//for(j=7;j>=0;j--)
// 8 bytes on each line
for(j=0;j<8;j++)
{
//val=framebuffer[offset]-1; //show inverted
offset=line*8+j;
val=framebuffer[offset];
shiftbyte(val);
}
}
digitalWrite(HIDE, 0); //show
}
void setpixel( byte* payload, unsigned int length){
int splitat;
String s = "";
for(int i = 0; i < length; i++) {
s += (char)payload[i];
// Serial.println((char)payload[i]);
if (isWhitespace((char)payload[i])) {
splitat = i;
i = length;
} //if
} //for
String Numberstring = "";
String Colorstring = "";
for(int i = 0; i < splitat; i++) {
Numberstring += (char) payload[i];
}
for (int i = (splitat + 1); i < length; i++) {
Colorstring += (char) payload[i];
}
//Colorstring contains something like = "#00ff00" or "00ff00"
// you need to convert it to 0,255,0 and insert it to the two calls below
// Am ende Newline.
int intcolors=(int) strtol(&Colorstring[1],NULL,16);
int r = intcolors >> 16;
int g = intcolors >> 8 & 0xFF;
int b = intcolors & 0xFF;
Serial.print("Number:" + Numberstring + " Color:" + Colorstring + " intcolors:");
//Serial.println(intcolors);
if(Numberstring == "text") {
//scrolltext = Colorstring;
//DEBUG_PRINT("scrolltext:");
//DEBUG_PRINTLN(scrolltext);
//scrolltext();
cursor_x=0;
cursor_y=0;
nokia_lcd_write_string(Colorstring.c_str() ,1);
show();
}
if(Numberstring.toInt() == 255) {
for(int i = 0; i < NUMPIXELS; i++) {
if (r == 0)
framebuffer[i]=0;
else
framebuffer[i]=1;
}
show();
}
else {
setPixelColor(Numberstring.toInt(), r );
show(); // This sends the updated pixel color to the hardware.
}
} //setpixel
// ein Frame das binär via MQTT empfangen wurde
// wird in den Frambuffer geschrieben und 1x show() aufgerufen
//
void writeframe(byte* payload, unsigned int length){
//Serial.print("TOPIC=frame");
// 1 pixel = 1 bit , 1 byte = 8 pixel
//write bytes to framebuffer
for (int i = 0; i < (NUMPIXELS) ; i++) {
//Serial.print((char)payload[i]);
//Serial.print(" ");
framebuffer[i] = payload[i];
}
// wenn 1 pixel = 1 byte dann das hier
//write frame to LEDs
// for(int i = 0; i < NUMPIXELS ; i++) {
//Serial.print(" ");
//Serial.print(j);
//Serial.print(":");
//Serial.print(r);
// r = payload[i];
// setPixelColor(i, r );
// }
Serial.println();
show();
} //writeframe
void callback(char* topic, byte* payload, unsigned int length) {
//Serial.print("Message arrived [");
//Serial.print(topic);
//Serial.print("] ");
//Serial.print("length:");
//Serial.print( length );
stringIntopic = String(topic);
if (stringIntopic == stringPixel ){
//Serial.print("TOPIC=setpixel");
setpixel(payload,length);
}
if (stringIntopic == stringFrame ){
writeframe(payload,length);
}
} //callback
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(mqtt_client_id)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish(outTopic, "hello world");
// ... and resubscribe
client.subscribe(inTopic);
client.subscribe(inTopic2);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
} //reconnect
void nokia_lcd_write_char(char code, uint8_t scale)
{
register uint8_t x, y;
for (x = 0; x < 5*scale; x++)
for (y = 0; y < 7*scale; y++)
if (pgm_read_byte(&CHARSET[code-32][x/scale]) & (1 << y/scale))
set_pixel(cursor_x + x, cursor_y + y, 1);
else
set_pixel(cursor_x + x, cursor_y + y, 0);
cursor_x += 5*scale + 1;
if (cursor_x >= 64) {
cursor_x = 0;
//cursor_y += 7*scale + 1;
cursor_y = 0;
}
if (cursor_y >= 10) {
cursor_x = 0;
cursor_y = 0;
}
}
void nokia_lcd_write_string(const char *str, uint8_t scale)
{
while(*str)
nokia_lcd_write_char(*str++, scale);
}
void nokia_lcd_set_cursor(uint8_t x, uint8_t y)
{
cursor_x = x;
cursor_y = y;
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
ArduinoOTA.handle();
delay(10);
// show();
} //loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment