Reputation: 1
Im making a program to auto detecting nodes using esp-now protocol in tree topology. Right now im having a problem in using fsm in the code, here is my code
#include <ESP8266WiFi.h>
#include <espnow.h>
#define MAX_CHILD_NODES 10 // Maximum number of child nodes
bool receive = false;
bool replyBC = false;
unsigned long currentMillis = 0;
unsigned long Checkroot_timer = 0;
unsigned long duration = random(1000, 1500);
// REPLACE WITH RECEIVER MAC Address
uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t rootMacAddress[6]; // MAC address of the root
uint8_t sendBroadcast[6];
enum State {
STATE_1 = 1,
STATE_2 = 2,
STATE_3 = 3
};
struct ChildNode {
uint8_t macAddress[6];
bool isNewest;
bool isConnectedBefore;
bool replySent; // Flag to track if a reply has been sent
};
ChildNode childNodes[MAX_CHILD_NODES]; // Array to store MAC addresses of child nodes
int numChildNodes = 0; // Counter for the number of child nodes
int newestNodeIndex = -1; // Index of the newest node in the childNodes array
State currentState = STATE_1;
void printMacAddress(const uint8_t* mac) {
for (int i = 0; i < 6; ++i) {
if (mac[i] < 0x10) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
if (i < 5) {
Serial.print(":");
}
}
Serial.println();
}
bool isMacAddressSaved(uint8_t* mac) {
for (int i = 0; i < numChildNodes; i++) {
if (memcmp(mac, childNodes[i].macAddress, 6) == 0) {
return true; // MAC address already saved
}
}
return false; // MAC address not saved
}
void printMessage(const uint8_t* incomingData, uint8_t len){
for (int i = 0; i < len; i++) {
Serial.print((char)incomingData[i]);
}
Serial.println();
}
void saveMacAddress(uint8_t* mac) {
bool isConnectedBefore = isMacAddressSaved(mac);
if (numChildNodes < MAX_CHILD_NODES && !isConnectedBefore) {
memcpy(childNodes[numChildNodes].macAddress, mac, 6);
childNodes[numChildNodes].isNewest = true;
if (newestNodeIndex >= 0) {
childNodes[newestNodeIndex].isNewest = false;
}
newestNodeIndex = numChildNodes;
numChildNodes++;
Serial.println("New node connected");
}
else if (isConnectedBefore) {
for (int i = 0; i < numChildNodes; i++) {
if (memcmp(mac, childNodes[i].macAddress, 6) == 0) {
childNodes[i].isConnectedBefore = true;
childNodes[i].replySent = false; // Reset the replySent flag for reconnected nodes
break;
}
}
Serial.println("Node reconnected");
}
}
void sendDataToNewNode(uint8_t* mac, uint8_t* data, uint8_t len) {
Serial.println("Data to Child has Sent");
esp_now_send(mac, data, len);
}
void sendReplyToRoot(uint8_t* mac, uint8_t* data, uint8_t len) {
Serial.println("Reply sent to root");
esp_now_send(mac, data, len);
}
void sendReplyToReconnectedNode() {
if (numChildNodes > 0) {
uint8_t replyData[] = "You have connected before";
for (int i = 0; i < numChildNodes; i++) {
if (childNodes[i].isConnectedBefore && !childNodes[i].replySent) {
sendDataToNewNode(childNodes[i].macAddress, replyData, sizeof(replyData));
childNodes[i].replySent = true; // Set the replySent flag to true
break; // Stop after sending the reply to the first reconnected node
}
}
}
}
void printSavedMacAddresses() {
Serial.println("Saved MAC Addresses:");
for (int i = 0; i < numChildNodes; i++) {
Serial.print("Node ");
Serial.print(i + 1);
Serial.print(": ");
for (int j = 0; j < 6; j++) {
Serial.print(childNodes[i].macAddress[j], HEX);
if (j < 5) {
Serial.print(":");
}
}
Serial.print(" | ");
if (childNodes[i].isConnectedBefore) {
Serial.println("Connected before");
}
else {
Serial.println("New connection");
}
}
}
void broadcast() {
if (!receive) {
uint8_t dataToSend[] = "SAYA NEW NODE";
esp_now_send(broadcastAddress, dataToSend, sizeof(dataToSend));
}
delay(5000);
}
void OnDataSent(uint8_t *mac, uint8_t sendStatus) {
Serial.print("Broadcast Status: ");
if (sendStatus == 0) {
Serial.println("Delivery success");
} else {
Serial.println("Delivery fail");
}
}
void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
unsigned long currentMillis = millis();
unsigned long Checkroot_timer = millis();
bool rootCheck = false;
switch(currentState){
case STATE_1:
Serial.print("Ini Case ");
Serial.println(currentState);
Serial.print("Received data from ");
printMacAddress(mac);
Serial.print("Received data: ");
printMessage(incomingData, len);
if (strncmp((char*)incomingData, "SAYA PARENT ANDA", len) == 0) {
memcpy(rootMacAddress, mac, 6);
Serial.println("Root MAC address saved");
receive = true;
currentState = STATE_2;
}
else if (strncmp((char*)incomingData, "You have connected before", len) == 0){
memcpy(rootMacAddress, mac, 6);
Serial.println("Root MAC address saved");
receive = true;
currentState = STATE_2;
}
else if (strncmp((char*)incomingData, "Sudah ada PARENT?", len) == 0){
uint8_t dataToSend[] = "Belum Ada PARENT";
sendReplyToRoot(mac, dataToSend, sizeof(dataToSend));
receive = true;
currentState = STATE_1;
}
else {
currentState = STATE_1;
}
break;
case STATE_2:
Serial.print("Ini Case ");
Serial.println(currentState);
Serial.print("Received data from ");
printMacAddress(mac);
Serial.print("Data: ");
printMessage(incomingData, len);
if (strncmp((char*)incomingData, "SAYA NEW NODE", len) == 0) {
while (millis() - currentMillis <= duration){
}
uint8_t dataToSend[] = "Sudah ada PARENT?";
esp_now_send(mac, dataToSend, sizeof(dataToSend));
currentState = STATE_3;
}
else{
currentState = STATE_2;
break;
}
break;
case STATE_3:
while (millis() - Checkroot_timer <= 1000){
if (strncmp((char*)incomingData, "Belum Ada PARENT", len) == 0){
rootCheck = true;
saveMacAddress(mac);
printSavedMacAddresses();
if (numChildNodes > 0) {
if (childNodes[newestNodeIndex].isConnectedBefore && !childNodes[newestNodeIndex].replySent) {
sendReplyToReconnectedNode();
}
else {
uint8_t dataToSend[] = "SAYA PARENT ANDA";
sendDataToNewNode(mac, dataToSend, sizeof(dataToSend));
}
currentState = STATE_2;
}
}
}
if (rootCheck == false){
Serial.println("No reply");
currentState = STATE_2;
}
break;
}
}
void setup() {
// Init Serial Monitor
Serial.begin(115200);
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
broadcast();
}
for the state diagram looks like this and the PARENT's code it is almost similar to state 3, but without the while()
function
State Diagram
For example, in state 1 at currentState = STATE_2, the program doesnt move to state 2 if there is no new received message. So if there is no new received data the state still in state 1, then if the program receive new data it will go to state 2 and starts to print "Ini Case ". How do I make it so that after current_state = state_2 the program immediately runs state 2?
When I run the code and it in state 1 then currentState = STATE_2, it doesn't immediately runs state 2. It still in state 1 until the program receive new data
Upvotes: 0
Views: 52