Reputation: 155
I'm attempting to use an ESP32 with Arduino IDE as a RFID door lock. I have everything working as it should, however it is not using both cores of the esp32. This means that my code will continually loop listening for RFID. process as follows:
Poll for RFID card -> If RFID detected pass to Rest API -> If user allowed then open solenoid -> Update Screen to say welcome to username passed from Rest API
Because I am using a delay to hold the mosfet open, it won't update the screen until after the lock has finished. I did experiment putting the update display code above the lock, but this just delayed opening the lock. To do both at the same time I believe I need to use both cores? Unless there is another way?
All of the multicore examples I can find online are using loops. So I can push the polling for RFID card into another task, but how can I call the update screen script? I'm getting pretty confused.
Please find some code extracts below.
This is the loop, just waits for card to be presented
{
if (nfc.tagPresent())
{
readString = "";
NfcTag tag = nfc.read();
String scannedUID = tag.getUidString();
scannedUID.replace(" ", "-");
Serial.println(scannedUID);
restlookup(scannedUID);
}
}
If tag is present, then passed to this procedure:
void restlookup(String UID){
if (client.connect(server, 80)) {
Serial.println("connected");
// Make a HTTP request:
String getReq = "GET /webapi/api/EmpAuth?id=" + UID;
Serial.println(getReq);
client.println(getReq);
client.println();
}
else {
Serial.println("connection failed");
}
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
//Serial.println(c)
}
}
}
display.clearDisplay();
readString.replace("\"", "");
if (readString == "fail"){
// tone(buzzPin, errorfreq);
// delay(timeOn);
// noTone(buzzPin);
// tone(buzzPin, errorfreq);
// delay(timeOn);
// noTone(buzzPin);
display.setCursor(0,30);
display.clearDisplay();
displaytextcent("Not Authorised");
display.display();
delay(2000);
restdisplay();
}
else{
digitalWrite(13, HIGH); //activate mosfet
delay(timeOpen);
digitalWrite(13, LOW); //deactivate mosfet
display.setCursor(0,30);
display.clearDisplay();
displaytextcent("Welcome");
displaytextcent(readString);
display.display();
delay(2000);
restdisplay();
}
}
}
So, my problem is that because everything is sequential, it's not quite as polished as I would like. It works.... but isn't the best.
If anyone has any suggestions I would really appreciate it. I don't have to use two cores, I just can't find a way to get everything to work at the same time.
Thanks
Andrew
Upvotes: 0
Views: 329
Reputation: 11
If this is just a personal project, I would say don't bother. If it works, don't try to fix it. The modifications will cost you more time and braincells than it's worth.
That said, you could improve the project in three main ways:
Instead of polling, try to use interrupts if your RFID module supports it. This will ensure the esp32 is not burning through cpu cycles when it doesn't have to.
Try to implement a sleep-wake mechanism based on interrupt from a button or the RFID itself. It is here that you can use a simple concurrent (separate) task to countdown from a set time since the last wake up and then putting it to sleep again. An even better approach is to use a hardware timer interrupt (again). Sleep+interrupt will make your battery last longer (if applicable) and will overall improve life of the esp32. Note that these alone might take a lot of planning and work depending on experience.
Once it is awake and there is an interrupt that a tag is used, this interrupt needs to be propagated through the RFID query, lookup and the decision making processes. Interrupt callbacks shouldn't do complicated tasks, so you can make as many parallel threads responsible for doing these as you like. The real difficulty is in communication or synchronization between these threads. While setting and polling for variables can be a preferable simple solution, it suffers from the burning through cpu cycles problem. Enter std::condition_variable. A thread can wait on a condition variable, saving cpu resources, until it is notified from another thread. Implementing this will need further planning and engineering. To help that process, there are design patterns that can be used for more modularity, conceptual clarity and efficiency. For your own convenience, if you choose to implement these, I would strongly suggest you use the ESF-IDF codebase with c++ threads and condition_variable instead of arduino framework + freertos.
Good luck in your endeavor.
Upvotes: 1