diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..7565249 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,18 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:az-delivery-devkit-v4] +platform = espressif32 +board = az-delivery-devkit-v4 +framework = arduino +lib_deps = + links2004/WebSockets@^2.3.7 + madhephaestus/ESP32Servo@^0.11.0 +monitor_speed = 115200 \ No newline at end of file diff --git a/Sesame-Device.ino b/src/main.cpp similarity index 87% rename from Sesame-Device.ino rename to src/main.cpp index 331f8dd..ce3c56f 100644 --- a/Sesame-Device.ino +++ b/src/main.cpp @@ -13,9 +13,15 @@ #include // To mark used keys as expired #include // To control the servo +// TODO: +// - Handle WiFi disconnect +// - Implement key sharing +// - Configure/diagnose over Bluetooth? /* Settings */ +#define SERIAL_BAUD_RATE 115200 + // The WiFi network to connect to constexpr const char* WIFI_SSID = "MyNetwork"; constexpr const char* WIFI_PWD = "MyPassword"; @@ -60,10 +66,10 @@ constexpr int servoPin = 14; constexpr int servoFrequency = 50; // The microseconds to set the servo to the pressed state -constexpr int PRESS_STATE_INTERVAL = 1550; +constexpr int PRESS_STATE_INTERVAL = 1600; // The microseconds to set the servo to the released state -constexpr int RELEASE_STATE_INTERVAL = 1700; +constexpr int RELEASE_STATE_INTERVAL = 1520; /* Global variables */ @@ -131,7 +137,7 @@ uint16_t indexOfNextUsableKey(); * @param keyIndex The index of the key in the 'keys' array. * @return 0, if the key is unused, else non-zero. */ -uint8_t keyWasAlreadyUsed(uint16_t keyIndex); +bool keyWasAlreadyUsed(uint16_t keyIndex); /** * Marks a key as used @@ -155,7 +161,7 @@ void markAllKeysUnused(); * Compares two keys in constant time * @return 1, if the keys are equal, else 0 */ -uint8_t keysAreEqual(const uint8_t* key1, const uint8_t* key2); +bool keysAreEqual(const uint8_t* key1, const uint8_t* key2); /* Servo management */ @@ -174,15 +180,17 @@ void releaseButton(); /* Logic */ /** - * Send a response event to the server. + * Send a response event to the server and include the next key index. * - * Sends the event type as a single byte representing the raw event type. + * Sends the event type as three byte. * @param event The event type */ void sendResponse(SesameEvent event) { - uint8_t response[1]; + uint8_t response[3]; response[0] = static_cast(event); - webSocket.sendBIN(response, 1); + response[1] = nextKeyIndex >> 8; + response[2] = nextKeyIndex & 0xFF; + webSocket.sendBIN(response, 3); //webSocket.sendTXT(text); Serial.printf("[INFO] Event %d\n", response[0]); } @@ -214,7 +222,7 @@ SesameEvent handleReceivedRequest(const uint8_t* payload, size_t length) { return SesameEvent::InvalidKeyIndex; } if (!keysAreEqual(payload + 2, keys[keyIndex])) { - return SesameEvent::InvalidKeyIndex; + return SesameEvent::InvalidKey; } if (keyWasAlreadyUsed(keyIndex)) { return SesameEvent::KeyAlreadyUsed; @@ -226,6 +234,7 @@ SesameEvent handleReceivedRequest(const uint8_t* payload, size_t length) { nextKeyIndex = keyIndex + 1; // Move servo shouldStartOpening = true; + Serial.printf("[Info] Used key %d\n", keyIndex); return SesameEvent::KeyAccepted; } @@ -271,6 +280,8 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { case WStype_BIN: processReceivedBytes(payload, length); break; + case WStype_PONG: + case WStype_PING: case WStype_ERROR: case WStype_FRAGMENT_TEXT_START: case WStype_FRAGMENT_BIN_START: @@ -286,12 +297,13 @@ void setup() { Serial.setDebugOutput(true); Serial.println("[INFO] Device started"); - markAllKeysUnused(); - Serial.println("[WARN] All keys reset"); + //markAllKeysUnused(); + //Serial.println("[WARN] All keys reset"); ESP32PWM::allocateTimer(pwmTimer); servo.setPeriodHertz(servoFrequency); servo.attach(servoPin); + releaseButton(); Serial.println("[INFO] Servo configured"); Serial.printf("[INFO] Key security: %d bit (%d byte keys)\n", KEY_STRENGTH, KEY_BYTE_COUNT); @@ -306,17 +318,22 @@ void setup() { } Serial.println("[INFO] WiFi connected"); - Serial.printf("[INFO] Opening socket %s%s on port %d\n", SERVER_URL, SERVER_PATH, SERVER_PORT); - + #ifdef USE_SSL + Serial.printf("[INFO] Opening SSL socket %s%s on port %d\n", SERVER_URL, SERVER_PATH, SERVER_PORT); webSocket.beginSSL(SERVER_URL, SERVER_PORT, SERVER_PATH); #else + Serial.printf("[INFO] Opening insecure socket %s%s on port %d\n", SERVER_URL, SERVER_PATH, SERVER_PORT); webSocket.begin(SERVER_URL, SERVER_PORT, SERVER_PATH); #endif webSocket.onEvent(webSocketEvent); // try again every 5000 ms if connection has failed webSocket.setReconnectInterval(SOCKET_RECONNECT_TIME); + + // Creates an EEPROM fake in RAM, which is committed to flash + // The RAM data can be released by calling `EEPROM.end()` + EEPROM.begin(KEY_COUNT); } void loop() { @@ -345,29 +362,31 @@ uint16_t indexOfNextUsableKey() { return 0; } -uint8_t keyWasAlreadyUsed(uint16_t keyIndex) { - return EEPROM.read(keyIndex); +bool keyWasAlreadyUsed(uint16_t keyIndex) { + return EEPROM.read(keyIndex) > 0; } void markKeyUsed(uint16_t keyIndex) { EEPROM.write(keyIndex, 1); + EEPROM.commit(); } void markAllKeysUnused() { for (uint16_t keyIndex = 0; keyIndex < KEY_COUNT; keyIndex += 1) { EEPROM.write(keyIndex, 0); } + EEPROM.commit(); } -uint8_t keysAreEqual(const uint8_t* key1, const uint8_t* key2) { +bool keysAreEqual(const uint8_t* key1, const uint8_t* key2) { uint8_t result = 0; for (uint8_t i = 0; i < KEY_BYTE_COUNT; i += 1) { result |= key1[i] ^ key2[i]; } if (result) { - return 0; + return false; } - return 1; + return true; } /* Servo management */