Created
June 9, 2021 16:00
-
-
Save thankthemaker/b91b47f0e6b773d23a3077e859ea0f72 to your computer and use it in GitHub Desktop.
rESCue OTA only
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Arduino.h" | |
#include <NimBLEDevice.h> | |
#include "esp_ota_ops.h" | |
#include <Preferences.h> | |
#include <ArduinoJson.h> | |
#define SOFTWARE_VERSION_MAJOR 1 | |
#define SOFTWARE_VERSION_MINOR 0 | |
#define SOFTWARE_VERSION_PATCH 0 | |
#define HARDWARE_VERSION_MAJOR 3 | |
#define HARDWARE_VERSION_MINOR 1 | |
#define SERVICE_UUID_ESPOTA "d804b643-6ce7-4e81-9f8a-ce0f699085eb" | |
#define CHARACTERISTIC_UUID_ID "d804b644-6ce7-4e81-9f8a-ce0f699085eb" | |
#define CHARACTERISTIC_UUID_CONF "d804b645-6ce7-4e81-9f8a-ce0f699085eb" | |
#define SERVICE_UUID_OTA "c8659210-af91-4ad3-a995-a58d6fd26145" // UART service UUID | |
#define CHARACTERISTIC_UUID_FW "c8659211-af91-4ad3-a995-a58d6fd26145" | |
#define CHARACTERISTIC_UUID_HW_VERSION "c8659212-af91-4ad3-a995-a58d6fd26145" | |
#define FULL_PACKET 512 | |
#define CHARPOS_UPDATE_FLAG 5 | |
int numberPixelLight = 0; | |
int numberPixelBatMon = 0; | |
int vescId = 0; | |
String authToken = ""; | |
String wifiPassword = ""; | |
String local_name; | |
BLEServer *pServer = NULL; | |
BLEService *pESPOTAService = NULL; | |
BLECharacteristic *pESPOTAIdCharacteristic = NULL; | |
BLECharacteristic *pESPOTAConfCharacteristic = NULL; | |
BLEService *pService = NULL; | |
BLECharacteristic *pVersionCharacteristic = NULL; | |
BLECharacteristic *pOtaCharacteristic = NULL; | |
esp_ota_handle_t otaHandler = 0; | |
bool updateFlag = false; | |
bool readyFlag = false; | |
int bytesReceived = 0; | |
int timesWritten = 0; | |
uint32_t frameNumber = 0; | |
Preferences preferences; | |
struct Config { | |
boolean otaUpdateActive = true; | |
boolean isNotificationEnabled = false; | |
double minBatteryVoltage = 41.0; | |
double maxBatteryVoltage = 50.4; | |
int startSoundIndex = 0; | |
int startLightIndex = 0; | |
int batteryWarningSoundIndex = 406; | |
int batteryAlarmSoundIndex = 402; | |
int startLightDuration = 1000; | |
int idleLightIndex = 0; | |
int lightFadingDuration = 50; | |
int lightMaxBrightness = 100; | |
int lightColorPrimary = 0; | |
int lightColorPrimaryRed = 0; | |
int lightColorPrimaryGreen = 0; | |
int lightColorPrimaryBlue = 0; | |
int lightColorSecondary = 0; | |
int lightColorSecondaryRed = 0; | |
int lightColorSecondaryGreen = 0; | |
int lightColorSecondaryBlue = 0; | |
boolean brakeLightEnabled = true; | |
int brakeLightMinAmp = 4; | |
int numberPixelLight = 32; | |
int numberPixelBatMon = 5; | |
int vescId = 25; | |
String authToken; | |
} config; | |
void readPreferences() { | |
printf("readPreferences: "); | |
preferences.begin("rESCue", true); | |
String json = preferences.getString("config", ""); | |
StaticJsonDocument<1024> doc; | |
deserializeJson(doc, json); | |
Serial.println("readPreferences: " + json); | |
config.otaUpdateActive = doc["otaUpdateActive"] | true; | |
config.isNotificationEnabled = doc["isNotificationEnabled"] | false; | |
config.minBatteryVoltage = doc["minBatteryVoltage"] | 40.0; | |
config.maxBatteryVoltage = doc["maxBatteryVoltage"] | 50.4; | |
config.startSoundIndex = doc["startSoundIndex"] | 107; | |
config.startLightIndex = doc["startLightIndex"] | 1; | |
config.batteryWarningSoundIndex = doc["batteryWarningSoundIndex"] | 406; | |
config.batteryAlarmSoundIndex = doc["batteryAlarmSoundIndex"] | 402; | |
config.startLightDuration = doc["startLightDuration"] | 1000; | |
config.lightColorPrimary = doc["lightColorPrimary"] | 0xFFFFFF; | |
config.lightColorSecondary = doc["lightColorSecondary"] | 0xFF0000; | |
config.idleLightIndex = doc["idleLightIndex"] | 0; | |
config.lightFadingDuration = doc["lightFadingDuration"] | 220; | |
config.lightMaxBrightness = doc["lightMaxBrightness"] | 100; | |
config.brakeLightEnabled = doc["brakeLightEnabled"] | true; | |
config.brakeLightMinAmp = doc["brakeLightMinAmp"] | 4; | |
config.authToken = doc["authToken"] | ""; | |
config.vescId = doc["vescId"] | 25; | |
config.numberPixelLight = doc["numberPixelLight"] | 16; | |
config.numberPixelBatMon = doc["numberPixelBatMon"] | 5; | |
// calculate RGB values for primary and secondary color | |
config.lightColorPrimaryRed = (config.lightColorPrimary >> 16) & 0x0ff; | |
config.lightColorPrimaryGreen = (config.lightColorPrimary >> 8) & 0x0ff; | |
config.lightColorPrimaryBlue = config.lightColorPrimary & 0x0ff; | |
config.lightColorSecondaryRed = (config.lightColorSecondary >> 16) & 0x0ff; | |
config.lightColorSecondaryGreen = (config.lightColorSecondary >> 8) & 0x0ff; | |
config.lightColorSecondaryBlue = config.lightColorSecondary & 0x0ff; | |
preferences.end(); | |
} | |
void savePreferences() { | |
printf("savePreferences: "); | |
preferences.begin("rESCue", false); | |
StaticJsonDocument<1024> doc; | |
doc["otaUpdateActive"] = config.otaUpdateActive; | |
doc["isNotificationEnabled"] = config.isNotificationEnabled; | |
doc["minBatteryVoltage"] = config.minBatteryVoltage; | |
doc["maxBatteryVoltage"] = config.maxBatteryVoltage; | |
doc["startSoundIndex"] = config.startSoundIndex; | |
doc["startLightIndex"] = config.startLightIndex; | |
doc["batteryWarningSoundIndex"] = config.batteryWarningSoundIndex; | |
doc["batteryAlarmSoundIndex"] = config.batteryAlarmSoundIndex; | |
doc["startLightDuration"] = config.startLightDuration; | |
doc["lightColorPrimary"] = config.lightColorPrimary; | |
doc["lightColorSecondary"] = config.lightColorSecondary; | |
doc["idleLightIndex"] = config.idleLightIndex; | |
doc["lightFadingDuration"] = config.lightFadingDuration; | |
doc["lightMaxBrightness"] = config.lightMaxBrightness; | |
doc["brakeLightEnabled"] = config.brakeLightEnabled; | |
doc["brakeLightMinAmp"] = config.brakeLightMinAmp; | |
doc["authToken"] = config.authToken; | |
doc["vescId"] = config.vescId; | |
doc["numberPixelLight"] = config.numberPixelLight; | |
doc["numberPixelBatMon"] = config.numberPixelBatMon; | |
String json = ""; | |
serializeJson(doc, json); | |
Serial.println("savePreferences: " + json); | |
preferences.putString("config", json); | |
preferences.end(); | |
} | |
NimBLEUUID getConfCharacteristicsUuid() { | |
return pESPOTAConfCharacteristic->getUUID(); | |
} | |
class OTACallback: public BLECharacteristicCallbacks { | |
void onWrite(BLECharacteristic *pCharacteristic) { | |
std::string rxData = pCharacteristic->getValue(); | |
if(pCharacteristic->getUUID().equals(getConfCharacteristicsUuid())) { | |
//Serial.println("Write config"); | |
//Serial.println("String " + String(rxData.c_str())); | |
//Serial.println("Length " + String(rxData.length())); | |
std::string str(rxData.c_str()); | |
std::string::size_type middle = str.find('='); // Find position of ',' | |
std::string key = ""; | |
std::string value = ""; | |
if(middle != std::string::npos) { | |
key = str.substr(0, middle); | |
value = str.substr(middle + 1, str.size() - (middle + 1)); | |
} | |
Serial.println(String(key.c_str()) + String("=") + String(value.c_str())); | |
if(key == "numberPixelLight") { | |
config.numberPixelLight = atoi(value.c_str()); | |
} | |
if(key == "numberPixelBatMon") { | |
config.numberPixelBatMon = atoi(value.c_str()); | |
} | |
if(key == "vescId") { | |
config.vescId = atoi(value.c_str()); | |
} | |
if(key == "authToken") { | |
config.authToken = value.c_str(); | |
} | |
if(key == "save") { | |
savePreferences(); | |
delay(100); | |
} | |
} else { | |
if (!updateFlag) { //If it's the first packet of OTA since bootup, begin OTA | |
Serial.println("\nBeginOTA"); | |
const esp_partition_t *partition = esp_ota_get_next_update_partition(NULL); | |
Serial.println("Selected OTA partiton:"); | |
Serial.println("partition label:" + String(partition->label)); | |
Serial.println("partition size:" + String(partition->size)); | |
esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &otaHandler); | |
updateFlag = true; | |
} | |
// if (_p_ble != NULL) { | |
if (rxData.length() > 0) { | |
Serial.print("Got frame " + String(frameNumber)); | |
esp_ota_write(otaHandler, rxData.c_str(), rxData.length()); | |
if (rxData.length() != FULL_PACKET) { | |
esp_ota_end(otaHandler); | |
Serial.println("\nEndOTA"); | |
const esp_partition_t *partition = esp_ota_get_next_update_partition(NULL); | |
if (ESP_OK == esp_ota_set_boot_partition(partition)) { | |
Serial.println("Activate partiton:"); | |
Serial.println("partition label:" + String(partition->label)); | |
Serial.println("partition size:" + String(partition->size)); | |
delay(2000); | |
esp_restart(); | |
} else { | |
Serial.println("Upload Error"); | |
} | |
} | |
} | |
// } | |
delay(5); // needed to give BLE stack some time | |
uint8_t txdata[4] = { (uint8_t)(frameNumber >> 24), (uint8_t)(frameNumber >> 16), (uint8_t)(frameNumber >> 8), (uint8_t)frameNumber}; | |
pCharacteristic->setValue((uint8_t *) txdata, 4); | |
pCharacteristic->notify(); | |
Serial.println(", Ack. frame no. " + String(frameNumber++)); | |
} | |
} | |
}; | |
bool begin(const char* localName = "UART Service") { | |
// Create the BLE Device | |
BLEDevice::init(localName); | |
// Create the BLE Server | |
pServer = BLEDevice::createServer(); | |
// pServer->setCallbacks(new BLECustomServerCallbacks()); | |
// Create the BLE Service | |
pESPOTAService = pServer->createService(SERVICE_UUID_ESPOTA); | |
pService = pServer->createService(SERVICE_UUID_OTA); | |
// Create a BLE Characteristic | |
pESPOTAIdCharacteristic = pESPOTAService->createCharacteristic( | |
CHARACTERISTIC_UUID_ID, | |
NIMBLE_PROPERTY::READ | |
); | |
pESPOTAConfCharacteristic = pESPOTAService->createCharacteristic( | |
CHARACTERISTIC_UUID_CONF, | |
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::WRITE | |
); | |
pVersionCharacteristic = pService->createCharacteristic( | |
CHARACTERISTIC_UUID_HW_VERSION, | |
NIMBLE_PROPERTY::READ | |
); | |
pOtaCharacteristic = pService->createCharacteristic( | |
CHARACTERISTIC_UUID_FW, | |
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::WRITE | |
); | |
pESPOTAConfCharacteristic->setCallbacks(new OTACallback()); | |
pOtaCharacteristic->setCallbacks(new OTACallback()); | |
// Start the service(s) | |
pESPOTAService->start(); | |
pService->start(); | |
// Start advertising | |
pServer->getAdvertising()->addServiceUUID(SERVICE_UUID_ESPOTA); | |
pServer->getAdvertising()->start(); | |
uint8_t hardwareVersion[5] = {HARDWARE_VERSION_MAJOR, HARDWARE_VERSION_MINOR, SOFTWARE_VERSION_MAJOR, SOFTWARE_VERSION_MINOR, SOFTWARE_VERSION_PATCH}; | |
pVersionCharacteristic->setValue((uint8_t*)hardwareVersion, 5); | |
return true; | |
} | |
void setup() { | |
Serial.begin(115200); | |
begin("rESCue OTA Updates"); | |
// Get Partitionsizes | |
size_t ul; | |
esp_partition_iterator_t _mypartiterator; | |
const esp_partition_t *_mypart; | |
ul = spi_flash_get_chip_size(); | |
Serial.print("\nFlash chip size: "); | |
Serial.println(ul); | |
Serial.println("Partition table:"); | |
_mypartiterator = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); | |
while (_mypartiterator != NULL) { | |
_mypart = esp_partition_get(_mypartiterator); | |
printf("Type: %02x SubType %02x Address 0x%06X Size 0x%06X Encryption %i Label %s\r\n", _mypart->type, _mypart->subtype, _mypart->address, _mypart->size, _mypart->encrypted, _mypart->label); | |
_mypartiterator = esp_partition_next(_mypartiterator); | |
} | |
_mypart = esp_ota_get_boot_partition(); | |
printf("Current active partition is %s\r\n", _mypart->label); | |
readPreferences(); | |
} | |
void loop() { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment