mirror of
https://github.com/sascha-hemi/HGD4_reversed.git
synced 2026-03-21 00:03:48 +01:00
Merge pull request #11 from jonasniesner/jonasniesner-patch-6
Add Bootloader
This commit is contained in:
@@ -5,29 +5,17 @@
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x239A",
|
||||
"0x8029"
|
||||
],
|
||||
[
|
||||
"0x239A",
|
||||
"0x0029"
|
||||
],
|
||||
[
|
||||
"0x239A",
|
||||
"0x002A"
|
||||
],
|
||||
[
|
||||
"0x239A",
|
||||
"0x802A"
|
||||
]
|
||||
],
|
||||
"usb_product": "Feather nRF52840 Express",
|
||||
"usb_product": "NRF52 DK",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "feather_nrf52840_express",
|
||||
"variant": "pca10056",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
@@ -46,30 +34,29 @@
|
||||
],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": [
|
||||
"jlink"
|
||||
],
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"zephyr"
|
||||
"arduino"
|
||||
],
|
||||
"name": "Adafruit Feather nRF52840 Express",
|
||||
"name": "Nordic nRF52840-DK (Adafruit BSP)",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocol": "jlink",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink",
|
||||
"cmsis-dap",
|
||||
"blackmagic"
|
||||
],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
]
|
||||
},
|
||||
"url": "https://www.adafruit.com/product/4062",
|
||||
"vendor": "Adafruit"
|
||||
"url": "https://os.mbed.com/platforms/Nordic-nRF52840-DK/",
|
||||
"vendor": "Nordic"
|
||||
}
|
||||
19
NRF_firmware/custom_upload.py
Normal file
19
NRF_firmware/custom_upload.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
|
||||
Import("env")
|
||||
|
||||
custom_hex_path = env.subst(os.path.join("$BUILD_DIR", "production.hex"))
|
||||
|
||||
env.Replace(
|
||||
UPLOADER="JLinkExe",
|
||||
UPLOADCMD=f"JLinkExe -device nrf52840_xxaa -if swd -speed 4000 -autoconnect 1 -CommanderScript upload.jlink"
|
||||
)
|
||||
|
||||
# Auto-generate the JLink command file from script if needed:
|
||||
with open("upload.jlink", "w") as f:
|
||||
f.write(f"""r
|
||||
loadfile {custom_hex_path}
|
||||
r
|
||||
g
|
||||
exit
|
||||
""")
|
||||
11638
NRF_firmware/data/bootloader.hex
Normal file
11638
NRF_firmware/data/bootloader.hex
Normal file
File diff suppressed because it is too large
Load Diff
BIN
NRF_firmware/data/signature.bin
Normal file
BIN
NRF_firmware/data/signature.bin
Normal file
Binary file not shown.
35
NRF_firmware/generate_production_image.py
Normal file
35
NRF_firmware/generate_production_image.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
def generate_production_binary(source, target, env):
|
||||
signature_bin = "data/signature.bin"
|
||||
firmware_hex = "$BUILD_DIR/${PROGNAME}.hex"
|
||||
bootloader_hex = "data/bootloader.hex"
|
||||
production_image = os.path.join("$BUILD_DIR", "production.hex")
|
||||
dfu_package = os.path.join("$BUILD_DIR", "dfu.zip")
|
||||
merge_tool = os.path.join(
|
||||
env.PioPlatform().get_package_dir("tool-sreccat") or "", "srec_cat"
|
||||
)
|
||||
|
||||
if not os.path.isfile(env.subst(production_image)):
|
||||
assert os.path.isfile(bootloader_hex), "Missing bootloader image!"
|
||||
assert os.path.isfile(signature_bin), "Missing signature file!"
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
f'"{merge_tool}" "{bootloader_hex}" -intel "{signature_bin}" -Binary -offset 0xFF000 "{firmware_hex}" -intel -offset 0x00 -o "{production_image}" -intel',
|
||||
f"Generating production image {production_image}",
|
||||
)
|
||||
)
|
||||
|
||||
# Generate DFU package
|
||||
if not os.path.isfile(env.subst(dfu_package)):
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
f'adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application "{firmware_hex}" "{dfu_package}"',
|
||||
f"Generating DFU package {dfu_package}",
|
||||
)
|
||||
)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", generate_production_binary)
|
||||
@@ -19,3 +19,6 @@ lib_compat_mode = soft
|
||||
upload_protocol = jlink
|
||||
debug_tool = jlink
|
||||
monitor_port = socket://localhost:19021
|
||||
extra_scripts =
|
||||
generate_production_image.py
|
||||
custom_upload.py
|
||||
@@ -4,15 +4,16 @@
|
||||
ModemConfig deviceConfig;
|
||||
|
||||
//set if config should be saved to modem
|
||||
bool saveConfig = false;
|
||||
bool saveConfig = true;
|
||||
|
||||
void setup() {
|
||||
rtt.trimDownBufferFull();
|
||||
rtt.println("|---------Starting setup---------|");
|
||||
rtt.println("|x-------XStarting setupX-------x|");
|
||||
gpioinit();
|
||||
sensorData.wakeup_reason = NRF_POWER->RESETREAS;
|
||||
delay(200);
|
||||
initializeModem();
|
||||
sensorpwr(true);
|
||||
blinkLED(1, 200, 200, true);
|
||||
//checkModemStorageSpace();
|
||||
LoadDeviceConfig();
|
||||
@@ -24,7 +25,6 @@ void setup() {
|
||||
void loop() {
|
||||
lastWaitCheck = millis();
|
||||
rtt.println("|---------Starting loop---------|");
|
||||
sensorpwr(true);
|
||||
rtt.println("Collecting sensor data");
|
||||
collectAllSensorData();
|
||||
rtt.print("WD counter ");
|
||||
@@ -38,9 +38,10 @@ void loop() {
|
||||
ScanForWiFiNetworks();
|
||||
rtt.println("Managing modem lifecycle");
|
||||
manageModemLifecycle();
|
||||
sensorpwr(false);
|
||||
rtt.println("Waiting for next transmission");
|
||||
rtt.println("Loop cycle completed.");
|
||||
globalMotionDetected = false;
|
||||
readAccelerometers(lastAcc1X, lastAcc1Y, lastAcc1Z, lastAcc2X, lastAcc2Y, lastAcc2Z);
|
||||
while (!waitForNextTransmission(deviceConfig.transmission_interval)) {
|
||||
performBackgroundTasks();
|
||||
}
|
||||
@@ -570,6 +571,8 @@ bool readAccelerometers(float& acc1_x, float& acc1_y, float& acc1_z, float& acc2
|
||||
if (!acc1.begin() || !acc2.begin()) {
|
||||
return false;
|
||||
}
|
||||
acc1.setRange(LIS3DH_RANGE_2_G);
|
||||
acc2.setRange(LIS3DH_RANGE_2_G);
|
||||
acc1.read();
|
||||
acc2.read();
|
||||
acc1_x = acc1.x;
|
||||
@@ -919,8 +922,6 @@ bool sendSensorDataToServer(const SensorData& data) {
|
||||
|
||||
void manageModemLifecycle() {
|
||||
unsigned long currentTime = millis();
|
||||
if (lastTransmissionTime == 0 || (currentTime - lastTransmissionTime >= deviceConfig.transmission_interval)) {
|
||||
rtt.flush();
|
||||
rtt.println("Transmitting sensor data...");
|
||||
if (!initializeModemIfNeeded()) {
|
||||
rtt.println("Failed to initialize modem");
|
||||
@@ -969,10 +970,15 @@ void manageModemLifecycle() {
|
||||
|
||||
// Shutdown modem between loops if configured
|
||||
if (deviceConfig.modem_shutdown_between_loops) {
|
||||
rtt.println("Shutting down modem between loops...");
|
||||
shutdownModem();
|
||||
// Check if we should keep modem on due to motion
|
||||
if (shouldKeepModemPowered()) {
|
||||
rtt.println("Keeping modem powered on due to motion or configuration");
|
||||
logPowerManagementStatus();
|
||||
} else {
|
||||
rtt.println("Shutting down modem between loops...");
|
||||
shutdownModem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool readModemInfo() {
|
||||
@@ -1424,6 +1430,7 @@ bool saveConfigToModem(const ModemConfig& config) {
|
||||
DynamicJsonDocument doc(16000);
|
||||
doc["device_name"] = config.device_name;
|
||||
doc["transmission_interval"] = config.transmission_interval;
|
||||
doc["transmission_interval_motion"] = config.transmission_interval_motion;
|
||||
doc["enable_gps"] = config.enable_gps;
|
||||
doc["gps_timeout"] = config.gps_timeout;
|
||||
doc["server_url"] = config.server_url;
|
||||
@@ -1440,6 +1447,9 @@ bool saveConfigToModem(const ModemConfig& config) {
|
||||
doc["ble_scan_max_beacons"] = config.ble_scan_max_beacons;
|
||||
doc["ble_scan_duration"] = config.ble_scan_duration;
|
||||
doc["modem_shutdown_between_loops"] = config.modem_shutdown_between_loops;
|
||||
doc["motion_detection_enabled"] = config.motion_detection_enabled;
|
||||
doc["motion_threshold"] = config.motion_threshold;
|
||||
doc["modem_shutdown_on_motion"] = config.modem_shutdown_on_motion;
|
||||
String configJson = "";
|
||||
serializeJson(doc, configJson);
|
||||
delay(10);
|
||||
@@ -1493,6 +1503,9 @@ bool loadConfigFromModem(ModemConfig& config) {
|
||||
if (doc.containsKey("transmission_interval")) {
|
||||
config.transmission_interval = doc["transmission_interval"].as<unsigned long>();
|
||||
}
|
||||
if (doc.containsKey("transmission_interval_motion")) {
|
||||
config.transmission_interval_motion = doc["transmission_interval_motion"].as<unsigned long>();
|
||||
}
|
||||
if (doc.containsKey("enable_gps")) {
|
||||
config.enable_gps = doc["enable_gps"].as<bool>();
|
||||
}
|
||||
@@ -1541,6 +1554,15 @@ bool loadConfigFromModem(ModemConfig& config) {
|
||||
if (doc.containsKey("modem_shutdown_between_loops")) {
|
||||
config.modem_shutdown_between_loops = doc["modem_shutdown_between_loops"].as<bool>();
|
||||
}
|
||||
if (doc.containsKey("motion_detection_enabled")) {
|
||||
config.motion_detection_enabled = doc["motion_detection_enabled"].as<bool>();
|
||||
}
|
||||
if (doc.containsKey("motion_threshold")) {
|
||||
config.motion_threshold = doc["motion_threshold"].as<float>();
|
||||
}
|
||||
if (doc.containsKey("modem_shutdown_on_motion")) {
|
||||
config.modem_shutdown_on_motion = doc["modem_shutdown_on_motion"].as<bool>();
|
||||
}
|
||||
//rtt.println("Configuration loaded successfully");
|
||||
return true;
|
||||
}
|
||||
@@ -1548,6 +1570,7 @@ bool loadConfigFromModem(ModemConfig& config) {
|
||||
void printConfig(const ModemConfig& config) {
|
||||
rtt.print("Device Name: "); rtt.println(config.device_name);
|
||||
rtt.print("Transmission Interval: "); rtt.print(config.transmission_interval); rtt.println(" ms");
|
||||
rtt.print("Transmission Interval (Motion): "); rtt.print(config.transmission_interval_motion); rtt.println(" ms");
|
||||
rtt.print("GPS Enabled: "); rtt.println(config.enable_gps ? "Yes" : "No");
|
||||
rtt.print("GPS Timeout: "); rtt.print(config.gps_timeout); rtt.println(" ms");
|
||||
rtt.print("WiFi Scan Enabled: "); rtt.println(config.wifi_scan_enabled ? "Yes" : "No");
|
||||
@@ -1556,6 +1579,9 @@ void printConfig(const ModemConfig& config) {
|
||||
rtt.print("BLE Max Beacons: "); rtt.println(config.ble_scan_max_beacons);
|
||||
rtt.print("BLE Scan Duration: "); rtt.print(config.ble_scan_duration); rtt.println(" ms");
|
||||
rtt.print("Modem Shutdown Between Loops: "); rtt.println(config.modem_shutdown_between_loops ? "Yes" : "No");
|
||||
rtt.print("Motion Detection Enabled: "); rtt.println(config.motion_detection_enabled ? "Yes" : "No");
|
||||
rtt.print("Motion Threshold: "); rtt.print(config.motion_threshold, 3); rtt.println(" g");
|
||||
rtt.print("Modem Shutdown On Motion: "); rtt.println(config.modem_shutdown_on_motion ? "Yes" : "No");
|
||||
rtt.print("Server URL: "); rtt.println(config.server_url);
|
||||
rtt.print("Server Endpoint: "); rtt.println(config.server_endpoint);
|
||||
rtt.print("Server Port: "); rtt.println(config.server_port);
|
||||
@@ -2182,8 +2208,13 @@ void optimizeScanData(DynamicJsonDocument& doc, size_t maxSize) {
|
||||
bool waitForNextTransmission(unsigned long interval) {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Choose interval based on motion detection
|
||||
unsigned long effectiveInterval = interval;
|
||||
if (deviceConfig.motion_detection_enabled && globalMotionDetected) {
|
||||
effectiveInterval = deviceConfig.transmission_interval_motion;
|
||||
}
|
||||
// Check if it's time for the next transmission
|
||||
if (currentTime - lastWaitCheck >= interval) {
|
||||
if (currentTime - lastWaitCheck >= effectiveInterval) {
|
||||
lastWaitCheck = currentTime;
|
||||
return true; // Time to transmit
|
||||
}
|
||||
@@ -2199,20 +2230,39 @@ void performBackgroundTasks() {
|
||||
lastBatteryCheck = millis();
|
||||
}
|
||||
|
||||
// Check for any pending modem operations
|
||||
if (modemInitialized && !modem.isGprsConnected()) {
|
||||
// Try to reconnect if disconnected
|
||||
static unsigned long lastReconnectAttempt = 0;
|
||||
if (millis() - lastReconnectAttempt > 60000) { // Try every minute
|
||||
rtt.println("Attempting to reconnect to network...");
|
||||
connectToNetwork();
|
||||
lastReconnectAttempt = millis();
|
||||
if (deviceConfig.motion_detection_enabled && millis() - lastMotionCheck > 100) {
|
||||
// Read current accelerometer values
|
||||
|
||||
if (readAccelerometers(currentAcc1X, currentAcc1Y, currentAcc1Z, currentAcc2X, currentAcc2Y, currentAcc2Z)) {
|
||||
// Calculate acceleration differences
|
||||
float acc1Diff = sqrt(pow(currentAcc1X - lastAcc1X, 2) +
|
||||
pow(currentAcc1Y - lastAcc1Y, 2) +
|
||||
pow(currentAcc1Z - lastAcc1Z, 2));
|
||||
float acc2Diff = sqrt(pow(currentAcc2X - lastAcc2X, 2) +
|
||||
pow(currentAcc2Y - lastAcc2Y, 2) +
|
||||
pow(currentAcc2Z - lastAcc2Z, 2));
|
||||
|
||||
// Check if motion is detected using configured threshold
|
||||
if (acc1Diff > deviceConfig.motion_threshold || acc2Diff > deviceConfig.motion_threshold) {
|
||||
if (!globalMotionDetected) {
|
||||
globalMotionDetected = true;
|
||||
globalLastMotionTime = millis();
|
||||
rtt.println("Motion detected!");
|
||||
rtt.print("Acc1 diff: "); rtt.print(acc1Diff, 3);
|
||||
rtt.print(" Acc2 diff: "); rtt.println(acc2Diff, 3);
|
||||
}
|
||||
}
|
||||
lastAcc1X = currentAcc1X;
|
||||
lastAcc1Y = currentAcc1Y;
|
||||
lastAcc1Z = currentAcc1Z;
|
||||
lastAcc2X = currentAcc2X;
|
||||
lastAcc2Y = currentAcc2Y;
|
||||
lastAcc2Z = currentAcc2Z;
|
||||
}
|
||||
|
||||
lastMotionCheck = millis();
|
||||
}
|
||||
rtt.println("Performing background tasks");
|
||||
|
||||
// Small delay to prevent busy waiting
|
||||
delay(1000); // 1 second delay between background task checks
|
||||
delay(10);
|
||||
}
|
||||
|
||||
// Function to parse JSON response from server
|
||||
@@ -2353,4 +2403,28 @@ bool initializeModemIfNeeded() {
|
||||
return initializeModem();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Function to check if modem should be kept powered on based on motion
|
||||
bool shouldKeepModemPowered() {
|
||||
if (!deviceConfig.modem_shutdown_between_loops) {
|
||||
return true; // Always keep modem on if shutdown is disabled
|
||||
}
|
||||
|
||||
if (deviceConfig.modem_shutdown_on_motion && globalMotionDetected) {
|
||||
return true; // Keep modem on if motion detected and configured to do so
|
||||
}
|
||||
|
||||
return false; // Shutdown modem normally
|
||||
}
|
||||
|
||||
// Function to get current power management status
|
||||
void logPowerManagementStatus() {
|
||||
rtt.print("Power Management - Modem Shutdown: ");
|
||||
rtt.print(deviceConfig.modem_shutdown_between_loops ? "Enabled" : "Disabled");
|
||||
rtt.print(", Motion Shutdown: ");
|
||||
rtt.print(deviceConfig.modem_shutdown_on_motion ? "Enabled" : "Disabled");
|
||||
rtt.print(", Motion Detected: ");
|
||||
rtt.print(globalMotionDetected ? "Yes" : "No");
|
||||
rtt.print(", Keep Modem On: ");
|
||||
rtt.println(shouldKeepModemPowered() ? "Yes" : "No");
|
||||
}
|
||||
@@ -35,6 +35,7 @@ BLEBas blebas; // battery
|
||||
struct ModemConfig {
|
||||
String device_name;
|
||||
unsigned long transmission_interval;
|
||||
unsigned long transmission_interval_motion;
|
||||
bool enable_gps;
|
||||
unsigned long gps_timeout;
|
||||
String server_url;
|
||||
@@ -51,11 +52,15 @@ struct ModemConfig {
|
||||
int ble_scan_max_beacons;
|
||||
unsigned long ble_scan_duration;
|
||||
bool modem_shutdown_between_loops;
|
||||
bool motion_detection_enabled;
|
||||
float motion_threshold;
|
||||
bool modem_shutdown_on_motion;
|
||||
|
||||
ModemConfig() {
|
||||
device_name = "Dev 1";
|
||||
transmission_interval = 30000;
|
||||
enable_gps = false;
|
||||
transmission_interval = 3600000;
|
||||
transmission_interval_motion = 60000;
|
||||
enable_gps = true;
|
||||
gps_timeout = 15000;
|
||||
server_url = "api.64eng.de";
|
||||
server_endpoint = "/sensordata.php";
|
||||
@@ -66,16 +71,19 @@ struct ModemConfig {
|
||||
enable_storage = true;
|
||||
max_stored_files = 10;
|
||||
wifi_scan_enabled = true;
|
||||
wifi_scan_max_networks = 8;
|
||||
wifi_scan_max_networks = 20;
|
||||
ble_scan_enabled = true;
|
||||
ble_scan_max_beacons = 9;
|
||||
ble_scan_duration = 10000;
|
||||
modem_shutdown_between_loops = false;
|
||||
ble_scan_max_beacons = 20;
|
||||
ble_scan_duration = 5000;
|
||||
modem_shutdown_between_loops = true;
|
||||
motion_detection_enabled = true;
|
||||
motion_threshold = 500;
|
||||
modem_shutdown_on_motion = false;
|
||||
}
|
||||
};
|
||||
|
||||
// BLE scanning variables
|
||||
DynamicJsonDocument bleScanDoc(8000);
|
||||
DynamicJsonDocument bleScanDoc(16000);
|
||||
JsonArray bleBeacons;
|
||||
bool bleScanning = false;
|
||||
unsigned long bleScanStartTime = 0;
|
||||
@@ -85,6 +93,17 @@ void ble_scan_callback(ble_gap_evt_adv_report_t* report);
|
||||
void scanforbeacons();
|
||||
bool initializeBLE();
|
||||
|
||||
// Global motion detection variables
|
||||
static bool globalMotionDetected = false;
|
||||
static unsigned long globalLastMotionTime = 0;
|
||||
|
||||
// Motion detection using accelerometers
|
||||
static unsigned long lastMotionCheck = 0;
|
||||
static float lastAcc1X = 0, lastAcc1Y = 0, lastAcc1Z = 0;
|
||||
static float lastAcc2X = 0, lastAcc2Y = 0, lastAcc2Z = 0;
|
||||
float currentAcc1X, currentAcc1Y, currentAcc1Z;
|
||||
float currentAcc2X, currentAcc2Y, currentAcc2Z;
|
||||
|
||||
bool espmodemrail = 0;
|
||||
bool espon = 0;
|
||||
bool modemon = 0;
|
||||
@@ -195,4 +214,12 @@ String readCompleteHttpResponse(HttpClient& http, unsigned long timeout);
|
||||
|
||||
// Non-blocking wait functions
|
||||
bool waitForNextTransmission(unsigned long interval);
|
||||
void performBackgroundTasks();
|
||||
void performBackgroundTasks();
|
||||
|
||||
// Motion detection functions
|
||||
bool isMotionDetected();
|
||||
void triggerMotionTransmission();
|
||||
|
||||
// Power management functions
|
||||
bool shouldKeepModemPowered();
|
||||
void logPowerManagementStatus();
|
||||
5
NRF_firmware/upload.jlink
Normal file
5
NRF_firmware/upload.jlink
Normal file
@@ -0,0 +1,5 @@
|
||||
r
|
||||
loadfile /home/jonas/Desktop/dd/HGD4_reversed-main/NRF_firmware/.pio/build/hgd6/production.hex
|
||||
r
|
||||
g
|
||||
exit
|
||||
@@ -50,9 +50,6 @@ extern "C"
|
||||
|
||||
#define LED_BUILTIN GREEN_LED
|
||||
|
||||
#define PIN_SERIAL_RX MODEM_RXD
|
||||
#define PIN_SERIAL_TX MODEM_TXD
|
||||
|
||||
#define PIN_SERIAL1_RX MODEM_RXD
|
||||
#define PIN_SERIAL1_TX MODEM_TXD
|
||||
|
||||
|
||||
Reference in New Issue
Block a user