Added SpanPoint::send() functionality

Works as expected.

Next Up:  Modify send() logic so that channels are NOT scanned if device is a main HomeSpan hub.
This commit is contained in:
Gregg 2022-09-30 22:20:32 -05:00
parent c819426dec
commit b7317c3b5f
4 changed files with 95 additions and 6 deletions

View File

@ -27,6 +27,7 @@
#include "HomeSpan.h" #include "HomeSpan.h"
#include <mbedtls/sha256.h> #include <mbedtls/sha256.h>
#include <esp_wifi.h>
SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth){ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth){
@ -36,10 +37,16 @@ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int
while(1); while(1);
} }
if(sendSize<0 || sendSize>200 || receiveSize<0 || receiveSize>200 || queueDepth<1 || (sendSize==0 && receiveSize==0)){
Serial.printf("\nFATAL ERROR! Can't create new SpanPoint(\"%s\",%d,%d,%d) - one or more invalid parameters ***\n",macAddress,sendSize,receiveSize,queueDepth);
Serial.printf("\n=== PROGRAM HALTED ===");
while(1);
}
this->sendSize=sendSize; this->sendSize=sendSize;
this->receiveSize=receiveSize; this->receiveSize=receiveSize;
Serial.printf("SpanPoint: Created link to device with MAC Address %02X:%02X:%02X:%02X:%02X:%02X. Send size: %d bytes. Receive size: %d bytes (queue depth=%d).\n", Serial.printf("SpanPoint: Created link to device with MAC Address %02X:%02X:%02X:%02X:%02X:%02X. Send size=%d bytes, Receive size=%d bytes with queue depth=%d.\n",
peerInfo.peer_addr[0],peerInfo.peer_addr[1],peerInfo.peer_addr[2],peerInfo.peer_addr[3],peerInfo.peer_addr[4],peerInfo.peer_addr[5],sendSize,receiveSize,queueDepth); peerInfo.peer_addr[0],peerInfo.peer_addr[1],peerInfo.peer_addr[2],peerInfo.peer_addr[3],peerInfo.peer_addr[4],peerInfo.peer_addr[5],sendSize,receiveSize,queueDepth);
init(); // initialize SpanPoint init(); // initialize SpanPoint
@ -49,7 +56,8 @@ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int
memcpy(peerInfo.lmk, lmk, 16); // set local key memcpy(peerInfo.lmk, lmk, 16); // set local key
esp_now_add_peer(&peerInfo); // add peer to ESP-NOW esp_now_add_peer(&peerInfo); // add peer to ESP-NOW
receiveQueue = xQueueCreate(queueDepth,receiveSize); if(receiveSize>0)
receiveQueue = xQueueCreate(queueDepth,receiveSize);
SpanPoints.push_back(this); SpanPoints.push_back(this);
} }
@ -71,25 +79,84 @@ void SpanPoint::init(const char *password){
memcpy(lmk, hash, 16); // store first 16 bytes of hash for later use as local key memcpy(lmk, hash, 16); // store first 16 bytes of hash for later use as local key
esp_now_set_pmk(hash+16); // set hash for primary key using last 16 bytes of hash esp_now_set_pmk(hash+16); // set hash for primary key using last 16 bytes of hash
esp_now_register_recv_cb(dataReceived); // set callback for receiving data esp_now_register_recv_cb(dataReceived); // set callback for receiving data
esp_now_register_send_cb(dataSent); // set callback for sending data
statusQueue = xQueueCreate(1,sizeof(esp_now_send_status_t)); // create statusQueue even if not needed
setChannelMask(0x3FFE); // default channel mask uses channels 1-13
initialized=true; initialized=true;
} }
/////////////////////////////// ///////////////////////////////
void SpanPoint::setChannelMask(uint16_t mask){
channelMask = mask & 0x3FFE;
channel=0;
for(int i=1;i<=13 && channel==0;i++)
channel=(channelMask & (1<<i))?i:0;
if(channel==0){
Serial.printf("\nFATAL ERROR! SpanPoint::setChannelMask(0x%04X) - one or more invalid parameters ***\n",mask);
Serial.printf("\n=== PROGRAM HALTED ===");
while(1);
}
if(!isHub) // if this is NOT the main HomeSpan device
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); // set the WiFi channel
Serial.printf("ChannelMask=0x%04X => channel=%d\n",channelMask,channel);
}
///////////////////////////////
boolean SpanPoint::get(void *dataBuf){ boolean SpanPoint::get(void *dataBuf){
if(receiveSize==0)
return(false);
return(xQueueReceive(receiveQueue, dataBuf, 0)); return(xQueueReceive(receiveQueue, dataBuf, 0));
} }
/////////////////////////////// ///////////////////////////////
boolean SpanPoint::send(void *data){
if(sendSize==0)
return(false);
esp_now_send_status_t status = ESP_NOW_SEND_FAIL;
for(int c=0;c<13;c++){
if((1<<channel) & channelMask){
for(int i=1;i<=3;i++){
Serial.printf("Sending on channel %d, attempt #%d\n",channel,i);
esp_now_send(peerInfo.peer_addr, (uint8_t *) data, sendSize);
xQueueReceive(statusQueue, &status, pdMS_TO_TICKS(2000));
if(status==ESP_NOW_SEND_SUCCESS)
return(true);
delay(10);
}
}
channel++;
if(channel==14)
channel=1;
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
}
return(false);
}
///////////////////////////////
void SpanPoint::setAsHub(){ void SpanPoint::setAsHub(){
if(SpanPoints.size()>0){ if(SpanPoints.size()>0){
Serial.printf("\nFATAL ERROR! SpanPoint objects created in main hub device must be instantiated AFTER calling homeSpan.begin() ***\n"); Serial.printf("\nFATAL ERROR! SpanPoint objects created in main hub device must be instantiated AFTER calling homeSpan.begin() ***\n");
Serial.printf("\n=== PROGRAM HALTED ==="); Serial.printf("\n=== PROGRAM HALTED ===");
while(1); while(1);
} }
isHub=true; isHub=true;
} }
@ -103,6 +170,9 @@ void SpanPoint::dataReceived(const uint8_t *mac, const uint8_t *incomingData, in
if(it==SpanPoints.end()) if(it==SpanPoints.end())
return; return;
if((*it)->receiveSize==0)
return;
if(len!=(*it)->receiveSize){ if(len!=(*it)->receiveSize){
Serial.printf("SpanPoint Warning! %d bytes received from %02X:%02X:%02X:%02X:%02X:%02X does not match %d-byte queue size\n",len,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],(*it)->receiveSize); Serial.printf("SpanPoint Warning! %d bytes received from %02X:%02X:%02X:%02X:%02X:%02X does not match %d-byte queue size\n",len,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],(*it)->receiveSize);
return; return;
@ -117,3 +187,6 @@ uint8_t SpanPoint::lmk[16];
boolean SpanPoint::initialized=false; boolean SpanPoint::initialized=false;
boolean SpanPoint::isHub=false; boolean SpanPoint::isHub=false;
vector<SpanPoint *> SpanPoint::SpanPoints; vector<SpanPoint *> SpanPoint::SpanPoints;
int SpanPoint::channel;
uint16_t SpanPoint::channelMask;
QueueHandle_t SpanPoint::statusQueue;

View File

@ -60,8 +60,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa
SpanPoint::setAsHub(); SpanPoint::setAsHub();
if(WiFi.getMode()!=WIFI_AP_STA) WiFi.mode(WIFI_AP_STA); // set mode to mixed AP/STA. This does not start any servers, just configures the WiFi radio to ensure it does not sleep (required for ESP-NOW)
WiFi.mode(WIFI_AP_STA); // set mode to mixed AP/STA. This does not start any servers, just configures the WiFi radio to ensure it does not sleep (required for ESP-NOW)
statusLED=new Blinker(statusDevice,autoOffLED); // create Status LED, even is statusDevice is NULL statusLED=new Blinker(statusDevice,autoOffLED); // create Status LED, even is statusDevice is NULL

View File

@ -765,16 +765,25 @@ class SpanPoint {
static boolean initialized; static boolean initialized;
static boolean isHub; static boolean isHub;
static vector<SpanPoint *> SpanPoints; static vector<SpanPoint *> SpanPoints;
static int channel; // WiFi channel (1-13)
static uint16_t channelMask; // channel mask
static QueueHandle_t statusQueue; // queue for communication between SpanPoint::dataSend and SpanPoint::send
static void dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len); static void dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len);
static void init(const char *password="HomeSpan"); static void init(const char *password="HomeSpan");
static void setAsHub(); static void setAsHub();
static void dataSent(const uint8_t *mac, esp_now_send_status_t status) {
xQueueOverwrite( statusQueue, &status );
}
public: public:
SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth=1); SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth=1);
static void setPassword(const char *pwd){init(pwd);}; static void setPassword(const char *pwd){init(pwd);};
static void setChannelMask(uint16_t mask);
boolean get(void *dataBuf); boolean get(void *dataBuf);
boolean send(void *data);
}; };
///////////////////////////////////////////////// /////////////////////////////////////////////////

View File

@ -50,12 +50,20 @@ void setup() {
// homeSpan.enableAutoStartAP(); // homeSpan.enableAutoStartAP();
// homeSpan.setApFunction(myWiFiAP); // homeSpan.setApFunction(myWiFiAP);
homeSpan.enableWebLog(10,"pool.ntp.org","UTC","myLog"); // creates a web log on the URL /HomeSpan-[DEVICE-ID].local:[TCP-PORT]/myLog
homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan");
SpanPoint::setPassword("Hello Thert"); SpanPoint::setPassword("Hello Thert");
dev1=new SpanPoint("AC:67:B2:77:42:20",0,sizeof(message_t)); dev1=new SpanPoint("AC:67:B2:77:42:20",4,0);
dev2=new SpanPoint("7C:DF:A1:61:E4:A8",0,sizeof(message_t)); dev2=new SpanPoint("7C:DF:A1:61:E4:A8",0,sizeof(message_t));
SpanPoint::setChannelMask(0x3FFE);
dev2->setChannelMask(1<<1);
dev2->setChannelMask(1<<3 | 1<<8 | 1<<13);
dev2->setChannelMask(1<<13);
new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments
new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics