Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate hardware functions from soft #56

Merged
merged 9 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ venv
_build
.gitignore
.lampda.par
*/**/*.o
219 changes: 3 additions & 216 deletions LampColorControler.ino
Original file line number Diff line number Diff line change
@@ -1,221 +1,8 @@
#include <Arduino.h>
#include <bluefruit.h>
#include <Wire.h>
#include "src/system/global.h"

#include "src/compile.h"
#include "src/system/alerts.h"
#include "src/system/behavior.h"
#include "src/system/charger/charger.h"
#include "src/system/physical/battery.h"
#include "src/system/physical/bluetooth.h"
#include "src/system/physical/button.h"
#include "src/system/physical/IMU.h"
#include "src/system/physical/fileSystem.h"
#include "src/system/physical/MicroPhone.h"
#include "src/system/physical/led_power.h"
#include "src/system/utils/serial.h"
#include "src/system/utils/utils.h"
#include "src/user/functions.h"

void set_watchdog(const uint32_t timeoutDelaySecond)
{
// Configure WDT
NRF_WDT->CONFIG = 0x01; // Configure WDT to run when CPU is asleep
NRF_WDT->CRV = timeoutDelaySecond * 32768 + 1; // set timeout
NRF_WDT->RREN = 0x01; // Enable the RR[0] reload register
NRF_WDT->TASKS_START = 1; // Start WDT
}

// timestamp of the system wake up
static uint32_t turnOnTime = 0;
void setup()
{
// start by resetting the led driver
ledpower::write_current(0);

// set turn on time
turnOnTime = millis();

// set watchdog (reset the soft when the program crashes)
// Should be long enough to flash the microcontroler !!!
set_watchdog(5); // second timeout

// necessary for all i2c communications
Wire.setClock(400000); // 400KHz clock
Wire.setTimeout(100); // ms timout
Wire.begin();

// setup serial
serial::setup();

analogReference(AR_INTERNAL_3_0); // 3v reference
analogReadResolution(ADC_RES_EXP);

// setup charger
charger::setup();

// start the file system
fileSystem::setup();
behavior::read_parameters();

// check if we are in first boot mode (no first boot flag stored)
const bool isFirstBoot = !fileSystem::doKeyExists(behavior::isFirstBootKey);

const auto startReason = readResetReason();
// POWER_RESETREAS_RESETPIN_Msk: reset from pin-reset detected
// POWER_RESETREAS_DOG_Msk: reset from watchdog
// POWER_RESETREAS_SREQ_Msk: reset via soft reset
// POWER_RESETREAS_LOCKUP_Msk: reset from cpu lockup
// POWER_RESETREAS_OFF_Msk: wake up from pin interrupt
// POWER_RESETREAS_LPCOMP_Msk: wake up from analogic pin detect (LPCOMP)
// POWER_RESETREAS_DIF_Msk: wake up from debug interface
// POWER_RESETREAS_NFC_Msk: wake from NFC field detection
// POWER_RESETREAS_VBUS_Msk: wake from vbus high signal

bool shouldAlertUser = false;
// handle start flags
if (!isFirstBoot)
{
// started after reset, clear all code and go to bootloader mode
if ((startReason & POWER_RESETREAS_RESETPIN_Msk) != 0x00)
{
enterSerialDfu();
}

if ((startReason & POWER_RESETREAS_DOG_Msk) != 0x00)
{
// POWER_USBREGSTATUS_OUTPUTRDY_Msk : debounce time passed
// POWER_USBREGSTATUS_VBUSDETECT_Msk : vbus is detected on usb

// power detected on the USB, reset the program
if ((NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0x00)
{
// system will reset & shutdown after that
enterSerialDfu();
}
else
{
// alert the user that the lamp was resetted by watchdog
shouldAlertUser = true;
}
}
}

// set up button colors and callbacks
button::init();

if (shouldAlertUser)
{
for (int i = 0; i < 5; i++)
{
button::set_color(utils::ColorSpace::WHITE);
delay(300);
button::set_color(utils::ColorSpace::BLACK);
delay(300);
}
}

const bool wasPoweredyByUserInterrupt = (startReason & POWER_RESETREAS_OFF_Msk) != 0x00;
// any wake up from something that is not an interrupt should be considered as vbus voltage
behavior::set_woke_up_from_vbus(not wasPoweredyByUserInterrupt);

// let the user start in unpowered mode
user::power_off_sequence();

// use the charging thread !
Scheduler.startLoop(charging_thread);

// user requested another thread, spawn it
if (user::should_spawn_thread())
{
Scheduler.startLoop(secondary_thread);
}
}

void charging_thread()
{
if (behavior::is_shuting_down())
return;

// run the charger loop (all the time)
charger::loop();
delay(2);
}

void secondary_thread()
{
if (behavior::is_shuting_down())
return;
if (not behavior::is_user_code_running())
return;

user::user_thread();
}

void check_loop_runtime(const uint32_t runTime)
{
static constexpr uint8_t maxAlerts = 5;
static uint32_t alarmRaisedTime = 0;
// check the loop duration
static uint8_t isOnSlowLoopCount = 0;
if (runTime > LOOP_UPDATE_PERIOD + 1)
{
isOnSlowLoopCount = min(isOnSlowLoopCount + 1, maxAlerts);

if (runTime > 500)
{
// if loop time is too long, go back to flash mode
enterSerialDfu();
}
}
else if (isOnSlowLoopCount > 0)
{
isOnSlowLoopCount--;
}

if (isOnSlowLoopCount >= maxAlerts)
{
alarmRaisedTime = millis();
AlertManager.raise_alert(Alerts::LONG_LOOP_UPDATE);
}
// lower the alert (after 5 seconds)
else if (isOnSlowLoopCount <= 1 and millis() - alarmRaisedTime > 3000)
{
AlertManager.clear_alert(Alerts::LONG_LOOP_UPDATE);
};
}
void setup() { global::main_setup(); }

/**
* \brief Run the main program loop
*/
void loop()
{
uint32_t start = millis();

// update watchdog (prevent crash)
NRF_WDT->RR[0] = WDT_RR_RR_Reload;

// loop is not ran in shutdown mode
button::handle_events(behavior::button_clicked_callback, behavior::button_hold_callback);

// handle user serial events
serial::handleSerialEvents();

// loop the behavior
behavior::loop();

// wait for a delay if we are faster than the set refresh rate
uint32_t stop = millis();
const uint32_t loopDuration = (stop - start);
if (loopDuration < LOOP_UPDATE_PERIOD)
{
delay(LOOP_UPDATE_PERIOD - loopDuration);
}

stop = millis();
check_loop_runtime(stop - start);

// automatically deactivate sensors if they are not used for a time
microphone::disable_after_non_use();
imu::disable_after_non_use();
}
void loop() { global::main_loop(); }
54 changes: 2 additions & 52 deletions simulator/include/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,72 +14,22 @@
// constants
using String = std::string;

#define PI 3.1415926535897
#define TWO_PI 6.2831853071795
#define HALF_PI 1.5707963267948

//
// lampda-specific hacks
//

#define D4 0x1004;
#define D5 0x1005;
#define D6 0x1006;
#define D7 0x1007;
#define D8 0x1008;

using byte = uint8_t;

template<typename T, typename U> T random(T min, U max)
{
uint32_t n = random();
// bad random, but who cares?
return (n % (max - min)) + min;
}

template<typename T> T random(T max) { return random(0, max); }

//
// ambiguous min/fmin/max/fmax/abs
// ambiguous abs
//

static constexpr double min(double a, double b) { return fmin(a, b); }

static constexpr double max(double a, double b) { return fmax(a, b); }

using std::abs;

//
// misc functions
//

float radians(float degrees) { return (degrees / 180.f) * PI; }

template<typename T, typename V, typename U> static constexpr T constrain(const T& a, const V& mini, const U& maxi)
{
if (a <= mini)
return mini;
if (a >= maxi)
return maxi;
return a;
}

template<typename T, typename V> static constexpr T pow(const T& a, const V& b)
{
T acc = 1;
for (V i = 0; i < b; ++i)
{
acc *= a;
}
return acc;
}

//
// emulate millis()
// emulate time_ms()
//

static uint64_t globalMillis;

uint64_t millis() { return globalMillis; }

#endif
18 changes: 2 additions & 16 deletions simulator/include/behavior_simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,7 @@
// prevent inclusion of colliding src/system/behavior.h
#define BEHAVIOR_HPP

void pinMode(auto, auto) {}
#define OUTPUT 0x1021
#define OUTPUT_H0H1 0x1022
#define INPUT_PULLUP_SENSE 0x1023
#define CHANGE 0x1024
#define LOW 0x1025
#define HIGH 0x1026
#define LED_POWER_PIN 0x1027

void ensure_build_canary() {}
int digitalPinToInterrupt(auto) { return 0; }
void attachInterrupt(auto, auto, auto) {}
int digitalRead(auto) { return 0; }
void digitalWrite(auto, auto) {}
void analogWrite(auto, auto) {}

#define UTILS_H
#define CONSTANTS_H
Expand Down Expand Up @@ -69,7 +55,7 @@ void update_brightness(uint8_t newBrightness, bool shouldUpdateCurrentBrightness
void power_on_behavior(auto& simu)
{
isShutdown = false;
lastStartupSequence = millis();
lastStartupSequence = time_ms();
isButtonUsermodeEnabled = false;
fprintf(stderr, "startup\n");

Expand Down Expand Up @@ -156,7 +142,7 @@ void hold_behavior(auto& simu, uint8_t consecutiveButtonCheck, uint32_t buttonHo
const uint32_t holdDuration =
(buttonHoldDuration > HOLD_BUTTON_MIN_MS) ? (buttonHoldDuration - HOLD_BUTTON_MIN_MS) : 0;

uint32_t realStartTime = millis() - lastStartupSequence;
uint32_t realStartTime = time_ms() - lastStartupSequence;
if (realStartTime > holdDuration)
{
realStartTime -= holdDuration;
Expand Down
4 changes: 1 addition & 3 deletions simulator/include/filesystem_simulator.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef FILESYSTEM_SIMULATOR_H
#define FILESYSTEM_SIMULATOR_H

#include <serial_simulator.h>

#include <cstdio>
#include <unistd.h>

Expand Down Expand Up @@ -154,7 +152,7 @@ struct File
// comment this to enable verbose filesystem debug log in simulator
#undef LMBD_SIMU_ENABLED

#include "src/system/physical/fileSystem.cpp"
#include "src/system/platform/fileSystem.cpp"

#ifndef LMBD_SIMU_ENABLED
#define LMBD_SIMU_ENABLED
Expand Down
13 changes: 0 additions & 13 deletions simulator/include/serial_simulator.h

This file was deleted.

Loading