Skip to content

Instantly share code, notes, and snippets.

@delhoume
Created April 9, 2018 08:28
Show Gist options
  • Select an option

  • Save delhoume/2688aa50d798dbb94c9adf8e77f0454b to your computer and use it in GitHub Desktop.

Select an option

Save delhoume/2688aa50d798dbb94c9adf8e77f0454b to your computer and use it in GitHub Desktop.
TPM2.NET protocol handler for esp8266
/*
TPM2.NET protocol handler
Works with Jinx LED software
*/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <FastLED.h>
#include <WiFiManager.h>
#include <Ticker.h>
#define TMP2NET_IN_PORT 65506
#define TMP2NET_OUT_PORT 65442
WiFiUDP udp;
const uint16_t width = 8;
const uint16_t height = 8;
const uint16_t numleds = width * height;
const uint16_t payload = numleds * 3;
const uint8_t packet_start_byte = 0x9c;
const uint8_t packet_type_data = 0xda;
const uint8_t packet_type_cmd = 0xc0;
const uint8_t packet_type_response = 0xaa;
const uint8_t packet_end_byte = 0x36;
const uint8_t packet_response_ack = 0xac;
// maximum udp esp8266 payload = 1460 -> 484 rgb leds per frame (22x22 matrix)
// then you have to use packet numbers and split the payload
const uint16_t expected_packet_size = payload + 7;
uint8_t data[payload];
#if defined(NO_WIFI_MANAGER)
const char *ssid = "";
const char *password = "";
IPAddress local_ip(192, 168, 1, 200);
IPAddress gateway_ip(192, 168, 1, 1);
IPAddress subnet_ip(255, 255, 255, 0);
#endif
// Param for different pixel layouts
// TODO: verify vertical order (if starting from top or bottom)
const bool kMatrixSerpentineLayout = true;
uint16_t XY(uint8_t x, uint8_t y) {
uint16_t i;
if (kMatrixSerpentineLayout == false) {
i = (y * width) + x;
} else {
if (y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (width - 1) - x;
i = (y * width) + reverseX;
} else {
// Even rows run forwards
i = (y * width) + x;
}
}
return i;
}
#define LED_PIN 3
CRGB leds[numleds];
Ticker ticker;
void tick() {
int state = digitalRead(BUILTIN_LED);
digitalWrite(BUILTIN_LED, !state);
}
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
//entered config mode, make led toggle faster
ticker.detach();
ticker.attach(0.2, tick);
}
const CRGB ipalette[3] = {
{ 0, 0, 0}, // black
{ 255, 255, 255}, // white
{ 255, 0, 200 } // pink
};
const uint8_t invader[8][8] PROGMEM = {
{0, 1, 0, 1, 1, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 1, 2, 1, 1, 2, 1, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1, 0, 0},
{0, 1, 1, 0, 0, 1, 1, 0}
};
void displayInvader() {
for (uint8_t y = 0; y < height; ++y) {
for (uint8_t x = 0; x < width; ++x) {
uint8_t idx = pgm_read_byte(&invader[y][x]);
leds[XY(x, y)] = ipalette[idx];
}
}
FastLED.show();
// TODO: display fps on OLED
FastLED.getFPS();
}
void setup() {
Serial.begin(115200);
delay(10);
pinMode(BUILTIN_LED, OUTPUT);
ticker.attach(0.6, tick);
FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, numleds);
FastLED.countFPS();
FastLED.setBrightness(128); // limit power usage for testing
// make the display show something
displayInvader();
#if defined(NO_WIFI_MANAGER)
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// is is necessary ?
WiFi.config(local_ip, gateway_ip, subnet_ip);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
#else
WiFiManager wifiManager;
// wifiManager.resetSettings();
// wifiManager.setDebugOutput(false);
wifiManager.setAPCallback(configModeCallback);
wifiManager.autoConnect("ledmatrix", "ledmatrix");
#endif
ticker.detach();
digitalWrite(BUILTIN_LED, HIGH);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
long rssi = WiFi.RSSI();
// -120 to 0 DBm
// int quality;
// if(rssi <= -100)
// quality = 0;
// else if(rssi >= -50)
// quality = 100;
// else
// quality = 2 * (rssi + 100);
// Serial.print("signal quality:");
// Serial.println(quality);
/*
Android code
private static final int MIN_RSSI = -100;
private static final int MAX_RSSI = -55;
public static final int RSSI_LEVELS = 5;
public static int calculateSignalLevel(int rssi, int numLevels) {
if (rssi <= MIN_RSSI) {
return 0;
} else if (rssi >= MAX_RSSI) {
return numLevels - 1;
} else {
float inputRange = (MAX_RSSI - MIN_RSSI);
float outputRange = (numLevels - 1);
return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
}
}
*/
Serial.print("signal strength: ");
Serial.print(rssi);
Serial.println(" dBm");
udp.begin(TMP2NET_IN_PORT);
}
void sendAck() {
udp.beginPacket(udp.remoteIP(), TMP2NET_OUT_PORT);
udp.write(&packet_response_ack, 1);
udp.endPacket();
}
void fillMatrix() {
for (uint8_t y = 0; y < height; ++y) {
uint8_t *ptr = data + y * 3 * width;
for (uint8_t x = 0; x < width; ++x, ptr += 3) {
leds[XY(x, y)].setRGB(ptr[0], ptr[1], ptr[2]);
}
}
FastLED.show();
}
void fillMatrix(CRGB color) {
// do not care about XY order
for (uint16_t l = 0; l < numleds; ++l) {
leds[l].setRGB(color.r, color.g, color.b);
}
// fill_solid(leds, numleds, color);
FastLED.show();
}
uint32_t frameCounter = 0;
void loop() {
uint16_t packet_size = udp.parsePacket();
// then parse to check
if (udp.read() != packet_start_byte)
return;
// packet type
uint8_t ptype = udp.read();
uint16_t frame_size = (udp.read() << 8) | udp.read();
// skip packet number and number of packets
udp.read();
udp.read();
switch (ptype) {
case packet_type_response:
sendAck();
break;
case packet_type_data: {
if (frame_size != payload)
return;
// TODO: check if Jinx! sends data in snake order
// then code will be much simpler and faster
// TODO: fill the matrix directly, in the (char*)leds array
// udp.read((char*)leds, payload);
// FastLed.show();
udp.read(data, payload);
// now process the data (fill the matrix)
fillMatrix();
++frameCounter;
break;
}
case packet_type_cmd: {
// read the command
uint8_t command;
uint8_t rgb[3];
udp.read(&command, 1); // not used yet
udp.read(rgb, 3);
fillMatrix(CRGB(rgb[0], rgb[1], rgb[2]));
break;
}
}
// skip end byte, maybe not neccessary
udp.read();
}
@Diegorabbia
Copy link

hola , funciona en ws2811 ?

@delhoume
Copy link
Author

It should work with any FastLED supported chipset

@guillelanus
Copy link

hello how are you? could you help me configure it.

@delhoume
Copy link
Author

delhoume commented Mar 25, 2020 via email

@ReynaldoLuis
Copy link

Hola no me funciona con el ESP01. Intenté de mil maneras, se sube, lo configuro y no me anda.

@guillelanus
Copy link

El tamaño de la matrix es de 30 de ancho por 15 de alto. No me prende no siquera un led solo

@delhoume
Copy link
Author

delhoume commented Apr 6, 2020

What might happen is that 30x15x3 is too large for a single UDP packet on esp8266, you have to split the load in rows, I have some sample code on my https://github.com/delhoume/wemos32x32/blob/master/wemos32x32.ino, see loopUDP(), where frames are 32x8x3 (width 32 height 8 and RGB).

The matrix should already work with some fastled sample code. Is the matrix working ?

@ayandeepd1
Copy link

please give more info on WiFiManager.h which library is this github link? also how does this connect to jinx. does the esp and jinx need to connect to same wifi?

@delhoume
Copy link
Author

delhoume commented Aug 3, 2022

it is well known esp8266 https://github.com/tzapu/WiFiManager available in library manager in Arduino IDE
Of course Jinx! and esp8266 must be on the same wifi network, you just have to know the esp8266 IP address and use it in Jinx!

@ayandeepd1
Copy link

thank you for your speedy reply. you are a savior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment