Skip to content

Commit

Permalink
⭐ feat(light sensor) integrate global init receive
Browse files Browse the repository at this point in the history
  • Loading branch information
polesskiy-dev committed Aug 16, 2024
1 parent ce816fe commit 8c30b37
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 107 deletions.
24 changes: 24 additions & 0 deletions firmware/iot-risk-logger-stm32l4/app/core/actor/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ extern "C" {
#define DEFAULT_QUEUE_MESSAGE_SIZE sizeof(message_t)
#define DEFAULT_TASK_STACK_SIZE_WORDS (128)

/**
* @brief Sets the state of an inherited actor and logs the action.
*
* @warning inherited actor from actor_t should have a `state` member.
*
* @param actorPointer A pointer to inherited the actor whose state is to be set.
* This should be a pointer to a struct that has a `state` member.
* @param stateEnum state to set
*
* @example
* typedef struct {
* actor_t super;
* StateEnum_t state;
* } My_Actor_t;
*
* My_Actor_t myActor;
* TO_STATE(&myActor, FIRST_STATE);
*/
#define TO_STATE(actorPointer, stateEnum) \
do { \
(actorPointer)->state = (stateEnum); \
fprintf(stdout, "%lu: %s\n", (actorPointer)->super.actorId, #stateEnum); \
} while (0);

/**
* @brief Structure representing a message in the actor framework.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ typedef enum {
// TEMPERATURE_HUMIDITY_SENSOR
TH_SENS_INITIALIZE,
TH_SENS_START_SINGLE_SHOT_READ,
TH_SENS_MEASURE_CONTINUOUSLY,
TH_SENS_CRON_READ,
TH_SENS_TURN_OFF,
TH_SENS_ERROR,
// LIGHT_SENSOR
LIGHT_SENS_INITIALIZE,
LIGHT_SENS_INITIALIZE_SUCCESS,
LIGHT_SENS_SINGLE_SHOT_READ,
LIGHT_SENS_MEASURE_CONTINUOUSLY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ extern actor_t* ACTORS_LIST_SystemRegistry[MAX_ACTORS];
* Each row corresponds to a specific global event, and each column contains the IDs of actors
* that are interested in that event.
*
* @note The array is initialized at compile-time and stored in Flash memory for efficiency.
* @note The matrix is initialized at compile-time and stored in Flash memory for efficiency.
* @note The matrix includes Actors IDs, not Actors themselves to decouple the event manager from the actors.
*
* Example usage:
* @code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ hide empty description
TURNED_OFF: Initialized, turned off\nready for commands, low power mode
CONTINUOUS_MEASURE: Device is measuring continuously\ngenerates interrupt on threshold exceed
OUT_OF_RANGE: Lux is out of range, limits are swapped\nreturn to measurements after lux returns in limits
[*] --> TURNED_OFF : INITIALIZE
[*] --> TURNED_OFF : GLOBAL_CMD_INITIALIZE
note "Publishes: \nGLOBAL_INITIALIZE_SUCCESS\nGLOBAL_ERROR" as N1
TURNED_OFF --> TURNED_OFF : SINGLE_SHOT_READ
TURNED_OFF --> TURNED_OFF : SET_LIMIT
TURNED_OFF --> CONTINUOUS_MEASURE : MEASURE_CONTINUOUSLY
TURNED_OFF --> CONTINUOUS_MEASURE : GLOBAL_CMD_START_CONTINUOUS_SENSING
CONTINUOUS_MEASURE --> CONTINUOUS_MEASURE : CRON_READ
CONTINUOUS_MEASURE --> OUT_OF_RANGE : LIMIT_INT
OUT_OF_RANGE --> CONTINUOUS_MEASURE : LIMIT_INT
OUT_OF_RANGE --> OUT_OF_RANGE : CRON_READ
OUT_OF_RANGE --> TURNED_OFF : TURN_OFF
CONTINUOUS_MEASURE --> TURNED_OFF : TURN_OFF
ERROR --> TURNED_OFF : RECOVER
ERROR --> TURNED_OFF : RECOVER (TODO)
TURNED_OFF --> ERROR : ERROR
CONTINUOUS_MEASURE --> ERROR : ERROR
OUT_OF_RANGE --> ERROR : ERROR
Expand Down
144 changes: 65 additions & 79 deletions firmware/iot-risk-logger-stm32l4/app/tasks/light_sensor/light_sensor.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

#include "light_sensor.h"

// state handlers
static osStatus_t handleLightSensorFSM(LIGHT_SENS_Actor_t *this, message_t *message);
/** states handlers */
static osStatus_t handleInit(LIGHT_SENS_Actor_t *this, message_t *message);
static osStatus_t handleTurnedOff(LIGHT_SENS_Actor_t *this, message_t *message);
static osStatus_t handleContinuousMeasure(LIGHT_SENS_Actor_t *this, message_t *message);
static osStatus_t handleOutOfRange(LIGHT_SENS_Actor_t *this, message_t *message);

static osStatus_t toState(LIGHT_SENS_Actor_t *this, LIGHT_SENS_State_t nextState);
extern actor_t* ACTORS_LIST_SystemRegistry[MAX_ACTORS];

LIGHT_SENS_Actor_t LIGHT_SENS_Actor = {
.super = {
Expand All @@ -42,14 +42,6 @@ const osThreadAttr_t lightSensorTaskDescription = {
.priority = (osPriority_t) osPriorityNormal,
};

const char * const lightSensStatesNames[LIGHT_SENS_MAX_STATE] = {
"LIGHT_SENS_NO_STATE",
"LIGHT_SENS_TURNED_OFF_STATE",
"LIGHT_SENS_CONTINUOUS_MEASURE_STATE",
"LIGHT_SENS_OUT_OF_RANGE_STATE",
"LIGHT_SENS_STATE_ERROR"
};

actor_t* LIGHT_SENS_TaskInit(void) {
LIGHT_SENS_Actor.super.osMessageQueueId = osMessageQueueNew(DEFAULT_QUEUE_SIZE, DEFAULT_QUEUE_MESSAGE_SIZE, &(osMessageQueueAttr_t){
.name = "lightSensorQueue"
Expand All @@ -63,22 +55,18 @@ void LIGHT_SENS_Task(void *argument) {
(void) argument; // Avoid unused parameter warning
message_t msg;

// TODO run in global init manager
osMessageQueuePut(LIGHT_SENS_Actor.super.osMessageQueueId, &(message_t){LIGHT_SENS_INITIALIZE}, 0, 0);
// debug check
// osMessageQueuePut(LIGHT_SENS_Actor.super.osMessageQueueId, &(message_t){LIGHT_SENS_SINGLE_SHOT_READ}, 0, 0);
// TODO move it to initializer
osMessageQueuePut(LIGHT_SENS_Actor.super.osMessageQueueId, &(message_t){LIGHT_SENS_MEASURE_CONTINUOUSLY}, 0, 0);

fprintf(stdout, "Light Sensor initialized\n");
fprintf(stdout, "Task %s started\n", lightSensorTaskDescription.name);

for (;;) {
// Wait for messages from the queue
if (osMessageQueueGet(LIGHT_SENS_Actor.super.osMessageQueueId, &msg, NULL, osWaitForever) == osOK) {
osStatus_t status = LIGHT_SENS_Actor.super.messageHandler((actor_t *) &LIGHT_SENS_Actor, &msg);
if (status != osOK) {
// TODO Handle error, emit common error event and reinitialize module
LIGHT_SENS_Actor.state = LIGHT_SENS_STATE_ERROR;
osStatus_t handleMessageStatus = LIGHT_SENS_Actor.super.messageHandler((actor_t *) &LIGHT_SENS_Actor, &msg);

if (handleMessageStatus != osOK) {
fprintf(stderr, "%s: Error handling event %u in state %ul\n", lightSensorTaskDescription.name, msg.event, LIGHT_SENS_Actor.state);
osMessageQueueId_t evManagerQueue = ACTORS_LIST_SystemRegistry[EV_MANAGER_ACTOR_ID]->osMessageQueueId;
osMessageQueuePut(evManagerQueue, &(message_t){GLOBAL_ERROR, .payload.value = LIGHT_SENSOR_ACTOR_ID}, 0, 0);
TO_STATE(&LIGHT_SENS_Actor, LIGHT_SENS_STATE_ERROR);
}
}
}
Expand All @@ -102,51 +90,55 @@ static osStatus_t handleLightSensorFSM(LIGHT_SENS_Actor_t *this, message_t *mess
* @brief Initializes the sensor, configures I2C, writes default settings, and transitions to the TURNED_OFF state
*/
static osStatus_t handleInit(LIGHT_SENS_Actor_t *this, message_t *message) {
if (LIGHT_SENS_INITIALIZE == message->event) {
if (GLOBAL_CMD_INITIALIZE == message->event) {
// init BSP I2C
BSP_I2C1_Init(); // TODO think about proper place to init I2C

// init the driver (io)
osStatus_t status = OPT3001_InitIO(OPT3001_I2C_ADDRESS, BSP_I2C1_WriteReg, BSP_I2C1_ReadReg);
osStatus_t ioStatus = OPT3001_InitIO(OPT3001_I2C_ADDRESS, BSP_I2C1_WriteReg, BSP_I2C1_ReadReg);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

// test read device id
uint16_t opt3001Id = 0x0000;
status = OPT3001_ReadDeviceID(&opt3001Id);
ioStatus = OPT3001_ReadDeviceID(&opt3001Id);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;
fprintf(stdout, "OPT3001 ID: %x\n", opt3001Id);

// write default config (OPT3001 remains in turned off state)
uint16_t opt3001Config = OPT3001_CONFIG_DEFAULT;

status = OPT3001_WriteConfig(opt3001Config);
ioStatus = OPT3001_WriteConfig(opt3001Config);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;
fprintf(stdout, "Write OPT3001 Config: %x\n", opt3001Config);

// read existing config to verify equality
uint16_t opt3001ConfigFromSensor = 0x0000;
status = OPT3001_ReadConfig(&opt3001ConfigFromSensor);
ioStatus = OPT3001_ReadConfig(&opt3001ConfigFromSensor);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;
fprintf(stdout, "OPT3001 Config: %x\n", opt3001ConfigFromSensor);

if (opt3001Config != opt3001ConfigFromSensor) {
fprintf(stderr, "OPT3001 Config mismatch\n");
return osError;
}

// TODO read it from NOR flash e.g. emit LIGHT_SENS_INITIALIZE_SUCCESS to global events manager
// TODO read it from NOR flash (implement settings manager)
// set high limit and minimal low limit so that the sensor never triggers the interrupt on low limit
status = OPT3001_WriteHighLimit(this->highLimit);
if (status != osOK) return osError;
ioStatus = OPT3001_WriteHighLimit(this->highLimit);
if (ioStatus != osOK) return osError;

status = OPT3001_WriteLowLimit(OPT3001_CONFIG_LIMIT_MIN);
if (status != osOK) return osError;
ioStatus = OPT3001_WriteLowLimit(OPT3001_CONFIG_LIMIT_MIN);
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_TURNED_OFF_STATE);
// publish to event manager that the sensor is initialized
osMessageQueueId_t evManagerQueue = ACTORS_LIST_SystemRegistry[EV_MANAGER_ACTOR_ID]->osMessageQueueId;
osMessageQueuePut(evManagerQueue, &(message_t){GLOBAL_INITIALIZE_SUCCESS, .payload.value = LIGHT_SENSOR_ACTOR_ID}, 0, 0);

TO_STATE(this, LIGHT_SENS_TURNED_OFF_STATE);
}

return osOK;
Expand All @@ -156,52 +148,52 @@ static osStatus_t handleInit(LIGHT_SENS_Actor_t *this, message_t *message) {
* @brief Perform single-shot measurements, set limits, or switch to continuous measurement mode.
*/
static osStatus_t handleTurnedOff(LIGHT_SENS_Actor_t *this, message_t *message) {
osStatus_t status;
osStatus_t ioStatus;

switch (message->event) {
case LIGHT_SENS_SINGLE_SHOT_READ:
// set single shot mode
status = OPT3001_WriteConfig(OPT3001_CONFIG_RANGE_NUMBER_AUTO_SCALE | \
ioStatus = OPT3001_WriteConfig(OPT3001_CONFIG_RANGE_NUMBER_AUTO_SCALE | \
OPT3001_CONFIG_CONVERSION_TIME_800_MS | \
OPT3001_CONFIG_MODE_SINGLE_SHOT | \
OPT3001_CONFIG_LATCH_ENABLED);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

// wait for the sensor to finish the measurement
osDelay(1000); // TODO replace with 800ms

// read the measured rawLux
status = OPT3001_ReadResultRawLux(&this->rawLux);
ioStatus = OPT3001_ReadResultRawLux(&this->rawLux);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

// convert rawLux to lux for debug
fprintf(stdout, "OPT3001 milli Lux: %ld\n", OPT3001_RawToMilliLux(this->rawLux));

// remains in turned off state after successful read, opt3001 turns off automatically after single shot read
toState(this, LIGHT_SENS_TURNED_OFF_STATE);
TO_STATE(this, LIGHT_SENS_TURNED_OFF_STATE);
return osOK;
case LIGHT_SENS_MEASURE_CONTINUOUSLY:
// set continuous measurements mode
status = OPT3001_WriteConfig(OPT3001_CONFIG_RANGE_NUMBER_AUTO_SCALE | \
ioStatus = OPT3001_WriteConfig(OPT3001_CONFIG_RANGE_NUMBER_AUTO_SCALE | \
OPT3001_CONFIG_CONVERSION_TIME_800_MS | \
OPT3001_CONFIG_MODE_CONTINUOUS | \
OPT3001_CONFIG_FAULT_COUNT_4 | \
OPT3001_CONFIG_LATCH_ENABLED);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
TO_STATE(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
return osOK;
case LIGHT_SENS_SET_LIMIT:
// set high limit from message payload
this->highLimit = message->payload.value;
status = OPT3001_WriteHighLimit(this->highLimit);
ioStatus = OPT3001_WriteHighLimit(this->highLimit);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_TURNED_OFF_STATE);
TO_STATE(this, LIGHT_SENS_TURNED_OFF_STATE);
return osOK;
}

Expand All @@ -212,37 +204,37 @@ static osStatus_t handleTurnedOff(LIGHT_SENS_Actor_t *this, message_t *message)
* @brief Cron read sensor data periodically, handle limit interrupts, or turn off the sensor.
*/
static osStatus_t handleContinuousMeasure(LIGHT_SENS_Actor_t *this, message_t *message) {
osStatus_t status;
osStatus_t ioStatus;

switch (message->event) {
case LIGHT_SENS_CRON_READ:
// read the measured rawLux on RTC cron
status = OPT3001_ReadResultRawLux(&this->rawLux);
if (status != osOK) return osError;
ioStatus = OPT3001_ReadResultRawLux(&this->rawLux);
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
TO_STATE(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
return osOK;
case LIGHT_SENS_TURN_OFF:
// turn off the sensor
status = OPT3001_WriteConfig(OPT3001_CONFIG_DEFAULT | OPT3001_CONFIG_MODE_SHUTDOWN);
ioStatus = OPT3001_WriteConfig(OPT3001_CONFIG_DEFAULT | OPT3001_CONFIG_MODE_SHUTDOWN);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_TURNED_OFF_STATE);
TO_STATE(this, LIGHT_SENS_TURNED_OFF_STATE);
return osOK;
case LIGHT_SENS_LIMIT_INT:
// read the measured rawLux overvalue
status = OPT3001_ReadResultRawLux(&this->rawLux);
if (status != osOK) return osError;
ioStatus = OPT3001_ReadResultRawLux(&this->rawLux);
if (ioStatus != osOK) return osError;

// TODO emit to event manager LIGHT_SENS_LIMIT_INT with this->rawLux payload

// swap limits to wait for lux returning below the high limit
status = OPT3001_WriteHighLimit(OPT3001_CONFIG_LIMIT_MAX)
ioStatus = OPT3001_WriteHighLimit(OPT3001_CONFIG_LIMIT_MAX)
| OPT3001_WriteLowLimit(this->highLimit);
if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_OUT_OF_RANGE_STATE);
TO_STATE(this, LIGHT_SENS_OUT_OF_RANGE_STATE);
return osOK;
}

Expand All @@ -253,45 +245,39 @@ static osStatus_t handleContinuousMeasure(LIGHT_SENS_Actor_t *this, message_t *m
* @brief Cron read sensor data, handle limit interrupts, or turn off the sensor.
*/
static osStatus_t handleOutOfRange(LIGHT_SENS_Actor_t *this, message_t *message) {
osStatus_t status;
osStatus_t ioStatus;

switch (message->event) {
case LIGHT_SENS_CRON_READ:
// still read the measured rawLux on RTC cron
status = OPT3001_ReadResultRawLux(&this->rawLux);
if (status != osOK) return osError;
ioStatus = OPT3001_ReadResultRawLux(&this->rawLux);
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_OUT_OF_RANGE_STATE);
TO_STATE(this, LIGHT_SENS_OUT_OF_RANGE_STATE);
return osOK;
case LIGHT_SENS_TURN_OFF:
// turn off the sensor
status = OPT3001_WriteConfig(OPT3001_CONFIG_DEFAULT | OPT3001_CONFIG_MODE_SHUTDOWN);
ioStatus = OPT3001_WriteConfig(OPT3001_CONFIG_DEFAULT | OPT3001_CONFIG_MODE_SHUTDOWN);

if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

toState(this, LIGHT_SENS_TURNED_OFF_STATE);
TO_STATE(this, LIGHT_SENS_TURNED_OFF_STATE);
return osOK;
case LIGHT_SENS_LIMIT_INT:
// read the measured rawLux OK overvalue
status = OPT3001_ReadResultRawLux(&this->rawLux);
if (status != osOK) return osError;
ioStatus = OPT3001_ReadResultRawLux(&this->rawLux);
if (ioStatus != osOK) return osError;
// TODO emit to event manager LIGHT_SENS_LIMIT_INT with this->rawLux payload, handle that this is OK value

// swap limits back to normal
status = OPT3001_WriteHighLimit(this->highLimit)
ioStatus = OPT3001_WriteHighLimit(this->highLimit)
| OPT3001_WriteLowLimit(OPT3001_CONFIG_LIMIT_MIN);
if (status != osOK) return osError;
if (ioStatus != osOK) return osError;

// back to continuous measure state
toState(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
TO_STATE(this, LIGHT_SENS_CONTINUOUS_MEASURE_STATE);
return osOK;
}

return osOK;
}

static osStatus_t toState(LIGHT_SENS_Actor_t *this, LIGHT_SENS_State_t nextState) {
// fprintf(stdout, "Light Sensor State from %s to %s\n", lightSensStatesNames[this->state], lightSensStatesNames[nextState]);
this->state = nextState;
return osOK;
}
Loading

0 comments on commit 8c30b37

Please sign in to comment.