Compare commits
8 Commits
bf21b61803
...
1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
ea11640889
|
|||
|
7f8c320b5a
|
|||
|
316fbd7c60
|
|||
|
8d5b663c78
|
|||
|
361424ded3
|
|||
|
e1bbccd755
|
|||
|
f7dd083992
|
|||
|
8a992787df
|
@@ -1,3 +1,3 @@
|
|||||||
# OTALibrary
|
# BLEOTA
|
||||||
|
|
||||||
The library for the micro controller to update its software Over The Air.
|
A library for esp32 Over the Air updates using BLE.
|
||||||
21
library.json
Normal file
21
library.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "BLEOTA",
|
||||||
|
"description": "A library for esp32 Over the Air updates using BLE",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.emaker.limited:MicrocontrollerCD/BLEOTA.git"
|
||||||
|
},
|
||||||
|
"authors":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "chopster44",
|
||||||
|
"email": "me@chopster44.com",
|
||||||
|
"maintainer": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "0.0.1",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": ["espressif32"],
|
||||||
|
"headers": ["BLEOTA.h"]
|
||||||
|
}
|
||||||
179
src/BLEOTA.cpp
Normal file
179
src/BLEOTA.cpp
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#include "BLEOTA.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
MAIN CLASS
|
||||||
|
*/
|
||||||
|
|
||||||
|
BLEOTAClass::BLEOTAClass()
|
||||||
|
: pVersionNumber_(new BLECharacteristic(VERSION_NUMBER_UUID, BLECharacteristic::PROPERTY_READ)),
|
||||||
|
pVersionNumberDescriptor_(new BLEDescriptor(VERSION_NUMBER_DESCRIPTOR_UUID)),
|
||||||
|
pOTACommand_(new BLECharacteristic(OTA_COMMAND_UUID, BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_WRITE)),
|
||||||
|
pOTACommandDescriptor_(new BLEDescriptor(OTA_COMMAND_DESCRIPTOR_UUID)),
|
||||||
|
pOTAFile_(new BLECharacteristic(OTA_FILE_UUID, BLECharacteristic::PROPERTY_WRITE)),
|
||||||
|
pOTAFileDescriptor_(new BLEDescriptor(OTA_FILE_DESCRIPTOR_UUID)) {
|
||||||
|
cmdCallbacks_ = new OTACommandCallbacks(this);
|
||||||
|
fileCallbacks_ = new OTAFileCallbacks(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
void BLEOTAClass::begin(BLEServer* server, char* versionNumber) {
|
||||||
|
// set internal versionNumber
|
||||||
|
vNum_ = versionNumber;
|
||||||
|
// set internal server
|
||||||
|
pServer_ = server;
|
||||||
|
// create service
|
||||||
|
BLEService* otaService = pServer_->createService(OTA_SERVICE_UUID);
|
||||||
|
|
||||||
|
pVersionNumber_->setValue(vNum_);
|
||||||
|
pVersionNumberDescriptor_->setValue("Version Number");
|
||||||
|
pVersionNumber_->addDescriptor(pVersionNumberDescriptor_);
|
||||||
|
|
||||||
|
otaService->addCharacteristic(pVersionNumber_);
|
||||||
|
pOTACommandDescriptor_->setValue("OTA Command");
|
||||||
|
pOTACommand_->addDescriptor(pOTACommandDescriptor_);
|
||||||
|
pOTACommand_->addDescriptor(new BLE2902());
|
||||||
|
pOTACommand_->setCallbacks(cmdCallbacks_);
|
||||||
|
otaService->addCharacteristic(pOTACommand_);
|
||||||
|
|
||||||
|
pOTAFileDescriptor_->setValue("OTA File");
|
||||||
|
pOTAFile_->addDescriptor(pOTAFileDescriptor_);
|
||||||
|
pOTAFile_->setCallbacks(fileCallbacks_);
|
||||||
|
otaService->addCharacteristic(pOTAFile_);
|
||||||
|
|
||||||
|
otaService->start();
|
||||||
|
setOTAcommand(CMD_ON);
|
||||||
|
state_ = STAGE_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEOTAClass::setOTAcommand(otaCommand cmd) {
|
||||||
|
uint8_t commandBuffer[1] = {};
|
||||||
|
commandBuffer[0] = cmd;
|
||||||
|
pOTACommand_->setValue(commandBuffer, 1);
|
||||||
|
pOTACommand_->notify();
|
||||||
|
currentCommand_ = cmd;
|
||||||
|
Serial.printf("Set command to %d\n", commandBuffer[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEOTAClass::sendFileProgress(uint32_t progress) {
|
||||||
|
uint8_t* commandBuffer = (uint8_t*)malloc(4);
|
||||||
|
commandBuffer[3] = (progress >> 24) & 0xFF;
|
||||||
|
commandBuffer[2] = (progress >> 16) & 0xFF;
|
||||||
|
commandBuffer[1] = (progress >> 8) & 0xFF;
|
||||||
|
commandBuffer[0] = progress & 0xFF;
|
||||||
|
pOTACommand_->setValue(commandBuffer, 4);
|
||||||
|
pOTACommand_->notify();
|
||||||
|
Serial.printf("Sent file progress");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEOTAClass::loop() {
|
||||||
|
if (millis() - lastLoop_ > 2000) {
|
||||||
|
if (state_ == STAGE_ERROR && currentCommand_ != CMD_ERROR) {
|
||||||
|
setOTAcommand(CMD_ERROR);
|
||||||
|
}
|
||||||
|
if (state_ == STAGE_DONE) {
|
||||||
|
// reboot
|
||||||
|
Serial.println("Rebooting");
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
COMMAND CHARACTERISTIC CALLBACKS
|
||||||
|
*/
|
||||||
|
|
||||||
|
// so that the callback has access to the main class
|
||||||
|
BLEOTAClass::OTACommandCallbacks::OTACommandCallbacks(BLEOTAClass* pParent) : pParent_(pParent) {};
|
||||||
|
|
||||||
|
void BLEOTAClass::OTACommandCallbacks::onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) {
|
||||||
|
Serial.println("Recieved cmd");
|
||||||
|
size_t cmdLength = pCharacteristic->getLength();
|
||||||
|
if (cmdLength > 4 && pParent_->state_ == STAGE_READY) {
|
||||||
|
// error
|
||||||
|
Serial.println("Error: command too long");
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
} else if (cmdLength > 1 && pParent_->state_ == STAGE_READY) {
|
||||||
|
// process file size
|
||||||
|
uint8_t* cmdBuffer = pCharacteristic->getData();
|
||||||
|
uint32_t cmd = ((uint32_t)cmdBuffer[3] << 24) |
|
||||||
|
((uint32_t)cmdBuffer[2] << 16) |
|
||||||
|
((uint32_t)cmdBuffer[1] << 8) | (uint32_t)cmdBuffer[0];
|
||||||
|
pParent_->fileSize_ = cmd;
|
||||||
|
// start update
|
||||||
|
if (!Update.begin(pParent_->fileSize_, U_FLASH)) {
|
||||||
|
// error
|
||||||
|
Serial.printf("Error: ");
|
||||||
|
Update.printError(Serial);
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pParent_->state_ = STAGE_FLASHING;
|
||||||
|
pParent_->setOTAcommand(CMD_READY);
|
||||||
|
Serial.println("Starting to flash");
|
||||||
|
} else if (cmdLength == 1) {
|
||||||
|
// process cmd
|
||||||
|
uint8_t cmd = pCharacteristic->getData()[0];
|
||||||
|
if (cmd == otaCommand::CMD_AGREE) {
|
||||||
|
// process agree
|
||||||
|
if (!Update.end()) {
|
||||||
|
// error
|
||||||
|
Serial.println("Error: client and server ready, but Updater is not");
|
||||||
|
Update.printError(Serial);
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
} else {
|
||||||
|
// reboot logic
|
||||||
|
pParent_->state_ = STAGE_DONE;
|
||||||
|
Serial.println("Set reboot flag");
|
||||||
|
}
|
||||||
|
} else if (cmd == CMD_DISAGREE) {
|
||||||
|
// process disagree
|
||||||
|
// start over
|
||||||
|
Update.abort();
|
||||||
|
Serial.println("Aborting update, app disagree");
|
||||||
|
pParent_->fileProgress_ = 0;
|
||||||
|
pParent_->state_ = STAGE_READY;
|
||||||
|
} else {
|
||||||
|
Serial.println("Error: wrong command");
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("Error: command length");
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
FILE CHARACTERISTIC CALLBACKS
|
||||||
|
*/
|
||||||
|
|
||||||
|
// so that the callback has access to the main class
|
||||||
|
BLEOTAClass::OTAFileCallbacks::OTAFileCallbacks(BLEOTAClass* pParent) : pParent_(pParent) {};
|
||||||
|
|
||||||
|
void BLEOTAClass::OTAFileCallbacks::onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) {
|
||||||
|
size_t packetSize = pCharacteristic->getLength();
|
||||||
|
Serial.println("Got packet");
|
||||||
|
if (packetSize == 0) {
|
||||||
|
// problem
|
||||||
|
// output error
|
||||||
|
Serial.println("Error: no packet");
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
} else {
|
||||||
|
// write file to updater
|
||||||
|
uint8_t* filePacket = pCharacteristic->getData();
|
||||||
|
if (Update.write(filePacket, packetSize) != packetSize) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
pParent_->state_ = STAGE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pParent_->fileProgress_ += packetSize;
|
||||||
|
Serial.printf("Packet Size: %d, Progress: %d, Total: %d\n", packetSize, pParent_->fileProgress_, pParent_->fileSize_);
|
||||||
|
if (pParent_->fileProgress_ >= pParent_->fileSize_) {
|
||||||
|
// send done
|
||||||
|
pParent_->setOTAcommand(CMD_DONE);
|
||||||
|
} else {
|
||||||
|
pParent_->sendFileProgress(pParent_->fileProgress_);
|
||||||
|
// pParent_->setOTAcommand(CMD_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLEOTAClass BLEota;
|
||||||
87
src/BLEOTA.h
Normal file
87
src/BLEOTA.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef BLEOTA
|
||||||
|
#define BLEOTA
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
#include <BLE2902.h>
|
||||||
|
#include <Update.h>
|
||||||
|
|
||||||
|
#define OTA_SERVICE_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561900"
|
||||||
|
|
||||||
|
#define VERSION_NUMBER_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561910"
|
||||||
|
#define VERSION_NUMBER_DESCRIPTOR_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561911"
|
||||||
|
|
||||||
|
#define OTA_COMMAND_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561920"
|
||||||
|
#define OTA_COMMAND_DESCRIPTOR_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561921"
|
||||||
|
|
||||||
|
#define OTA_FILE_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561930"
|
||||||
|
#define OTA_FILE_DESCRIPTOR_UUID "71a4438e-fd52-4b15-b3d2-ec0e3e561931"
|
||||||
|
|
||||||
|
class BLEOTAClass {
|
||||||
|
public:
|
||||||
|
BLEOTAClass();
|
||||||
|
void begin(BLEServer* server, char* versionNumber = "1.0.0");
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
enum otaCommand {
|
||||||
|
CMD_ON = 0x00,
|
||||||
|
CMD_READY = 0x01,
|
||||||
|
CMD_DONE = 0x02,
|
||||||
|
CMD_AGREE = 0x03,
|
||||||
|
CMD_DISAGREE = 0x04,
|
||||||
|
CMD_ERROR = 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
enum otaStage {
|
||||||
|
STAGE_READY,
|
||||||
|
STAGE_FLASHING,
|
||||||
|
STAGE_DONE,
|
||||||
|
STAGE_ERROR
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setOTAcommand(otaCommand cmd);
|
||||||
|
void sendFileProgress(uint32_t progress);
|
||||||
|
|
||||||
|
class OTACommandCallbacks : public BLECharacteristicCallbacks {
|
||||||
|
public:
|
||||||
|
OTACommandCallbacks(BLEOTAClass* pParent);
|
||||||
|
void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) override;
|
||||||
|
private:
|
||||||
|
BLEOTAClass* pParent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OTAFileCallbacks : public BLECharacteristicCallbacks {
|
||||||
|
public:
|
||||||
|
OTAFileCallbacks(BLEOTAClass* pParent);
|
||||||
|
void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) override;
|
||||||
|
private:
|
||||||
|
BLEOTAClass* pParent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
BLEServer* pServer_;
|
||||||
|
char* vNum_;
|
||||||
|
|
||||||
|
BLECharacteristic* pVersionNumber_;
|
||||||
|
BLEDescriptor* pVersionNumberDescriptor_;
|
||||||
|
|
||||||
|
BLECharacteristic* pOTACommand_;
|
||||||
|
BLEDescriptor* pOTACommandDescriptor_;
|
||||||
|
OTACommandCallbacks* cmdCallbacks_;
|
||||||
|
otaCommand currentCommand_;
|
||||||
|
|
||||||
|
BLECharacteristic* pOTAFile_;
|
||||||
|
BLEDescriptor* pOTAFileDescriptor_;
|
||||||
|
OTAFileCallbacks* fileCallbacks_;
|
||||||
|
|
||||||
|
uint32_t fileSize_ = 0;
|
||||||
|
uint32_t fileProgress_ = 0;
|
||||||
|
|
||||||
|
otaStage state_ = otaStage::STAGE_READY;
|
||||||
|
|
||||||
|
unsigned long lastLoop_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern BLEOTAClass BLEota;
|
||||||
|
|
||||||
|
#endif /* BLEOTA */
|
||||||
Reference in New Issue
Block a user