Skip to content
Snippets Groups Projects
Commit 23ce6d6e authored by abivarma.kandiah's avatar abivarma.kandiah
Browse files

Merge branch 'mqtt_receive' into 'master'

Merge ESP code to master

See merge request !2
parents e12f38aa db046456
Branches
No related tags found
1 merge request!2Merge ESP code to master
#include <WiFi.h>
#include <PubSubClient.h>
#include <HardwareSerial.h>
#define MATRIX_SIZE 10 // 10x10
#define IMG_DATA_SIZE MATRIX_SIZE * MATRIX_SIZE * 3 //DATA SIZE FOR ONE MATRIX = RGB * MATRIX_SIZE
#define BUFFER_SIZE 128
#define CLUSTER "cluster1"
// WiFi
const char *ssid = "uni-ete2"; // Enter your WiFi name
const char *password = "uni-ete2-esp32"; // Enter WiFi password
// MQTT Broker
const char *mqtt_broker = "192.168.1.101";
const char *topic_send = "fromesp";
const char *topic_img = CLUSTER"/image";
const char *topic_txt = CLUSTER"/text";
const char *topic_size = CLUSTER"/size";
const int mqtt_port = 1883;
// WIFI & MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// UART2
HardwareSerial SerialPort(2); // use UART2
char rcv_buffer[BUFFER_SIZE] = {0};
// MATRIX CLUSTER SIZE
uint8_t cluster_size_x = 1;
uint8_t cluster_size_y = 1;
/**
*@brief
Setup all the peripherals of the ESP32 (UART2 & Software serial).
It will connect automatically to an Hardcoded wifi router,
then it will connect with the MQTT broker.
Finally it will publish a message to the topic,
and will subscribe to the needed sub-topic.
*@params
void
*@return
void
*/
void setup()
{
// Set software serial baud to 115200;
Serial.begin(115200);
// Set UART2 serial
SerialPort.begin(115200, SERIAL_8N1, 16, 17); // RX pin: 16, TX pin: 17
// Connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the Wi-Fi network");
// Connecting to a mqtt broker
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
client.setBufferSize(2000);
while (!client.connected())
{
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str());
if (client.connect(client_id.c_str()))
{
Serial.println("Public EMQX MQTT broker connected");
} else
{
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// Publish and subscribe
client.publish(topic_send, "Hi, I'm ESP32 ^^");
client.subscribe(topic_img);
client.subscribe(topic_txt);
}
/**
*@brief
Send an UART message in Pin TX 17 from UART2.
The message will follow the Hepialight2 custom UART format.
Format :
Header : [0x77]
Len : [0x01-0xFF]
Data[0] : [0x00-0xFF]
Data[n] : [0x00-0xFF]
Crc : [0x00-0xFF] = Data[0] ^ Data[1] ^ Data[n] ^ Len
Footer : [0xAA]
*@params
data : data to send to the Hepialight2
length : length of the data
*@return
void
*/
void send_uart_data(const char* data, uint8_t lenght)
{
// SEND UART PACKET HEADER
SerialPort.print((char)0x77);
SerialPort.print((char)lenght);
// SEND DATA AND COMPUTE CRC
uint8_t crc = 0;
for(int i = 0; i < lenght; i++)
{
if(data[i] == 0x77 || data[i] == 0x10 || data[i] == 0xAA)
{
crc = crc ^ 0x10;
SerialPort.print((char)0x10);
}
crc = crc ^ data[i];
SerialPort.print((char)data[i]);
}
// SEND UART PACKET FOOTER
SerialPort.print((char)(crc ^ lenght));
SerialPort.print((char)0xAA);
}
/**
*@brief
Receive an UART message in Pin RX 17 from UART2.
The received message should follow the Hepialight2 custom UART format.
Format :
Header : [0x77]
Len : [0x01-0xFF]
Data[0] : [0x00-0xFF]
Data[n] : [0x00-0xFF]
Crc : [0x00-0xFF] = Data[0] ^ Data[1] ^ Data[n] ^ Len
Footer : [0xAA]
*@params
received_buffer : Will fill the bufeer with
a null-terminated string with the received data
*@return
void
*/
void receive_uart_data(char* received_buffer)
{
static bool receiving_data = false; // Indicator for data reception
static uint8_t buffer[BUFFER_SIZE]; // Receive buffer
static int buffer_index = 0; // Current buffer index
static int message_length = 0; // Length of the currently received message
static uint8_t expected_crc = 0; // Expected CRC
uint8_t received_crc = 0;
bool ctrl_byte = false;
while(SerialPort.available())
{
uint8_t received_byte = SerialPort.read();
switch(received_byte)
{
case 0x77:
// IF 0x10 just before
if(ctrl_byte)
{
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
continue;
}
// UART HEADER
buffer_index = 0;
receiving_data = false;
break;
case 0xAA:
// IF 0x10 just before
if(ctrl_byte)
{
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
continue;
}
// UART HEADER
receiving_data = false;
if(expected_crc == received_crc)
{
memcpy(received_buffer, buffer, message_length);
buffer[buffer_index] = 0;
return;
}
break;
case 0x10:
// IF 0x10 just before
if(!ctrl_byte)
{
ctrl_byte = true;
continue;
}
// DATA
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
break;
default:
// DATA LEN
if(!receiving_data)
{
message_length = received_byte;
expected_crc = received_byte; // Expected CRC is initialized with the message length
receiving_data = true;
continue;
}
// DATA
// GET MESSAGE CRC
if(buffer_index == message_length)
{
received_crc = received_byte;
continue;
}
// Store message bytes in the buffer
buffer[buffer_index++] = received_byte;
expected_crc ^= received_byte; // Calculate expected CRC
break;
}
}
}
/**
*@brief
Convert the 2d index to a 1d index.
*@params
x : x index on a 2d space.
x : y index on a 2d space.
pitch : the lenght of the 2d space.
*@return
int : 1d array index
*/
int d2_to_flat(uint8_t x, uint8_t y, uint32_t pitch)
{
return (x * pitch) + y;
}
/**
*@brief
Remove the header from the ppm image received from
a mqtt message.
*@params
packet : mqtt packet data that contains the ppm image.
lenght : length of the packet data.
*@return
uint8_t* : returns the mqtt packet pointer offset by the header.
*/
uint8_t* remove_header_from_ppm(uint8_t* packet, unsigned int* length)
{
int cnt = 0;
for(int i = 0; i < *length; i++)
{
if(packet[i] == '\n')
{
cnt++;
}
if(cnt >= 3)
{
*length -= i - 1;
return packet + i + 1;
}
}
return NULL;
}
/**
*@brief
Send the received ppm image to the Hepialight 2 by UART2.
The hepialight2 is adressed by his ID on a 2d space (Example : (0, 0)).
The 24 bits RGB data are refactored in 16 bits data (Hepialigt2 buffer size is limited).
R : 8 bits -> 5 bits
G : 8 bits -> 6 bits
B : 8 bits -> 5 bits
*@params
idx : Hepialight matrix ID-x.
idy : Hepialight matrix ID-y.
data : PPM image data (without PPM header).
lenght : length of the data.
*@return
void
*/
void send_data_to_matrix(uint8_t idx, uint8_t idy, uint8_t* data, uint32_t length)
{
uint8_t raw_data[220];
char header[] = "PT;x,y;IMAGE;";
strcpy((char*)raw_data, header);
raw_data[3] = '0' + idx;
raw_data[5] = '0' + idy;
uint8_t send_len = 13;
// RGB DATA PROCESS
// HARDCODED
for(int x = (cluster_size_y - 1 - idy) * 10; x < (cluster_size_y - idy) * 10; x+=1)
{
for(int y = idx * 30; y < (idx+1) * 30; y+=3)
{
// Serial.println()
int i = d2_to_flat(x, y, 30 * cluster_size_y);
// COMPUTE COLOR IN 16 BITS
uint8_t r = data[i] & 0x1F;
uint8_t g = data[i+1] & 0x3F;
uint8_t b = data[i+2] & 0x1F ;
uint16_t rgb = r << 11 | g << 5 | b;
// SPLIT ON 8 BITS
uint8_t rgb_0 = rgb >> 8;
uint8_t rgb_1 = rgb & 0xFF;
// SEND RGB
raw_data[send_len++] = rgb_0;
raw_data[send_len++] = rgb_1;
}
}
// SEND UART PACKET HEADER
send_uart_data((char*)raw_data, send_len);
}
/**
*@brief
Callback function called when the ESP32 receive a mqtt packet.
Only when the ESP32 is subscribed to the right topic.
*@params
topic : The concerned topic.
payload : Received packet.
data : length of the received packet.
*@return
void
*/
void callback(char *topic, byte *payload, unsigned int length)
{
// TERMINAL SERIAL
Serial.print("Message arrived in topic: ");
Serial.println(topic);
if(strcmp(topic, topic_txt) == 0)
{
char data[100];
char header[] = "PT;0,0;MOVING;16711680;0.1;";
memcpy(data, header, strlen(header) + 1);
// MATRIX ID
data[3] = '0' + cluster_size_x - 1;
data[5] = '0';
strncat(data, (char*)payload, length);
uint32_t len = strlen(data);
// SEND UART PACKET HEADER
SerialPort.print((char)0x77);
SerialPort.print((char)len);
uint8_t crc = 0;
for(int i = 0; i < len; i++)
{
if(data[i] == 0x77 || data[i] == 0x10 || data[i] == 0xAA)
{
crc = crc ^ 0x10;
SerialPort.print((char)0x10);
}
crc = crc ^ data[i];
SerialPort.print((char)data[i]);
}
// SEND UART PACKET FOOTER
SerialPort.print((char)(crc ^ len));
SerialPort.print((char)0xAA);
return;
}
// GET RAW DATA
uint8_t* raw_data = remove_header_from_ppm(payload, &length);
if(raw_data == NULL)
{
return;
}
// SEND UART PACKET FOR EACH MATRIX
for(int x_mat = 0; x_mat < cluster_size_x; x_mat++)
{
for(int y_mat = cluster_size_y - 1; y_mat >= 0; y_mat--)
{
// SEND UART PACKET
send_data_to_matrix(x_mat, y_mat, raw_data, IMG_DATA_SIZE);
}
}
}
/**
*@brief
Main loop. Handle the mqtt callback function.
When the ESP32 receive a "ESP" UART message, it will respond "OK".
When the ESP32 receive a "MATSIZE" message,
it will update the hepialight2 cluster size
and will publish to the /size subtopic to signal the broker.
*@params
idx : Hepialight matrix ID-x
idy : Hepialight matrix ID-y
data : PPM image data (without PPM header)
lenght : length of the data.
*@return
void
*/
void loop()
{
client.loop();
receive_uart_data(rcv_buffer); // READ UART BUFFER
// CHECK PRESENCE FROM HEPIALIGHT
if(strcmp(rcv_buffer, "ESP") == 0)
{
Serial.println(rcv_buffer);
rcv_buffer[0] = 0; // CLEAR BUFFER
send_uart_data("OK", 2); // SEND OK
}
// SET MATRIX SIZE
if(strncmp(rcv_buffer, "MATSIZE", 7) == 0)
{
Serial.println(rcv_buffer);
// GET CLUSTER SIZE
cluster_size_x = (rcv_buffer[8] + 1) - '0';
cluster_size_y = (rcv_buffer[10] + 1) - '0';
rcv_buffer[0] = 0; // CLEAR BUFFER
// PUBLISH NEW CLUSTER SIZE
char clust_size[20];
char clust_y[10];
itoa(cluster_size_x*10, clust_size, 10);
int i_0 = strlen(clust_size);
clust_size[i_0] = 'x';
clust_size[i_0+1] = 0;
itoa(cluster_size_y*10, clust_y, 10);
strcat(clust_size, clust_y);
client.publish(topic_size, clust_size);
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment