//Master Location Dashboard.
//The program controls up to 20 devices internally and 15 devices on screen
//It uses the SD card to log data into two different files.
//DataRSSI file contains the RSSI values of the AP devices in the ESPNow channel.
//DataPing file contains the packet latency akcnowledgement time for each one of the data packages sent.
//It keeps track of all the devices connected by verifying that their SSID format matches the costum string.
//The SSID is formatted as TOURNAME:COSTUMERNAME:MAC_ADDRESS. Where TOURNAME is no longer than 6 characters,
//COSTUMERNAME is up to 5 characters and the MAC_ADDRESS is a six touple value.
//The graphical interface supports touch screen input and displays up to 15 devices. It allows the user to select one
//device and display MAC address, costumer name assigned and tour name.
//Finally, the program alerts in case any of the devices losing connection and shows the costumer name it was assigned to.
//NOTE: Performanace improvement remove all the serial print commands.
//This program uses as a basic template the master.ino program from the ESP32\EspNow
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ILI9341.h> // Hardware-specific library
#include <Adafruit_STMPE610.h>
//ESPNow library
#include <esp_now.h>
#include <WiFi.h>
//Tour name. Sample: WAMALL --> Washington Mall
#define TOURNAME "WAMALL"
// Pin definitions for 2.4" TFT FeatherWing vary among boards...
//We could have got away with just the ESP32, but we could have used a ESP8266. Left for future use.
#if defined(ESP8266)
#define TFT_CS 0
#define TFT_DC 15
#define SD_CS 2
#elif defined(ESP32)
#define TFT_CS 15
#define TFT_DC 33
#define SD_CS 14
#endif
#ifdef ESP32
#define STMPE_CS 32
#define TFT_CS 15
#define TFT_DC 33
#define SD_CS 14
#endif
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
#define CHANNEL 4
#define PRINTSCANRESULTS 0
// Global copy of slave
#define NUMSLAVES 20
//Device distance range status constants
#define STATUS_HERE 0
#define STATUS_LOST 1
#define STATUS_CLOSE 2
#define STATUS_FAR 3
//Tailored structure to keep track of the connected devices.
typedef struct nodeData{
String nodeSSID;
String tourName;
String costumerName;
int Status;
int Current_RSSI;
};
//Filename definitions and constants
#define UNIQUE_ID_FILENAME "/FileNameId.txt"
#define FILE_RSSI "/DataRSSI_"
#define FILE_PING "/DataPing_"
#define FILE_EXT ".vis"
bool openSDFlg=false;
bool openRSSIFlg=false;
bool openPingFlg=false;
File fnCounter;
File dataRSSI;
File dataPing;
String fnPing;
String fnRSSI;
int fnCounterId =0; //Automatic incremental file id to generate unique files every time it runs
bool PanicFlag=false; //Alert a device(s) have lost connection
bool ClearDisFlag=false;
bool NeedRefresh = false;
//Costum array data for each device connected
nodeData peerNodeData[NUMSLAVES];
//Internal device connection
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int checkConCounter[NUMSLAVES];
int SlaveCnt = 0;
int PrevSel = 0;
//Instantiation of the display and touch screen interface objects.
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
//Timing variables
unsigned long start =0;
unsigned long startPeer[NUMSLAVES];
unsigned long refreshTime =0;
//Variables that defines the display dimensions.
int rectHeight;
int rectWidth;
int radius;
//Define constants for device status
#define STATUS_UNKNOWN 0
#define STATUS_OK 1
#define STATUS_WARNING 2
#define STATUS_DANGER 3
//Define constants for radio frequency strenght
#define RANGE_OK 45
#define RANGE_WARNING 69
#define RANGE_DANGER 70
//More display constants to grid the screen
#define DISCON_MAX 5
#define GRID_MAX_X 5
#define GRID_MAX_Y 3
#define USE_SCREEN_Y 1
#define USE_SCREEN_DIV 2
//Amount of time to rescan the network
#define REFRESH_THRESHOLD 3000000
//More display variables
int OffsetX=0;
int OffsetY=0;
//Debug control flags. Did not work that well.
#define DEBUG_ESPNOW 1
//#define DEBUG_TS 1
//Device selected flag.
int FlgSelect = 0;
//Function that initializes the file logging.
//Opens an index file that contains the sequential unique counter to be attached to the login filename, to create a unique filename each time the device runs.
void InitLog()
{
if(!SD.begin(SD_CS))
{
Serial.println(F("failed!"));
openSDFlg = false;
}
else
{
uint8_t cardType = SD.cardType();
Serial.println("SD OK");
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
openSDFlg = false;
}
else
{
static uint8_t buf[512];
Serial.println("Check file Exists");
if (SD.exists(UNIQUE_ID_FILENAME))
{
Serial.println("File Exists");
fnCounter = SD.open(UNIQUE_ID_FILENAME);
if (fnCounter)
{
Serial.println("Open File and read");
Serial.println(fnCounter.size());
fnCounter.read(buf,fnCounter.size());
Serial.println(String((char *)buf));
fnCounterId = String((char *)buf).toInt();
Serial.print("Counter: ");
Serial.println(fnCounterId);
fnCounter.close();
fnCounter=SD.open(UNIQUE_ID_FILENAME,FILE_WRITE);
fnCounter.print(String(fnCounterId+1));
fnCounter.close();
}
}
else
{
Serial.println("Create File");
fnCounter = SD.open(UNIQUE_ID_FILENAME,FILE_WRITE);
if (fnCounter)
{
Serial.println("File open for write");
fnCounter.print("0");
fnCounter.close();
}
else
Serial.println("Error");
fnCounterId =0;
}
String tmpStr = FILE_RSSI;
tmpStr.concat(String(fnCounterId));
tmpStr.concat(FILE_EXT);
fnRSSI = tmpStr;
dataRSSI = SD.open(tmpStr,FILE_APPEND);
if (dataRSSI)
{
Serial.println("RSSI ready");
openRSSIFlg = true;
//dataRSSI.print("THIs is atest");
dataRSSI.flush();
}
tmpStr = FILE_PING;
tmpStr.concat(String(fnCounterId));
tmpStr.concat(FILE_EXT);
fnPing = tmpStr;
dataPing = SD.open(tmpStr,FILE_APPEND);
if (dataPing)
{
Serial.print(tmpStr);
Serial.println("Ping ready");
openPingFlg = true;
//dataPing.print("THIs is atest");
dataPing.flush();
}
openSDFlg = true;
}
}
}
//This function cycles the close/open process of the logging files.
//This function is needed due to the flush function now working. The function is call every 3 seconds and dumps the buffer to the files.
void RefreshFiles()
{
dataRSSI.close();
dataRSSI = SD.open(fnRSSI,FILE_APPEND);
if (dataRSSI)
{
Serial.println("RSSI ready");
openRSSIFlg = true;
dataRSSI.flush();
}
else
openPingFlg = false;
dataPing.close();
dataPing = SD.open(fnPing,FILE_APPEND);
if (dataPing)
{
Serial.println("Ping ready");
openPingFlg = true;
dataPing.flush();
}
else
openPingFlg = false;
}
//This function updates the status of the display interface and logs the changes per device.
void UpdateStatus(int Pos,int numTotX,int Status,int offsetPos,bool refreshFile)
{
int PosX = Pos%numTotX;
int PosY = Pos/numTotX;
int startY = rectHeight * offsetPos;
String tmpStr;
switch (Status)
{
case STATUS_UNKNOWN:
tft.fillCircle((PosX*rectWidth)+rectWidth/2,startY + (PosY*rectHeight)+rectHeight/2,radius,ILI9341_WHITE);
peerNodeData[Pos].Status = STATUS_LOST;
if (openRSSIFlg && refreshFile)
{
tmpStr = "Status : ALERT LOST "+peerNodeData[Pos].costumerName+" "+peerNodeData[Pos].nodeSSID+" "+String(micros()/1000);
dataRSSI.println(tmpStr);
dataRSSI.flush();
Serial.print(tmpStr);
}
break;
case STATUS_OK:
tft.fillCircle((PosX*rectWidth)+rectWidth/2,startY + (PosY*rectHeight)+rectHeight/2,radius,ILI9341_GREEN);
peerNodeData[Pos].Status = STATUS_HERE;
if (openRSSIFlg && refreshFile)
{
tmpStr = "Status : Here "+peerNodeData[Pos].costumerName+" "+peerNodeData[Pos].nodeSSID+" "+String(peerNodeData[Pos].Current_RSSI)+" "+String(micros()/1000);
dataRSSI.println(tmpStr);
dataRSSI.flush();
Serial.print(tmpStr);
}
break;
case STATUS_WARNING:
tft.fillCircle((PosX*rectWidth)+rectWidth/2,startY + (PosY*rectHeight)+rectHeight/2,radius,ILI9341_YELLOW);
peerNodeData[Pos].Status = STATUS_CLOSE;
if (openRSSIFlg && refreshFile)
{
tmpStr = "Status : Close "+peerNodeData[Pos].costumerName+" "+peerNodeData[Pos].nodeSSID+" "+String(peerNodeData[Pos].Current_RSSI)+" "+String(micros()/1000);
dataRSSI.println(tmpStr);
dataRSSI.flush();
Serial.print(tmpStr);
}
break;
case STATUS_DANGER:
tft.fillCircle((PosX*rectWidth)+rectWidth/2,startY + (PosY*rectHeight)+rectHeight/2,radius,ILI9341_RED);
peerNodeData[Pos].Status = STATUS_FAR;
if (openRSSIFlg && refreshFile)
{
tmpStr = "Status : Far "+peerNodeData[Pos].costumerName+" "+peerNodeData[Pos].nodeSSID+" "+String(peerNodeData[Pos].Current_RSSI)+" "+String(micros()/1000);
dataRSSI.println(tmpStr);
dataRSSI.flush();
Serial.print(tmpStr);
}
break;
}
tft.fillCircle((PosX*rectWidth)+rectWidth/2,startY + (PosY*rectHeight)+rectHeight/2,radius-4,ILI9341_BLACK);
}
//This function selects the node on the display according to the touch screen cordinates passed.
//The function tries to flush all the commands in the touch screen stack, before returning.
void SelectNode(TS_Point posScreen,int offsetPos)
{
int posX;
int posY;
int pos;
TS_Point p;
int startY = rectHeight * offsetPos;
posX = posScreen.x /rectWidth ;
posY = posScreen.y /rectHeight ;
pos = posX + (posY*GRID_MAX_X);
#ifdef DEBUG_TS
Serial.print("X = "); Serial.print(posScreen.x);
Serial.print("\tY = "); Serial.println(posScreen.y);
Serial.print("PX = "); Serial.print(posX);
Serial.print("\tPY = "); Serial.println(posY);
Serial.print("Pos = "); Serial.print(pos);
Serial.print("\tPrev = "); Serial.println(PrevSel);
#endif
if ((pos >= offsetPos && pos < offsetPos+SlaveCnt) && pos != PrevSel)
{
tft.drawRect((PrevSel%GRID_MAX_X)*rectWidth,startY+(PrevSel/GRID_MAX_X)*rectHeight,rectWidth,rectHeight,ILI9341_WHITE);
tft.drawRect(posX*rectWidth,startY+(posY*rectHeight),rectWidth,rectHeight,ILI9341_BLUE);
PrevSel = pos;
}
if (FlgSelect > 1 && (posScreen.x > tft.width()-rectWidth && posScreen.y > tft.height()-rectHeight))
{
FlgSelect=0;
tft.fillRect(tft.width()-rectWidth,startY+(tft.height()-rectHeight), rectWidth,rectHeight, ILI9341_BLACK);
tft.drawRect(tft.width()-rectWidth,startY+(tft.height()-rectHeight),rectWidth,rectHeight,ILI9341_CYAN);
ClearScreen();
CreateGrid(GRID_MAX_X,GRID_MAX_Y,0);
CreateGrid(GRID_MAX_X,GRID_MAX_Y,3);
}
else
FlgSelect++;
while (ts.touched())
{
p = ts.getPoint();
}
//delay(100);
while (!ts.bufferEmpty())
{
p = ts.getPoint();
}
}
//Creates the grid on the display according to the number of bins to supper per row and column
void CreateGrid(int numNodesHorz, int numNodesVert,int offsetPos)
{
int i,j;
int cx = USE_SCREEN_Y*(tft.height()/USE_SCREEN_DIV)-1;
int startY=0;
rectHeight = cx / numNodesVert;
rectWidth = tft.width() / numNodesHorz;
radius = (((rectHeight < rectWidth)? rectHeight: rectWidth)/2)-2;
startY = rectHeight * offsetPos;
for(i=0;i<numNodesVert;i++)
{
for (j=0;j<numNodesHorz;j++)
{
tft.drawRect(j*rectWidth,startY+(i*rectHeight),rectWidth,rectHeight,ILI9341_WHITE);
tft.fillCircle((j*rectWidth)+rectWidth/2,startY+((i*rectHeight)+rectHeight/2),radius,ILI9341_WHITE);
tft.fillCircle((j*rectWidth)+rectWidth/2,startY+((i*rectHeight)+rectHeight/2),radius-4,ILI9341_BLACK);
}
}
tft.drawRect(tft.width()-rectWidth,tft.height()-rectHeight,rectWidth,rectHeight,ILI9341_CYAN);
}
//This function clear the screen and sets the default values for text.
void ClearScreen()
{
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 2);
tft.setTextColor(ILI9341_WHITE,ILI9341_BLACK);
tft.setTextSize(2);
}
//Refresh the status of the cube, depending on the RSSI value passed.
void RefreshCube(int Pos,int Value,int offsetPos, bool refreshFile)
{
if (Value <= RANGE_OK)
UpdateStatus(Pos,GRID_MAX_X,STATUS_OK,offsetPos,refreshFile);
else if (Value <= RANGE_WARNING)
UpdateStatus(Pos,GRID_MAX_X,STATUS_WARNING, offsetPos,refreshFile);
else if (Value >= RANGE_DANGER)
UpdateStatus(Pos,GRID_MAX_X,STATUS_DANGER,offsetPos,refreshFile);
else
UpdateStatus(Pos,GRID_MAX_X,STATUS_UNKNOWN,offsetPos,refreshFile);
}
//This function runs over the array of devices and check the number of consecutive attempts to connect to the device that went unsuccesfull
void ConfirmConnection(int offsetPos)
{
bool foundDisconnect=false;
for(int i=0;i<SlaveCnt;i++)
{
if (checkConCounter[i] > DISCON_MAX)
{
UpdateStatus(i,GRID_MAX_X,STATUS_UNKNOWN,offsetPos,false);
PanicFlag = true;
foundDisconnect = true;
}
}
if (!foundDisconnect)
{
PanicFlag= false;
ClearDisFlag=false;
if (NeedRefresh)
{
NeedRefresh=false;
ClearScreen();
CreateGrid(GRID_MAX_X,GRID_MAX_Y,0);
CreateGrid(GRID_MAX_X,GRID_MAX_Y,3);
}
}
else
{
String tmpStr="Lost: ";
bool FirstTime=true;
tft.fillRect(0,tft.height()/2, tft.width(),tft.height()/2, ILI9341_BLACK);
tft.setTextColor(ILI9341_RED);
tft.setTextSize(3);
printDisplay(15,"ALERT",0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
for (int i=0;i<SlaveCnt;i++)
{
if (peerNodeData[i].Status == STATUS_LOST)
{
if (!FirstTime)
{
tmpStr.concat(",");
}
FirstTime=false;
tmpStr.concat(peerNodeData[i].costumerName);
}
}
printDisplay(20,tmpStr,0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
delay(200);
if (!ClearDisFlag)
{
ClearScreen();
CreateGrid(GRID_MAX_X,GRID_MAX_Y,0);
ClearDisFlag=true;
NeedRefresh=true;
}
}
}
//Initialize ESPNow protocol
void InitESPNow()
{
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
}
//This function searches in the internal array if the peer is already register
int searchPeer(int peerMAC[])
{
int retValue=-1;
if (SlaveCnt ==0)
retValue=-1;
else
{
int i,j;
bool FlgDifferent = false;
for (i=0;i<SlaveCnt;i++)
{
FlgDifferent = false;
for (j=0;j<6;j++)
{
if (peerMAC[j] != slaves[i].peer_addr[j])
{
FlgDifferent = true;
break;
}
}
if (!FlgDifferent)
{
retValue = i;
break;
}
}
}
return retValue;
}
//This function performs a scan network searching for the devices that match the SSID format.
//If found they are included in the register peers array.
void ScanForSlave() {
int8_t scanResults = WiFi.scanNetworks(false,false,false,500);
if (scanResults == 0) {
#ifdef DEBUG_ESPNOW
Serial.println("No WiFi devices in AP Mode found");
#endif
} else {
#ifdef DEBUG_ESPNOW
Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
#endif
for (int i = 0; i < scanResults; ++i) {
// Print SSID and RSSI for each device found
String SSID = WiFi.SSID(i);
int32_t RSSI = WiFi.RSSI(i);
String BSSIDstr = WiFi.BSSIDstr(i);
#ifdef DEBUG_ESPNOW
if (PRINTSCANRESULTS) {
Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
}
#endif
if (SSID.indexOf(TOURNAME) == 0) {
int mac[6];
int CurPos;
int numMacElem=0;
numMacElem = sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] );
CurPos = searchPeer(mac);
if (CurPos < 0)
{
// SSID of interest
#ifdef DEBUG_ESPNOW
Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
#endif
// Get BSSID => Mac Address of the Slave
if ( 6 == numMacElem ) {
for (int ii = 0; ii < 6; ++ii ) {
slaves[SlaveCnt].peer_addr[ii] = (uint8_t) mac[ii];
}
}
slaves[SlaveCnt].channel = CHANNEL; // pick a channel
slaves[SlaveCnt].encrypt = 0; // no encryption
if ((SlaveCnt) == 0)
tft.setCursor(12+(rectWidth*(SlaveCnt%GRID_MAX_X)),((rectHeight/2)*(SlaveCnt/GRID_MAX_X))+20); //(tft.height()/2) +
else
tft.setCursor(12+(rectWidth*(SlaveCnt%GRID_MAX_X)),((rectHeight)*(SlaveCnt/GRID_MAX_X))+20); //(tft.height()/2) +
RefreshCube(SlaveCnt,-1*RSSI,0,true);
tft.print(-1*RSSI);
checkConCounter[SlaveCnt] = 0;
int FirstInstance = SSID.indexOf(":");
int SecondInstance = SSID.indexOf(":",FirstInstance+1);
peerNodeData[SlaveCnt].nodeSSID = SSID.substring(SecondInstance+1);
peerNodeData[SlaveCnt].tourName = SSID.substring(0,FirstInstance);
peerNodeData[SlaveCnt].costumerName = SSID.substring(FirstInstance+1,SSID.indexOf(":",FirstInstance+1));
peerNodeData[SlaveCnt].Status = STATUS_HERE;
peerNodeData[SlaveCnt].Current_RSSI = RSSI;
SlaveCnt++;
}
else
{
if ((CurPos) == 0)
tft.setCursor(12+(rectWidth*(CurPos%GRID_MAX_X)),((rectHeight/2)*(CurPos/GRID_MAX_X))+20);
else
tft.setCursor(12+(rectWidth*(CurPos%GRID_MAX_X)),((rectHeight)*(CurPos/GRID_MAX_X))+20);
peerNodeData[CurPos].Current_RSSI = RSSI;
RefreshCube(CurPos,-1*RSSI,0,true);
tft.print(-1*RSSI);
checkConCounter[CurPos] = 0;
}
}
}
for(int i=0;i<SlaveCnt;i++)
checkConCounter[i]++;
}
#ifdef DEBUG_ESPNOW
if (SlaveCnt > 0) {
Serial.print(SlaveCnt); Serial.println(" Slave(s) found, processing..");
} else {
Serial.println("No Slave Found, trying again.");
}
#endif
// clean up ram
WiFi.scanDelete();
}
// Check if the slave is already paired with the master.
// If not, pair the slave with master
void manageSlave() {
if (SlaveCnt > 0) {
for (int i = 0; i < SlaveCnt; i++) {
const esp_now_peer_info_t *peer = &slaves[i];
const uint8_t *peer_addr = slaves[i].peer_addr;
Serial.print("Processing: ");
for (int ii = 0; ii < 6; ++ii ) {
Serial.print((uint8_t) slaves[i].peer_addr[ii], HEX);
if (ii != 5) Serial.print(":");
}
Serial.print(" Status: ");
// check if the peer exists
bool exists = esp_now_is_peer_exist(peer_addr);
if (exists) {
// Slave already paired.
Serial.println("Already Paired");
} else {
// Slave not paired, attempt pair
esp_err_t addStatus = esp_now_add_peer(peer);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
} else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW Not Init");
} else if (addStatus == ESP_ERR_ESPNOW_ARG) {
Serial.println("Add Peer - Invalid Argument");
} else if (addStatus == ESP_ERR_ESPNOW_FULL) {
Serial.println("Peer list full");
} else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("Out of memory");
} else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
Serial.println("Peer Exists");
} else {
Serial.println("Not sure what happened");
}
}
}
} else {
// No slave found to process
#ifdef DEBUG_ESPNOW
Serial.println("No Slave found to process");
#endif
}
}
uint8_t data = 0;
// send data
void sendData() {
data++;
for (int i = 0; i < SlaveCnt; i++) {
const uint8_t *peer_addr = slaves[i].peer_addr;
#ifdef DEBUG_ESPNOW
if (i == 0) { // print only for first slave
Serial.print("Sending: ");
Serial.println(data);
}
#endif
esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data));
Serial.print("Send Status: ");
if (result == ESP_OK) {
Serial.println("Success");
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW not Init.");
} else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println("Internal Error");
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
} else {
Serial.println("Not sure what happened");
}
startPeer[i] = micros();
}
}
//Display at the specified position the meesage passed.
void printDisplay(int iPos,String strData,int offsetPos)
{
int startY = rectHeight * offsetPos;
if ((iPos) == 0)
tft.setCursor(12+(rectWidth*(iPos%GRID_MAX_X)),startY+((rectHeight/2)*(iPos/GRID_MAX_X))+20);
else
tft.setCursor(12+(rectWidth*(iPos%GRID_MAX_X)),startY+((rectHeight)*(iPos/GRID_MAX_X))+20);
tft.print(strData);
}
// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
char macStr[18];
int CurPos;
int mac[6];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
for (int i=0;i<6;i++)
mac[i] = mac_addr[i];
CurPos = searchPeer(mac);
unsigned long tmpTime =(micros()-startPeer[CurPos])/1000;
if (status == ESP_NOW_SEND_SUCCESS && !PanicFlag)
{
RefreshCube(15+CurPos,0,0,false);
printDisplay(15+CurPos,String(tmpTime),0);
if (openPingFlg)
{
String tmpStr = "Received OK "+peerNodeData[CurPos].costumerName+" "+peerNodeData[CurPos].nodeSSID+" "+String(peerNodeData[CurPos].Current_RSSI)+" "+String(tmpTime);
dataPing.println(tmpStr);
dataPing.flush();
Serial.print(tmpStr);
}
}
else
{
if (status != ESP_NOW_SEND_SUCCESS)
{
if (openPingFlg)
{
String tmpStr = "Received Failed "+peerNodeData[CurPos].costumerName+" "+peerNodeData[CurPos].nodeSSID+" "+String(peerNodeData[CurPos].Current_RSSI)+" "+String(tmpTime);
dataPing.println(tmpStr);
dataPing.flush();
Serial.print(tmpStr);
}
}
}
#ifdef DEBUG_ESPNOW
Serial.print("Last Packet Sent to: "); Serial.println(macStr);
Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
#endif
}
//Initialize all the components.
void setup() {
memset(slaves, 0, sizeof(slaves));
memset(checkConCounter, 0, sizeof(checkConCounter));
Serial.begin(115200);
//Set device in STA mode to begin with
WiFi.mode(WIFI_STA);
#ifdef DEBUG_ESPNOW
Serial.println("ESPNow/Multi-Slave/Master Example");
Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
#endif
InitESPNow();
esp_now_register_send_cb(OnDataSent);
ts.begin();
tft.begin(); // Initialize screen
ClearScreen();
CreateGrid(GRID_MAX_X,GRID_MAX_Y,0);
CreateGrid(GRID_MAX_X,GRID_MAX_Y,3);
ScanForSlave();
refreshTime = micros();
InitLog();
}
int loopCnt=0;
//Main loop
void loop() {
if (!FlgSelect)
{
// wait for 3seconds to run the logic again
if (micros()-refreshTime > REFRESH_THRESHOLD)
{
ScanForSlave();
refreshTime = micros();
RefreshFiles();
}
if (SlaveCnt > 0) {
manageSlave();
sendData();
}
}
ConfirmConnection(0);
if (ts.touched())
{
TS_Point p = ts.getPoint();
while (!ts.bufferEmpty())
{
p = ts.getPoint();
}
delay(100);
p = ts.getPoint();
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
if (FlgSelect)
{
p = ts.getPoint();
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
SelectNode(p,0);
if (FlgSelect)
{
ClearScreen();
delay(100);
tft.fillRect(tft.width()-rectWidth,tft.height()-rectHeight, rectWidth,rectHeight, ILI9341_CYAN);
String strTempo = "MAC ";
strTempo.concat(peerNodeData[PrevSel].nodeSSID);
printDisplay(0,strTempo,0);
strTempo = "Name: ";
strTempo.concat(peerNodeData[PrevSel].costumerName);
printDisplay(5,strTempo,0);
strTempo = "Tour: ";
strTempo.concat(peerNodeData[PrevSel].tourName);
printDisplay(10,strTempo,0);
}
}
else
{
if (p.x > tft.width()-rectWidth && p.y > tft.height()-rectHeight)
{
if (FlgSelect == 0)
{
FlgSelect++;
tft.fillRect(tft.width()-rectWidth,tft.height()-rectHeight, rectWidth,rectHeight, ILI9341_CYAN);
while (ts.touched())
{
p = ts.getPoint();
}
//delay(100);
while (!ts.bufferEmpty())
{
p = ts.getPoint();
}
}
}
}
}
}
Comments