https://revspace.nl/index.php?title=MuxMatrix&feed=atom&action=history
MuxMatrix - Revision history
2024-03-28T12:57:51Z
Revision history for this page on the wiki
MediaWiki 1.32.1
https://revspace.nl/index.php?title=MuxMatrix&diff=13684&oldid=prev
Mux at 17:03, 18 June 2017
2017-06-18T17:03:12Z
<p></p>
<table class="diff diff-contentalign-left" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en-GB">
<td colspan="2" style="background-color: #fff; color: #222; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #222; text-align: center;">Revision as of 17:03, 18 June 2017</td>
</tr><tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l463" >Line 463:</td>
<td colspan="2" class="diff-lineno">Line 463:</td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> displaytext('CONNECTED ',0,1)</div></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> displaytext('CONNECTED ',0,1)</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> m = mqtt.Client("muxmatrix", 10)</div></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> m = mqtt.Client("muxmatrix", 10)</div></td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> </del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> --m:on("connect", function(client)</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> -- displaytext("MQTT ON ")</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> --end)</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> </del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> --m:on("offline", function(client)</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> -- displaytext("MQTT OFF ")</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'>−</td><td style="color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><del style="font-weight: bold; text-decoration: none;"> --end)</del></div></td><td colspan="2"> </td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> m:on("message", function(client, topic, message)</div></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> m:on("message", function(client, topic, message)</div></td></tr>
</table>
Mux
https://revspace.nl/index.php?title=MuxMatrix&diff=13683&oldid=prev
Mux: Created page with "{{Project |Name=MuxMatrix |Picture=IMG 6806h.jpg |Omschrijving=Niet van de film |Status=In progress |Contact=Mux }} == De MuxMatrix == Gezien er op Revspace n..."
2017-06-18T17:02:29Z
<p>Created page with "{{Project |Name=MuxMatrix |Picture=IMG 6806h.jpg |Omschrijving=Niet van de film |Status=In progress |Contact=Mux }} == De MuxMatrix == Gezien er op Revspace n..."</p>
<p><b>New page</b></p><div>{{Project<br />
|Name=MuxMatrix<br />
|Picture=IMG 6806h.jpg<br />
|Omschrijving=Niet van de film<br />
|Status=In progress<br />
|Contact=Mux<br />
}}<br />
<br />
== De MuxMatrix ==<br />
<br />
Gezien er op Revspace nog lang niet genoeg LEDs, LED-Matrices en ESP8266/Arduino-gebaseerde dingen te vinden zijn, leek het me een goed idee om eens een 80x32 monochroom waterdicht display te maken. De MuxMatrix - gemaakt door onze Heer en Keizer mux bij de gratie van zijn geniale mechanische, elektronische en programmeerkunsten - trekt alle sensordata van [https://revspace.nl/MQTT MQTT] en geeft dit weer op het display. <br />
<br />
== Constructie ==<br />
<br />
Het hart van dit project is het Baco Army Goods 32x16-pixel rode LED-matrixbord (beschikbaar in 2009-2010), met name bekend van het [https://gathering.tweakers.net/forum/list_message/29939964#29939964 Tweakers.net EL-forum]. Vijf van deze displays zijn ge-daisy-chained tot één groot scherm en aan een Arduino Nano gehangen. Deze microcontroller houdt een buffer van 320 bytes in geheugen die hij zo snel als maar kan het scherm in dauwt. Dit zorgt voor een refresh rates richting de paarhonderd Hz. De buffer kan worden veranderd door simpelweg naar de seriële poort op 115.2kbaud te schrijven; de buffer wordt dan, beginnend bij adres 0, overschreven. Wanneer langer dan 10 msec geen bytes worden gestuurd, wordt de pointer gereset naar 0. De buffer doet automatisch wraparound na 320 bytes.<br />
<br />
De ESP8266 draait NodeMCU 5.1.4 en een lua-programma dat automatisch verbindt met het publieke 2.4GHz netwerk, connect naar onze mosquitto-server en subscribet op /revspace/sensors/#. De ontvangen sensoren worden in een hashmap gegooid en iedere 2 seconden wordt een nieuwe sensorwaarde uit deze lijst gekozen om te displayen. De sensorwaarde wordt dan ongezet in een string, de string wordt via een giga-lookup table met een 8x8 pixel font omgezet in letters in een bitmap in geheugen, de bitmap wordt dan omgezet naar het juiste format voor het scherm en vervolgens wordt de buffer door UART naar de AVR gespoten. Simpel.<br />
<br />
De ESP8266 en AVR worden gevoed vanuit het scherm, dat op 5V draait. Omdat de ESP8266 op 3.3V draait zit er een level shifter tussen de ESP en AVR, en is er een 1117 3.3V spanningsregelaar onder de ESP te vinden. Een ongebruikte pin op de header wordt gebruikt om vanuit de dotmatrices 5V richting de microcontroller en ESP te sturen. De schermen worden gevoed vanuit een 12 parallel geschakelde TP-link 5V/1A voedinkjes die onze beste vriend en consort in het Keizershuis Sebastius heeft meegenomen, en nog steeds in de snoepautomaat te vinden zijn. Al deze voedingen parallel schakelen heeft objectief geen echte reden, anders dan dat het kan en dat dus iemand het moest doen.<br />
<br />
Fysiek zit alles op een frame van 40x40mm t-slotprofiel geklemd, met een polycarbonaat window. <br />
<br />
== ToDo/toekomstige functionaliteit ==<br />
<br />
Meest gewenste functionaliteit is dat er live getekend kan worden op het scherm. Dit is momenteel echter heel lastig te realiseren, omdat op de space MQTT effectief readonly is vanuit human interfaces. (bijv. browser). Dat gezegd hebbende, is het plan om het scherm naar /revspace/muxmatrix/draw te laten luisteren. Wanneer daar een message wordt gedumpt, interpreteert het scherm dit als een base64-encoded monochrome bitmap, decodeert deze en toont dit op het scherm. Dit is nog onvolledig geïmplementeerd, maar de base64-decoding en conversie is al aanwezig in de firmware.<br />
<br />
Verder is wenselijk:<br />
- Een passender font (bijv. 5x7)<br />
- Een diffuser voor het scherm, zodat tekst beter leesbaar wordt (raamfolie is waarschijnlijk voldoende)<br />
- LED-strips om het scherm heen. Het scherm is expres zwevend in het frame geplaatst zodat er meer LEDs langs kunnen schijnen. MEER LEDs!<br />
- impregnering van het laser-gesneden hout en conformal coating op de elektronica<br />
- Meer hotglue<br />
<br />
== Filmpjes! Foto's! ==<br />
<br />
Ik heb een JijBuis-filmpje gemaakt over dit project. Om internationale diplomatieke redenen introduceer ik mijzelf hier niet als Heer en Keizer, hoewel dit feit uiteraard niet ter discussie staat.<br />
<br />
https://www.youtube.com/watch?v=RQCOlsAp9yA<br />
<br />
<gallery><br />
Muxmatrix-elektronica.jpeg<br />
muxmatrix-voeding.jpeg<br />
Muxmatrix-display.jpeg<br />
</gallery><br />
<br />
== Code ==<br />
<br />
Omdat wikipagina's op deze website niet lang genoeg zijn, hier verbatim alle code<br />
<br />
main.c<br />
<pre><br />
/*<br />
* wifi-leddisplay.c<br />
*<br />
* Created: 30-May-17 14:49:30<br />
* Author : Emile<br />
*/ <br />
<br />
/*<br />
<br />
Short explanation of this program:<br />
This AVR receives serial data from an ESP8266 and puts this into a big array. Then it displays<br />
this array on the dotmatrix display every 8ms (~125fps). <br />
<br />
The display routine runs every 1ms, drawing one line every time. 8 lines make a full display.<br />
<br />
The USART is configured to simply put all received bytes into the buffer. It is configured at<br />
76k8 and expects 320 bytes. Theoretically this could sustain 24fps, but in practice the<br />
interrupts do tend to crowd each other out a bit, so be safe and keep it to ~10fps<br />
<br />
The end of a transmission is denoted by at least 10ms of no data. <br />
*/<br />
<br />
#define F_CPU 16000000UL<br />
<br />
#include <util/delay.h><br />
#include <avr/io.h><br />
#include <avr/interrupt.h><br />
<br />
//PORTD<br />
#define LDAT_PIN (1 << 3) //arduino nano D2<br />
#define UDAT_PIN (1 << 2) //D3<br />
#define CLK_PIN (1 << 7) //D7<br />
<br />
//PORTC<br />
#define A0_PIN (1 << 0) //A0<br />
#define A1_PIN (1 << 1) //A1<br />
#define A2_PIN (1 << 2) //A2<br />
<br />
//PORTB<br />
#define STROBE_PIN (1 << 0) //D8<br />
#define OE_PIN (1 << 1) //D9<br />
<br />
//macros<br />
#define CLK_STROBE() PORTD |= CLK_PIN; _delay_us(10); PORTD &= ~CLK_PIN<br />
#define STROBE_STROBE() PORTB &= ~STROBE_PIN; _delay_us(10); PORTB |= STROBE_PIN<br />
<br />
//constants<br />
#define BITMAP_SIZE 340<br />
<br />
//globals<br />
volatile uint8_t i = 0;<br />
uint16_t j = 0;<br />
uint8_t bitmap[BITMAP_SIZE];<br />
uint16_t bmp_i = 0;<br />
<br />
<br />
//prototypes<br />
void init(void);<br />
void drawbitmap(void);<br />
<br />
int main(void)<br />
{<br />
init();<br />
drawbitmap();<br />
/* Replace with your application code */<br />
while (1) <br />
{<br />
PORTB &= ~STROBE_PIN;<br />
for(j = 0; j < 160; j++){<br />
PORTD &= ~(CLK_PIN | LDAT_PIN | UDAT_PIN);<br />
if(bitmap[j + 160] & (1 << i)) PORTD |= LDAT_PIN;<br />
if(bitmap[j] & (1 << i)) PORTD |= UDAT_PIN;<br />
PORTD |= CLK_PIN;<br />
}<br />
PORTB |= STROBE_PIN;<br />
PORTD |= OE_PIN;<br />
PORTC = i;<br />
PORTD &= ~OE_PIN;<br />
if(++i >= 8) i = 0;<br />
}<br />
}<br />
<br />
<br />
void init(void){<br />
DDRD = LDAT_PIN | UDAT_PIN | CLK_PIN;<br />
DDRC = A0_PIN | A1_PIN | A2_PIN;<br />
DDRB = STROBE_PIN | OE_PIN;<br />
<br />
PORTB |= STROBE_PIN;<br />
PORTD |= OE_PIN;<br />
<br />
//setup data timeout timer: 10ms (16MHz/256/625=100Hz)<br />
OCR1A = 625;<br />
TCCR1B = (1 << WGM12) | (1 << CS12); //16MHz/64, CTC<br />
TIMSK1 = (1 << OCIE1A); //enable compare interrupt<br />
<br />
<br />
//setup USART at 115.2kHz (16MHz/(16*(8+1)), 8N0<br />
UCSR0A |= (1 << U2X0); //double baud rate<br />
UCSR0B = (1 << RXCIE0) | (1 << RXEN0); //enable receive and rx interrupt<br />
UBRR0 = 16; //baud rate, see calc above<br />
<br />
sei();<br />
}<br />
<br />
//draw reset bitmap: just a block of 8 red pixels at the top-left<br />
void drawbitmap(void){<br />
for(j = 0; j < 340; j++){<br />
bitmap[j] = 0;<br />
}<br />
bitmap[160] = 0xff;<br />
}<br />
<br />
//fires on each byte reception<br />
ISR(USART_RX_vect){<br />
bitmap[bmp_i++] = UDR0; //store byte<br />
TCNT1 = 0; //reset timeout timer <br />
TIMSK1 = (1 << OCIE1A); //enable compare interrupt<br />
}<br />
<br />
ISR(TIMER1_COMPA_vect){<br />
bmp_i = 0;<br />
TIMSK1 = 0; //disable interrupt<br />
}<br />
</pre><br />
<br />
init.lua<br />
<pre><br />
uart.setup(0, 115200, 8, uart.PARITY_NONE, uart.STOPBITS_1)<br />
<br />
<br />
-- load fonts<br />
dofile('font.lc')<br />
-- load base64 decoding<br />
dofile('base64.lc')<br />
-- load main program<br />
dofile('main.lc')<br />
</pre><br />
<br />
base64.lua<br />
<pre><br />
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de><br />
-- licensed under the terms of the LGPL2<br />
<br />
--local moduleName = ... <br />
--local M = {}<br />
--_G[moduleName] = M<br />
<br />
-- character table string<br />
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'<br />
<br />
-- encoding<br />
function base64enc(data)<br />
return ((data:gsub('.', function(x) <br />
local r,b='',x:byte()<br />
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end<br />
return r;<br />
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)<br />
if (#x < 6) then return '' end<br />
local c=0<br />
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end<br />
return b:sub(c+1,c+1)<br />
end)..({ '', '==', '=' })[#data%3+1])<br />
end<br />
<br />
-- decoding<br />
function base64dec(data)<br />
data = string.gsub(data, '[^'..b..'=]', '')<br />
return (data:gsub('.', function(x)<br />
if (x == '=') then return '' end<br />
local r,f='',(b:find(x)-1)<br />
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end<br />
return r;<br />
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)<br />
if (#x ~= 8) then return '' end<br />
local c=0<br />
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end<br />
return string.char(c)<br />
end))<br />
end<br />
<br />
</pre><br />
<br />
font.lua<br />
<pre><br />
--this function copies the relevant characters of an 8x8 font<br />
--into the display buffer<br />
local font = {<br />
0, 0, 0, 0, 0, 0, 0, 0, <br />
24, 60, 60, 24, 24, 0, 24, 0, <br />
108, 108, 0, 0, 0, 0, 0, 0, <br />
108, 108, 254, 108, 254, 108, 108, 0, <br />
48, 124, 192, 120, 12, 248, 48, 0, <br />
0, 198, 204, 24, 48, 102, 198, 0, <br />
56, 108, 56, 118, 220, 204, 118, 0, <br />
96, 96, 192, 0, 0, 0, 0, 0, <br />
24, 48, 96, 96, 96, 48, 24, 0, <br />
96, 48, 24, 24, 24, 48, 96, 0, <br />
0, 102, 60, 255, 60, 102, 0, 0, <br />
0, 48, 48, 252, 48, 48, 0, 0, <br />
0, 0, 0, 0, 0, 48, 48, 96, <br />
0, 0, 0, 252, 0, 0, 0, 0, <br />
0, 0, 0, 0, 0, 48, 48, 0, <br />
6, 12, 24, 48, 96, 192, 128, 0, <br />
124, 198, 206, 222, 246, 230, 124, 0, <br />
48, 112, 48, 48, 48, 48, 252, 0, <br />
120, 204, 12, 56, 96, 204, 252, 0, <br />
120, 204, 12, 56, 12, 204, 120, 0, <br />
28, 60, 108, 204, 254, 12, 30, 0, <br />
252, 192, 248, 12, 12, 204, 120, 0, <br />
56, 96, 192, 248, 204, 204, 120, 0, <br />
252, 204, 12, 24, 48, 48, 48, 0, <br />
120, 204, 204, 120, 204, 204, 120, 0, <br />
120, 204, 204, 124, 12, 24, 112, 0, <br />
0, 48, 48, 0, 0, 48, 48, 0, <br />
0, 48, 48, 0, 0, 48, 48, 96, <br />
24, 48, 96, 192, 96, 48, 24, 0, <br />
0, 0, 252, 0, 0, 252, 0, 0, <br />
96, 48, 24, 12, 24, 48, 96, 0, <br />
120, 204, 12, 24, 48, 0, 48, 0, <br />
124, 198, 222, 222, 222, 192, 120, 0, <br />
48, 120, 204, 204, 252, 204, 204, 0, <br />
252, 102, 102, 124, 102, 102, 252, 0, <br />
60, 102, 192, 192, 192, 102, 60, 0, <br />
248, 108, 102, 102, 102, 108, 248, 0, <br />
254, 98, 104, 120, 104, 98, 254, 0, <br />
254, 98, 104, 120, 104, 96, 240, 0, <br />
60, 102, 192, 192, 206, 102, 62, 0, <br />
204, 204, 204, 252, 204, 204, 204, 0, <br />
120, 48, 48, 48, 48, 48, 120, 0, <br />
30, 12, 12, 12, 204, 204, 120, 0, <br />
230, 102, 108, 120, 108, 102, 230, 0, <br />
240, 96, 96, 96, 98, 102, 254, 0, <br />
198, 238, 254, 254, 214, 198, 198, 0, <br />
198, 230, 246, 222, 206, 198, 198, 0, <br />
56, 108, 198, 198, 198, 108, 56, 0, <br />
252, 102, 102, 124, 96, 96, 240, 0, <br />
120, 204, 204, 204, 220, 120, 28, 0, <br />
252, 102, 102, 124, 108, 102, 230, 0, <br />
120, 204, 224, 112, 28, 204, 120, 0, <br />
252, 180, 48, 48, 48, 48, 120, 0, <br />
204, 204, 204, 204, 204, 204, 252, 0, <br />
204, 204, 204, 204, 204, 120, 48, 0, <br />
198, 198, 198, 214, 254, 238, 198, 0, <br />
198, 198, 108, 56, 56, 108, 198, 0, <br />
204, 204, 204, 120, 48, 48, 120, 0, <br />
254, 198, 140, 24, 50, 102, 254, 0, <br />
120, 96, 96, 96, 96, 96, 120, 0, <br />
192, 96, 48, 24, 12, 6, 2, 0, <br />
120, 24, 24, 24, 24, 24, 120, 0, <br />
16, 56, 108, 198, 0, 0, 0, 0, <br />
0, 0, 0, 0, 0, 0, 0, 255, <br />
48, 48, 24, 0, 0, 0, 0, 0, <br />
0, 0, 120, 12, 124, 204, 118, 0, <br />
224, 96, 96, 124, 102, 102, 220, 0, <br />
0, 0, 120, 204, 192, 204, 120, 0, <br />
28, 12, 12, 124, 204, 204, 118, 0, <br />
0, 0, 120, 204, 252, 192, 120, 0, <br />
56, 108, 96, 240, 96, 96, 240, 0, <br />
0, 0, 118, 204, 204, 124, 12, 248, <br />
224, 96, 108, 118, 102, 102, 230, 0, <br />
48, 0, 112, 48, 48, 48, 120, 0, <br />
12, 0, 12, 12, 12, 204, 204, 120, <br />
224, 96, 102, 108, 120, 108, 230, 0, <br />
112, 48, 48, 48, 48, 48, 120, 0, <br />
0, 0, 204, 254, 254, 214, 198, 0, <br />
0, 0, 248, 204, 204, 204, 204, 0, <br />
0, 0, 120, 204, 204, 204, 120, 0, <br />
0, 0, 220, 102, 102, 124, 96, 240, <br />
0, 0, 118, 204, 204, 124, 12, 30, <br />
0, 0, 220, 118, 102, 96, 240, 0, <br />
0, 0, 124, 192, 120, 12, 248, 0, <br />
16, 48, 124, 48, 48, 52, 24, 0, <br />
0, 0, 204, 204, 204, 204, 118, 0, <br />
0, 0, 204, 204, 204, 120, 48, 0, <br />
0, 0, 198, 214, 254, 254, 108, 0, <br />
0, 0, 198, 108, 56, 108, 198, 0, <br />
0, 0, 204, 204, 204, 124, 12, 248, <br />
0, 0, 252, 152, 48, 100, 252, 0, <br />
28, 48, 48, 224, 48, 48, 28, 0, <br />
24, 24, 24, 0, 24, 24, 24, 0, <br />
224, 48, 48, 28, 48, 48, 224, 0, <br />
118, 220, 0, 0, 0, 0, 0, 0<br />
}<br />
<br />
<br />
function displaytext(str, xa, ya)<br />
local s = 0<br />
local jx = 0<br />
<br />
strlen = string.len(str)<br />
if strlen > 40 then<br />
strlen = 40<br />
end<br />
for i = 1,strlen do<br />
for j = 1, 8 do<br />
y = ya + math.floor((xa + i - 1) / 10)<br />
x = (xa + i - 1) % 10 + 1<br />
s = string.byte(str,i)<br />
if s < 32 then s = 32 end<br />
if s > 126 then s = 32 end<br />
s = s - 32 <br />
bytebuf[y * 80 + x + j * 10] = font[s * 8 + j]<br />
end<br />
end<br />
bmp2display()<br />
end<br />
</pre><br />
<br />
main.lua<br />
<pre><br />
-- This screen subscribes to /revspace/sensors<br />
-- and displays all sensor values in sequence,<br />
-- about 2 seconds each<br />
<br />
-------------------<br />
-- GLOBALS --<br />
-------------------<br />
local displaybuf = {} --this goes to the display<br />
bytebuf = {} --this contains the decoded base64<br />
--local mqttbuffer = "" --this is received from the mqtt server in base64<br />
local connected = 0<br />
sensors = {}<br />
table_idx = 0<br />
tablelen = 0<br />
<br />
--empty buffer<br />
function clear()<br />
for i=1,320 do<br />
displaybuf[i] = 0<br />
bytebuf[i] = 0<br />
end<br />
end<br />
<br />
clear()<br />
----------------------<br />
-- HELPER FUNCTIONS --<br />
----------------------<br />
<br />
-- converts bitmaps to display format<br />
function bmp2display()<br />
local a = 1<br />
for i = 2, 10, 2 do<br />
for j = 1, 32, 1 do<br />
displaybuf[a] = bytebuf[i + (j - 1) * 10]<br />
a = a + 1<br />
end<br />
end<br />
for i = 1, 9, 2 do<br />
for j = 1, 32, 1 do<br />
displaybuf[a] = bytebuf[i + (j - 1) * 10]<br />
a = a + 1<br />
end<br />
end<br />
end<br />
<br />
-- converts base64 to bytes<br />
function msg2buffer(strin)<br />
local strout = base64dec(strin)<br />
for i=1,320 do<br />
bytebuf[i] = string.byte(strout,i)<br />
end<br />
end<br />
<br />
<br />
<br />
--------------------<br />
-- MAIN SETUP --<br />
--------------------<br />
<br />
-- periodic screen refresh timer<br />
timer1 = tmr.create()<br />
timer1:register(2000,tmr.ALARM_AUTO, function(t)<br />
<br />
-- increment index and wraparound<br />
table_idx = table_idx + 1<br />
if table_idx > tablelen then table_idx = 1 end<br />
<br />
local it = 1<br />
for k,v in pairs(sensors) do<br />
if(it == table_idx) then<br />
clear() <br />
displaytext(string.sub(k,18,-1),0,0)<br />
displaytext(string.sub(v,1,10),0,3)<br />
end<br />
it = it + 1<br />
end <br />
<br />
drawdisplay()<br />
end)<br />
timer1:start()<br />
<br />
function drawdisplay()<br />
uart.write(0,0) --shift display down by 1<br />
for i=1,320 do<br />
local str = tmr.now()<br />
uart.write(0, displaybuf[i])<br />
end<br />
end<br />
<br />
-- wifi setup<br />
wifi.setmode(wifi.STATION)<br />
wifi.sta.config({ssid="revspace-pub-2.4ghz"})<br />
wifi.sta.connect()<br />
<br />
-- display 'not connected'<br />
displaytext('NO CONNECTION',0,1)<br />
<br />
<br />
-- display 'connected' message when it gets an IP<br />
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T)<br />
displaytext('CONNECTED ',0,1)<br />
m = mqtt.Client("muxmatrix", 10)<br />
<br />
--m:on("connect", function(client)<br />
-- displaytext("MQTT ON ")<br />
--end)<br />
<br />
--m:on("offline", function(client)<br />
-- displaytext("MQTT OFF ")<br />
--end)<br />
<br />
m:on("message", function(client, topic, message)<br />
sensors[topic] = message<br />
-- get true size of table<br />
tablelen = 0<br />
for _ in pairs(sensors) do tablelen = tablelen + 1 end <br />
--displaytext('MESSAGE ')<br />
end)<br />
<br />
m:connect("mosquitto.space.revspace.nl", 1883, 0, function(client)<br />
--displaytext("MQTT CONNECT")<br />
client:subscribe({["/revspace/sensors/#"]=0,["/revspace/muxmatrix/draw"]=0}, 0, function(client)<br />
--displaytext("SUBSCRIBED")<br />
connected = 1<br />
end)<br />
end, function(client, reason)<br />
if (reason == mqtt.CONN_FAIL_SERVER_NOT_FOUND) then<br />
displaytext("SERVER OFF",0,0)<br />
elseif(reason == mqtt.CONN_FAIL_NOT_A_CONNACK_MSG) then<br />
displaytext("NO CONNACK",0,0)<br />
elseif(reason == mqtt.CONN_FAIL_DNS) then<br />
displaytext("DNS FAIL ",0,0)<br />
elseif(reason == mqtt.CONN_FAIL_TIMEOUT_RECEIVING) then<br />
displaytext("TIMEOUT RX",0,0)<br />
elseif(reason == mqtt.CONN_FAIL_TIMEOUT_SENDING) then<br />
displaytext("TIMEOUT TX",0,0)<br />
elseif(reason == mqtt.CONNACK_REFUSED_PROTOCOL_VER) then<br />
displaytext("PROTOCOL F",0,0)<br />
elseif(reason == mqtt.CONNACK_REFUSED_ID_REJECTED) then<br />
displaytext("ID REFUSED",0,0)<br />
elseif(reason == mqtt.CONNACK_REFUSED_SERVER_UNAVAILABLE) then<br />
displaytext("UNAVAILABL",0,0)<br />
elseif(reason == mqtt.CONNACK_REFUSED_BAD_USER_OR_PASS) then<br />
displaytext("BAD PWDUSR",0,0)<br />
elseif(reason == mqtt.CONNACK_REFUSED_NOT_AUTHORIZED) then<br />
displaytext("NOAUTH ",0,0)<br />
else<br />
displaytext("UNKNOWNERR",0,0)<br />
end <br />
end) <br />
end)<br />
</pre></div>
Mux