M changelog.md => changelog.md +1 -0
@@ 11,6 11,7 @@
* `[audio][bluetooth]` Added Bluetooth A2DP playback
* `[settings]` Added sql script for file indexer DB schema
* `[settings][bluetooth]` Create "Add device" windows
+* `[hardware]` Slider driver (offline/online mode selection)
### Fixed
M module-bsp/board/linux/magnetometer/magnetometer.cpp => module-bsp/board/linux/magnetometer/magnetometer.cpp +8 -4
@@ 3,10 3,6 @@
#include "bsp/magnetometer/magnetometer.hpp"
-#include "bsp/BoardDefinitions.hpp"
-
-using namespace drivers;
-
static xQueueHandle qHandleIrq = NULL;
namespace bsp
@@ 31,5 27,13 @@ namespace bsp
{
return bsp::Board::Linux;
}
+
+ std::optional<bsp::KeyCodes> WorkerEventHandler()
+ {
+ return std::nullopt;
+ }
+
+ void enableIRQ()
+ {}
} // namespace magnetometer
} // namespace bsp
M module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp => module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp +0 -19
@@ 257,22 257,3 @@ void BluetoothCommon::set_irq(bool enable)
LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, true);
LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, true);
}
-
-extern "C"
-{
- void GPIO1_Combined_16_31_IRQHandler(void)
- {
- BaseType_t xHigherPriorityTaskWoken = 0;
- uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO1);
-
- if (irq_mask & (1 << BSP_BLUETOOTH_UART_CTS_PIN)) {
- LOG_DEBUG("CTS IRQ!\n");
- }
-
- // Clear all IRQs
- GPIO_PortClearInterruptFlags(GPIO1, irq_mask);
-
- // Switch context if necessary
- portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
- }
-};
A module-bsp/board/rt1051/bsp/magnetometer/ALS31300.cpp => module-bsp/board/rt1051/bsp/magnetometer/ALS31300.cpp +119 -0
@@ 0,0 1,119 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "ALS31300.hpp"
+
+namespace drivers::als31300
+{
+
+ conf_reg::conf_reg(whole_reg_t whole_reg)
+ {
+ user_eeprom = whole_reg & 0b11111;
+ int_latch_enable = (whole_reg >> 5) & 0b1;
+ channel_X_en = (whole_reg >> 6) & 0b1;
+ channel_Y_en = (whole_reg >> 7) & 0b1;
+ channel_Z_en = (whole_reg >> 8) & 0b1;
+ I2C_threshold = (whole_reg >> 9) & 0b1;
+ slave_addr = (whole_reg >> 10) & 0b1111111;
+ disable_slave_ADC = (whole_reg >> 17) & 0b1;
+ I2C_CRC_en = (whole_reg >> 18) & 0b1;
+ hall_mode = (whole_reg >> 19) & 0b11;
+ bandwidth = (whole_reg >> 21) & 0b111;
+ RESERVED = (whole_reg >> 24) & 0xFF;
+ }
+
+ conf_reg::operator whole_reg_t() const
+ {
+ return (user_eeprom & 0b11111) | (int_latch_enable & 0b1) << 5 | (channel_X_en & 0b1) << 6 |
+ (channel_Y_en & 0b1) << 7 | (channel_Z_en & 0b1) << 8 | (I2C_threshold & 0b1) << 9 |
+ (slave_addr & 0b1111111) << 10 | (disable_slave_ADC & 0b1) << 17 | (I2C_CRC_en & 0b1) << 18 |
+ (hall_mode & 0b11) << 19 | (bandwidth & 0b111) << 21 | (RESERVED & 0xFF) << 24;
+ }
+
+ int_reg::int_reg(whole_reg_t whole_reg)
+ {
+ int_X_threshold = whole_reg & 0b111111;
+ int_Y_threshold = (whole_reg >> 6) & 0b111111;
+ int_Z_threshold = (whole_reg >> 12) & 0b111111;
+ int_X_en = (whole_reg >> 18) & 0b1;
+ int_Y_en = (whole_reg >> 19) & 0b1;
+ int_Z_en = (whole_reg >> 20) & 0b1;
+ int_eeprom_en = (whole_reg >> 21) & 0b1;
+ int_eeprom_status = (whole_reg >> 22) & 0b1;
+ int_mode = (whole_reg >> 23) & 0b1;
+ int_threshold_signed = (whole_reg >> 24) & 0b1;
+ RESERVED = (whole_reg >> 25) & 0b1111111;
+ }
+
+ int_reg::operator whole_reg_t() const
+ {
+ return (int_X_threshold & 0b111111) | (int_Y_threshold & 0b111111) << 6 | (int_Z_threshold & 0b111111) << 12 |
+ (int_X_en & 0b1) << 18 | (int_Y_en & 0b1) << 19 | (int_Z_en & 0b1) << 20 | (int_eeprom_en & 0b1) << 21 |
+ (int_eeprom_status & 0b1) << 22 | (int_mode & 0b1) << 23 | (int_threshold_signed & 0b1) << 24 |
+ (RESERVED & 0b1111111) << 25;
+ }
+
+ pwr_reg::pwr_reg(whole_reg_t whole_reg)
+ {
+ sleep = whole_reg & 0b11;
+ I2C_loop_mode = (whole_reg >> 2) & 0b11;
+ count_max_LP_mode = (whole_reg >> 4) & 0b111;
+ RESERVED = (whole_reg >> 7) & 0x1FFFFFF;
+ }
+
+ pwr_reg::operator whole_reg_t() const
+ {
+ return (sleep & 0b11) | (I2C_loop_mode & 0b11) << 2 | (count_max_LP_mode & 0b111) << 4 |
+ (RESERVED & 0x1FFFFFF) << 7;
+ }
+
+ measurements_MSB_reg::measurements_MSB_reg(whole_reg_t whole_reg)
+ {
+ temperature_MSB = whole_reg & 0b111111;
+ int_flag = (whole_reg >> 6) & 0b1;
+ new_data_flag = (whole_reg >> 7) & 0b1;
+ Z_MSB = (whole_reg >> 8) & 0xFF;
+ Y_MSB = (whole_reg >> 16) & 0xFF;
+ X_MSB = (whole_reg >> 24) & 0xFF;
+ }
+
+ measurements_MSB_reg::operator whole_reg_t() const
+ {
+ return (temperature_MSB & 0b111111) | (int_flag & 0b1) << 6 | (new_data_flag & 0b1) << 7 | (Z_MSB & 0xFF) << 8 |
+ (Y_MSB & 0xFF) << 16 | (X_MSB & 0xFF) << 24;
+ }
+
+ measurements_LSB_reg::measurements_LSB_reg(whole_reg_t whole_reg)
+ {
+ temperature_LSB = whole_reg & 0b111111;
+ hall_mode_status = (whole_reg >> 6) & 0b11;
+ Z_LSB = (whole_reg >> 8) & 0b1111;
+ Y_LSB = (whole_reg >> 12) & 0b1111;
+ X_LSB = (whole_reg >> 16) & 0b1111;
+ int_eeprom_write_pending = (whole_reg >> 20) & 0b1;
+ RESERVED = (whole_reg >> 21) & 0x7FF;
+ }
+
+ measurements_LSB_reg::operator whole_reg_t() const
+ {
+ return (temperature_LSB & 0b111111) | (hall_mode_status & 0b11) << 6 | (Z_LSB & 0b1111) << 8 |
+ (Y_LSB & 0b1111) << 12 | (X_LSB & 0b1111) << 16 | (int_eeprom_write_pending & 0b1) << 20 |
+ (RESERVED & 0x7FF) << 21;
+ }
+
+ float temperature_convert(uint16_t raw_temperature)
+ {
+ const int32_t intermediate = raw_temperature - 1708;
+ return intermediate * 0.0737;
+ }
+
+ int16_t measurement_sign_convert(uint16_t raw_measurement, uint8_t bit_length)
+ {
+ // via: https://stackoverflow.com/questions/16946801/n-bit-2s-binary-to-decimal-in-c
+ const auto sign_flag = 1 << (bit_length - 1);
+ if (raw_measurement & sign_flag) {
+ raw_measurement |= -(1 << bit_length);
+ }
+ return raw_measurement;
+ }
+} // namespace drivers::als31300
A module-bsp/board/rt1051/bsp/magnetometer/ALS31300.hpp => module-bsp/board/rt1051/bsp/magnetometer/ALS31300.hpp +176 -0
@@ 0,0 1,176 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <cstdint>
+#include <cstring>
+#include <set>
+#include <chrono>
+
+// ALS31300 magnetometer driver
+namespace drivers::als31300
+{
+
+ // Note: this device returns 32-bit register values in MSB order
+
+ using whole_reg_t = uint32_t; // ALS31300 always talks 4 bytes
+
+ constexpr auto I2C_ADDRESS = 0x64;
+
+ // base ALS31300 register struct.
+ struct base_reg
+ {
+ virtual operator whole_reg_t() const = 0;
+ };
+
+ // REGISTER DEFINITIONS
+
+ // there is no 0x01 register
+ // --------
+ constexpr auto CONF_REG = 0x02;
+ struct conf_reg : base_reg
+ {
+ conf_reg(whole_reg_t whole_reg);
+ operator whole_reg_t() const override;
+ uint8_t user_eeprom : 5;
+ bool int_latch_enable : 1;
+ bool channel_X_en : 1;
+ bool channel_Y_en : 1;
+ bool channel_Z_en : 1;
+ bool I2C_threshold : 1;
+ uint8_t slave_addr : 7;
+ bool disable_slave_ADC : 1;
+ bool I2C_CRC_en : 1;
+ uint8_t hall_mode : 2;
+ uint8_t bandwidth : 3;
+ uint8_t RESERVED : 8;
+ };
+
+ constexpr auto CONF_REG_LATCH_disabled = 0b0;
+ constexpr auto CONF_REG_LATCH_enabled = 0b1;
+
+ constexpr auto CONF_REG_CHANNEL_disabled = 0b0;
+ constexpr auto CONF_REG_CHANNEL_enabled = 0b1;
+
+ constexpr auto CONF_REG_I2C_THRES_3v0 = 0b0;
+ constexpr auto CONF_REG_I2C_THRES_1v8 = 0b1;
+
+ // --------
+ constexpr auto INT_REG = 0x03;
+
+ struct int_reg : base_reg
+ {
+ int_reg(whole_reg_t whole_reg);
+ operator whole_reg_t() const override;
+ uint8_t int_X_threshold : 6;
+ uint8_t int_Y_threshold : 6;
+ uint8_t int_Z_threshold : 6;
+ bool int_X_en : 1;
+ bool int_Y_en : 1;
+ bool int_Z_en : 1;
+ bool int_eeprom_en : 1;
+ bool int_eeprom_status : 1;
+ bool int_mode : 1;
+ bool int_threshold_signed : 1;
+ uint8_t RESERVED : 7;
+ };
+
+ constexpr auto INT_REG_INT_CHANNEL_disabled = 0b0;
+ constexpr auto INT_REG_INT_CHANNEL_enabled = 0b1;
+
+ constexpr auto INT_REG_INT_MODE_threshold = 0b0;
+ constexpr auto INT_REG_INT_MODE_delta = 0b1;
+
+ constexpr auto INT_REG_THRESHOLD_absolute = 0b0;
+ constexpr auto INT_REG_THRESHOLD_signed = 0b1;
+
+ constexpr auto INT_REG_INT_EEPROM_disable = 0b0;
+ constexpr auto INT_REG_INT_EEPROM_enable = 0b1;
+
+ // --------
+ constexpr auto PWR_REG = 0x27;
+
+ struct pwr_reg : base_reg
+ {
+ pwr_reg(whole_reg_t whole_reg);
+ operator whole_reg_t() const override;
+ uint8_t sleep : 2;
+ uint8_t I2C_loop_mode : 2;
+ uint8_t count_max_LP_mode : 3;
+ uint32_t RESERVED : 25;
+ };
+
+ constexpr auto PWR_REG_SLEEP_MODE_active = 0b00;
+ constexpr auto PWR_REG_SLEEP_MODE_sleep = 0b01;
+ constexpr auto PWR_REG_SLEEP_MODE_LPDCM = 0b10; // Low-Power Duty Cycle Mode
+
+ constexpr auto PWR_REG_LOOP_MODE_single = 0b00;
+ constexpr auto PWR_REG_LOOP_MODE_fast_loop = 0b01;
+ constexpr auto PWR_REG_LOOP_MODE_full_loop = 0b10;
+
+ enum PWR_REG_SLEEP_MODE
+ {
+ active = PWR_REG_SLEEP_MODE_active,
+ sleep = PWR_REG_SLEEP_MODE_sleep,
+ periodic_active = PWR_REG_SLEEP_MODE_LPDCM,
+ };
+
+ constexpr auto PWR_ON_DELAY_MS = 1; // spec'd as 600µs at most
+
+ // --------
+ constexpr auto MEASUREMENTS_MSB_REG = 0x28;
+
+ struct measurements_MSB_reg : base_reg
+ {
+ measurements_MSB_reg(whole_reg_t whole_reg);
+ operator whole_reg_t() const override;
+ uint8_t temperature_MSB : 6;
+ bool int_flag : 1;
+ bool new_data_flag : 1;
+ uint8_t Z_MSB : 8;
+ uint8_t Y_MSB : 8;
+ uint8_t X_MSB : 8;
+ };
+
+ constexpr auto MEAS_REG_NEW_DATA_not_avail = 0b0;
+ constexpr auto MEAS_REG_NEW_DATA_available = 0b1;
+
+ // --------
+ constexpr auto MEASUREMENTS_LSB_REG = 0x29;
+
+ struct measurements_LSB_reg : base_reg
+ {
+ measurements_LSB_reg(whole_reg_t whole_reg);
+ operator whole_reg_t() const override;
+ uint8_t temperature_LSB : 6;
+ uint8_t hall_mode_status : 2;
+ uint8_t Z_LSB : 4;
+ uint8_t Y_LSB : 4;
+ uint8_t X_LSB : 4;
+ bool int_eeprom_write_pending : 1;
+ uint16_t RESERVED : 11;
+ };
+
+ float temperature_convert(uint16_t raw_temperature);
+
+ // NOTE: device sensitivity HW fixed at 4 LSB/Gauss == 0.4 LSB/mT
+ // All measurements are supposed to be raw 4 LSB/Gauss. No need to introduce fractions
+ constexpr auto MEASUREMENTS_REG_bitlength_full_scale = 12;
+
+ int16_t measurement_sign_convert(uint16_t raw_measurement,
+ uint8_t bit_length = MEASUREMENTS_REG_bitlength_full_scale);
+ // --------
+ constexpr uint8_t CUSTOMER_ACCESS_REG = 0x35;
+ constexpr whole_reg_t CUSTOMER_ACCESS_REG_code = 0x2C413534;
+
+ // --------
+
+ /// give eeprom registers time to complete WRITE
+ const std::set<uint8_t> EEPROM_REGS = {CUSTOMER_ACCESS_REG, CONF_REG, INT_REG};
+
+ using std::chrono_literals::operator""ms;
+ constexpr auto EEPROM_REG_WRITE_DELAY_MS = 60ms; // docs say 50ms, +10ms for good measure
+
+ /////////////////////
+} // namespace drivers::als31300
M module-bsp/board/rt1051/bsp/magnetometer/magnetometer.cpp => module-bsp/board/rt1051/bsp/magnetometer/magnetometer.cpp +280 -3
@@ 3,23 3,83 @@
#include "bsp/magnetometer/magnetometer.hpp"
+#include <module-utils/Utils.hpp> // for byte conversion functions. it is included first because of magic enum define
+
+#include "ALS31300.hpp"
#include "bsp/BoardDefinitions.hpp"
+
#include "drivers/i2c/DriverI2C.hpp"
-#include "fsl_common.h"
+#include <fsl_common.h>
+#include <timers.h>
using namespace drivers;
+using namespace utils;
static std::shared_ptr<drivers::DriverI2C> i2c;
-static drivers::I2CAddress addr = {.deviceAddress = 0x64, .subAddressSize = 1};
+
+static I2CAddress addr = {.deviceAddress = als31300::I2C_ADDRESS, .subAddressSize = 1};
+
+union i2c_buf_t
+{
+ uint8_t buf[sizeof(als31300::whole_reg_t)];
+ als31300::whole_reg_t whole_reg;
+};
+
+static i2c_buf_t i2c_buf;
static xQueueHandle qHandleIrq = NULL;
namespace bsp
{
-
namespace magnetometer
{
+ std::shared_ptr<DriverGPIO> gpio;
+
+ bsp::KeyCodes current_parsed = bsp::KeyCodes::Undefined;
+
+ static TimerHandle_t timerHandle;
+ static constexpr uint16_t MAGNETOMETER_POLL_INTERVAL_MS = 500;
+
+ static void TimerHandler(TimerHandle_t xTimer)
+ {
+ if (qHandleIrq != nullptr) {
+ uint8_t val = 0x01;
+ xQueueSend(qHandleIrq, &val, 0);
+ }
+ }
+
+ bool setActive(als31300::PWR_REG_SLEEP_MODE sleep_mode);
+
+ bool i2cRead(const uint8_t reg_addr, als31300::whole_reg_t &whole_reg)
+ {
+ addr.subAddress = reg_addr;
+ if (i2c->Read(addr, i2c_buf.buf, sizeof(als31300::whole_reg_t)) != sizeof(als31300::whole_reg_t)) {
+ return false;
+ }
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ // magnetometr talks big endian
+ i2c_buf.whole_reg = swapBytes(i2c_buf.whole_reg);
+#endif
+ whole_reg = i2c_buf.whole_reg;
+ return true;
+ }
+
+ bool i2cWrite(const uint8_t reg_addr, const als31300::whole_reg_t whole_reg)
+ {
+ addr.subAddress = reg_addr;
+#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
+ // magnetometer talks big endian
+ i2c_buf.whole_reg = swapBytes(whole_reg);
+#else
+ i2c_buf.whole_reg = whole_reg;
+#endif
+ auto wrote = i2c->Write(addr, i2c_buf.buf, sizeof(als31300::whole_reg_t)) == sizeof(als31300::whole_reg_t);
+ if (als31300::EEPROM_REGS.count(reg_addr) == 1) {
+ vTaskDelay(pdMS_TO_TICKS(als31300::EEPROM_REG_WRITE_DELAY_MS.count()));
+ }
+ return wrote;
+ }
int32_t init(xQueueHandle qHandle)
{
@@ 28,9 88,162 @@ namespace bsp
DriverI2CParams{.baudrate = static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_I2C_BAUDRATE)});
qHandleIrq = qHandle;
+
+ // any configuration must be proceeded in active state
+ setActive(als31300::PWR_REG_SLEEP_MODE::active);
+
+ // GET WRITE ACCESS
+ if (!i2cWrite(als31300::CUSTOMER_ACCESS_REG, als31300::CUSTOMER_ACCESS_REG_code)) {
+ LOG_ERROR("magneto: CANNOT INIT SLIDER SENSOR");
+ return kStatus_Fail;
+ }
+
+ // CONFIGURATION register read
+ als31300::whole_reg_t read_reg;
+ i2cRead(als31300::CONF_REG, read_reg);
+ const als31300::conf_reg current_reg_conf(read_reg);
+ LOG_DEBUG("CONF read:\t%" PRIu32, static_cast<uint32_t>(current_reg_conf));
+ als31300::conf_reg reg_conf = current_reg_conf;
+ reg_conf.I2C_threshold = als31300::CONF_REG_I2C_THRES_1v8;
+ reg_conf.int_latch_enable = als31300::CONF_REG_LATCH_disabled; // we want to detect stable positions
+ reg_conf.channel_X_en = als31300::CONF_REG_CHANNEL_enabled;
+ reg_conf.channel_Y_en = als31300::CONF_REG_CHANNEL_enabled;
+ reg_conf.channel_Z_en = als31300::CONF_REG_CHANNEL_disabled;
+ reg_conf.bandwidth = 1; // longest unit measurement
+ if (current_reg_conf != reg_conf) {
+ assert(i2cWrite(als31300::CONF_REG, reg_conf));
+ LOG_DEBUG("CONF wrote:\t%" PRIu32, static_cast<uint32_t>(reg_conf));
+
+ i2cRead(als31300::CONF_REG, read_reg);
+ LOG_DEBUG("CONF verify:\t%" PRIu32, static_cast<uint32_t>(als31300::conf_reg(read_reg)));
+ }
+ else {
+ LOG_DEBUG("CONF is fine, sparing a write");
+ }
+
+ // INTERRUPTS register
+ i2cRead(als31300::INT_REG, read_reg);
+ const als31300::int_reg current_reg_int = read_reg;
+ LOG_DEBUG("INT read:\t%" PRIu32, static_cast<uint32_t>(current_reg_int));
+ als31300::int_reg reg_int = current_reg_int;
+ reg_int.int_eeprom_en = als31300::INT_REG_INT_EEPROM_disable;
+ reg_int.int_mode = als31300::INT_REG_INT_MODE_threshold;
+ reg_int.int_threshold_signed = als31300::INT_REG_THRESHOLD_absolute;
+ reg_int.int_X_en = als31300::INT_REG_INT_CHANNEL_disabled;
+ reg_int.int_Y_en = als31300::INT_REG_INT_CHANNEL_disabled;
+ reg_int.int_Z_en = als31300::INT_REG_INT_CHANNEL_disabled;
+ reg_int.int_X_threshold = 1;
+ reg_int.int_Y_threshold = 4;
+ reg_int.int_Z_threshold = 0;
+ if (current_reg_int != reg_int) {
+ assert(i2cWrite(als31300::INT_REG, reg_int));
+ LOG_DEBUG("INT wrote:\t%" PRIu32, static_cast<uint32_t>(reg_int));
+
+ i2cRead(als31300::INT_REG, read_reg);
+ LOG_DEBUG("INT verify:\t%" PRIu32, static_cast<uint32_t>(als31300::int_reg(read_reg)));
+ }
+ else {
+ LOG_DEBUG("INT is fine, sparing a write");
+ }
+
+ // INTERRUPT PIN
+ gpio =
+ DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::MAGNETOMETER_GPIO), DriverGPIOParams{});
+
+ // INTERRUPT PIN
+ gpio->ClearPortInterrupts(1 << static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ));
+ gpio->ConfPin(DriverGPIOPinParams{.dir = DriverGPIOPinParams::Direction::Input,
+ .irqMode = DriverGPIOPinParams::InterruptMode::IntFallingEdge,
+ .pin = static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ)});
+ // NOTE: irq not yet enabled
+ // this version uses timer to poll the sensor
+ // the timer requests to read the magnetometer periodically
+ if (timerHandle == nullptr) {
+ timerHandle = xTimerCreate(
+ "SliderTimer", pdMS_TO_TICKS(MAGNETOMETER_POLL_INTERVAL_MS), true, nullptr, TimerHandler);
+ if (timerHandle == nullptr) {
+ LOG_FATAL("Could not create the timer for Headset insertion/removal detection");
+ return kStatus_Fail;
+ }
+ }
+
+ // POWER register
+ i2cRead(als31300::PWR_REG, read_reg);
+ const als31300::pwr_reg current_reg_pwr = read_reg;
+ LOG_DEBUG("POWER read:\t%" PRIu32, static_cast<uint32_t>(current_reg_pwr));
+ als31300::pwr_reg reg_pwr = current_reg_pwr;
+ reg_pwr.I2C_loop_mode = als31300::PWR_REG_LOOP_MODE_single; // we don't want constant data flow
+ reg_pwr.sleep = als31300::PWR_REG_SLEEP_MODE_active;
+ reg_pwr.count_max_LP_mode = 3U; // get an update every 6 - 500, 7 - 1000 ms
+
+ i2cWrite(als31300::PWR_REG, reg_pwr);
+ LOG_DEBUG("POWER wrote:\t%" PRIu32, static_cast<uint32_t>(reg_pwr));
+
+ xTimerStart(timerHandle, 1000);
+
return kStatus_Success;
}
+ std::pair<bool, Measurements> getMeasurement()
+ {
+ als31300::whole_reg_t read_reg;
+
+ if (!i2cRead(als31300::MEASUREMENTS_MSB_REG, read_reg)) {
+ LOG_DEBUG("magneto: CANNOT READ");
+ return std::make_pair(false, Measurements()); // todo: nullopt
+ }
+ // is there anything new ?
+ als31300::measurements_MSB_reg reg_msb = read_reg;
+
+ if (reg_msb.int_flag == true) {
+ LOG_DEBUG("magneto: INT flag in register");
+ }
+
+ if (reg_msb.new_data_flag != als31300::MEAS_REG_NEW_DATA_available) {
+ return std::make_pair(false, Measurements());
+ }
+ else {
+ if (reg_msb.int_flag == true) {
+ // clear INT flag
+ if (!i2cWrite(als31300::MEASUREMENTS_MSB_REG, reg_msb)) {
+ return std::make_pair(false, Measurements()); // todo: null opt
+ }
+ }
+ Measurements meas;
+
+ i2cRead(als31300::MEASUREMENTS_LSB_REG, read_reg);
+
+ als31300::measurements_LSB_reg reg_lsb = read_reg;
+
+ meas.X = als31300::measurement_sign_convert(reg_msb.X_MSB << 4 | reg_lsb.X_LSB);
+ meas.Y = als31300::measurement_sign_convert(reg_msb.Y_MSB << 4 | reg_lsb.Z_LSB);
+ meas.Z = als31300::measurement_sign_convert(reg_msb.Z_MSB << 4 | reg_lsb.Z_LSB);
+
+ return std::pair(true, meas);
+ }
+ }
+
+ bool setActive(als31300::PWR_REG_SLEEP_MODE sleep_mode)
+ {
+ // POWER register
+ als31300::whole_reg_t read_reg;
+
+ if (!i2cRead(als31300::PWR_REG, read_reg)) {
+ return false;
+ }
+ als31300::pwr_reg reg_pwr = read_reg;
+ reg_pwr.sleep = sleep_mode;
+
+ if (!i2cWrite(als31300::PWR_REG, reg_pwr)) {
+ return false;
+ }
+ if (sleep_mode == als31300::PWR_REG_SLEEP_MODE::active ||
+ sleep_mode == als31300::PWR_REG_SLEEP_MODE::periodic_active) {
+ vTaskDelay(pdMS_TO_TICKS(als31300::PWR_ON_DELAY_MS)); // give it some time to wake up
+ }
+ return true;
+ }
+
bool isPresent(void)
{
uint8_t buf;
@@ 43,6 256,65 @@ namespace bsp
return true;
}
+ bsp::KeyCodes parse(const Measurements &measurements)
+ {
+ // X is tri-stable
+ const auto X_lower_boundary = -150;
+ const auto X_upper_boundary = 150;
+ const auto X_lower_threshold = -65;
+ const auto X_upper_threshold = 60;
+ // Y is bi-stable
+ const auto Y_threshold = -175;
+ // Y is used only for proofing X, so no strict thresholds
+ // Z is useless
+
+ if (measurements.X > X_lower_boundary && measurements.X < X_upper_boundary) {
+ if (measurements.X < X_lower_threshold) {
+ if (measurements.Y > Y_threshold) {
+ return bsp::KeyCodes::SSwitchDown;
+ }
+ }
+ else if (measurements.X > X_upper_threshold) {
+ if (measurements.Y > Y_threshold) {
+ return bsp::KeyCodes::SSwitchUp;
+ }
+ }
+ else {
+ if (measurements.Y < Y_threshold) {
+ return bsp::KeyCodes::SSwitchMid;
+ }
+ }
+ }
+ return bsp::KeyCodes::Undefined;
+ }
+
+ std::optional<bsp::KeyCodes> WorkerEventHandler()
+ {
+ // try to get new data from active magneto
+ setActive(als31300::PWR_REG_SLEEP_MODE::active);
+ auto [new_data, measurement] = getMeasurement();
+ setActive(als31300::PWR_REG_SLEEP_MODE::sleep);
+ if (new_data == true) {
+ auto incoming_parsed = parse(measurement);
+ if (incoming_parsed != bsp::KeyCodes::Undefined and incoming_parsed != current_parsed) {
+ current_parsed = incoming_parsed;
+ return current_parsed;
+ }
+ }
+ return std::nullopt;
+ }
+
+ BaseType_t IRQHandler()
+ {
+ gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ));
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ if (qHandleIrq != NULL) {
+ uint8_t val = 0x01;
+ xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
+ }
+ return xHigherPriorityTaskWoken;
+ }
+
bsp::Board GetBoard(void)
{
if (isPresent()) {
@@ 50,5 322,10 @@ namespace bsp
}
return bsp::Board::T3;
}
+
+ void enableIRQ()
+ {
+ gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ));
+ }
} // namespace magnetometer
} // namespace bsp
M module-bsp/board/rt1051/bsp/torch/torch.cpp => module-bsp/board/rt1051/bsp/torch/torch.cpp +4 -3
@@ 12,15 12,16 @@
using namespace drivers;
static std::shared_ptr<drivers::DriverI2C> i2c;
-static drivers::I2CAddress addr = {.deviceAddress = 0x63, .subAddressSize = 1};
-
-static xQueueHandle qHandleIrq = NULL;
namespace bsp
{
namespace torch
{
+ static xQueueHandle qHandleIrq = NULL;
+
+ static I2CAddress addr = {.deviceAddress = 0x63, .subAddressSize = 1};
+
std::shared_ptr<DriverGPIO> gpio;
const unsigned short max_current_mA = 150;
ColourTemperature currentColourTemp = warmest;
M module-bsp/board/rt1051/common/irq/irq_gpio.cpp => module-bsp/board/rt1051/common/irq/irq_gpio.cpp +29 -0
@@ 12,6 12,8 @@
#include "bsp/battery-charger/battery_charger.hpp"
#include "bsp/cellular/bsp_cellular.hpp"
#include "bsp/keyboard/keyboard.hpp"
+#include "bsp/BoardDefinitions.hpp"
+#include "bsp/magnetometer/magnetometer.hpp"
#if 0 // TODO:M.P implement the rest of BSP drivers
@@ 29,6 31,7 @@ namespace bsp
void irq_gpio_Init(void)
{
DisableIRQ(GPIO1_Combined_0_15_IRQn);
+ DisableIRQ(GPIO1_Combined_16_31_IRQn);
DisableIRQ(GPIO2_Combined_0_15_IRQn);
DisableIRQ(GPIO2_Combined_16_31_IRQn);
DisableIRQ(GPIO3_Combined_16_31_IRQn);
@@ 45,6 48,9 @@ namespace bsp
EnableIRQ(GPIO1_Combined_0_15_IRQn);
NVIC_SetPriority(GPIO1_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
+ EnableIRQ(GPIO1_Combined_16_31_IRQn);
+ NVIC_SetPriority(GPIO1_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
+
EnableIRQ(GPIO2_Combined_0_15_IRQn);
NVIC_SetPriority(GPIO2_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
@@ 74,6 80,29 @@ namespace bsp
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
+ void GPIO1_Combined_16_31_IRQHandler(void)
+ {
+ BaseType_t xHigherPriorityTaskWoken = 0;
+ uint32_t irq_mask = GPIO_GetPinsInterruptFlags(GPIO1);
+
+ if (irq_mask & (1 << static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ))) {
+ xHigherPriorityTaskWoken |= bsp::magnetometer::IRQHandler();
+ LOG_DEBUG("magneto IRQ! >%s<",
+ GPIO_PinRead(GPIO1, static_cast<uint32_t>(BoardDefinitions::MAGNETOMETER_IRQ)) ? "high"
+ : "low");
+ }
+
+ if (irq_mask & (1 << BSP_BLUETOOTH_UART_CTS_PIN)) {
+ LOG_DEBUG("CTS IRQ!");
+ }
+
+ // Clear all IRQs
+ GPIO_PortClearInterruptFlags(GPIO1, irq_mask);
+
+ // Switch context if necessary
+ portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
+ }
+
void GPIO2_Combined_0_15_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = 0;
M module-bsp/board/rt1051/common/pin_mux.c => module-bsp/board/rt1051/common/pin_mux.c +10 -0
@@ 308,6 308,7 @@ void PINMUX_InitBootPins(void)
PINMUX_InitJACKDET();
PINMUX_InitVibrator();
PINMUX_InitTorch();
+ PINMUX_InitMagnetometer();
}
/*
@@ 1487,6 1488,15 @@ void PINMUX_InitTorch(void)
PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_KEEPER | PAD_CONFIG_HYSTERESIS_DISABLED);
}
+void PINMUX_InitMagnetometer(void)
+{
+ IOMUXC_SetPinMux(PINMUX_MAGNETOMETER_IRQ_PIN, 0U);
+ IOMUXC_SetPinConfig(PINMUX_MAGNETOMETER_IRQ_PIN,
+
+ PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
+ PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_22kOhm);
+}
+
/***********************************************************************************************************************
* EOF
**********************************************************************************************************************/
M module-bsp/board/rt1051/common/pin_mux.h => module-bsp/board/rt1051/common/pin_mux.h +3 -0
@@ 217,6 217,9 @@ extern "C"
#define PINMUX_TORCH_EN_PIN IOMUXC_GPIO_AD_B1_05_GPIO1_IO21
void PINMUX_InitTorch(void);
+#define PINMUX_MAGNETOMETER_IRQ_PIN IOMUXC_GPIO_AD_B1_04_GPIO1_IO20
+ void PINMUX_InitMagnetometer(void);
+
#if defined(__cplusplus)
}
#endif
M module-bsp/bsp/magnetometer/magnetometer.hpp => module-bsp/bsp/magnetometer/magnetometer.hpp +36 -12
@@ 1,23 1,47 @@
#pragma once
-#include <stdint.h>
+#include <bsp/keyboard/key_codes.hpp>
-extern "C" {
- #include "FreeRTOS.h"
- #include "task.h"
- #include "queue.h"
+#include <cstdint>
+#include <optional>
+
+extern "C"
+{
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
}
#include "../common.hpp"
-namespace bsp {
+namespace bsp
+{
-namespace magnetometer{
+ namespace magnetometer
+ {
- int32_t init(xQueueHandle qHandle);
+ int32_t init(xQueueHandle qHandle);
- bool isPresent(void);
- bsp::Board GetBoard(void);
-}
+ bool isPresent(void);
-}
+ bsp::Board GetBoard(void);
+
+ /// unit: 4 LSB/Gauss
+ struct Measurements
+ {
+ int16_t X;
+ int16_t Y;
+ int16_t Z;
+ };
+
+ /// returns a pair of <new_data_read?, values>
+ std::pair<bool, Measurements> getMeasurement();
+
+ bsp::KeyCodes parse(const Measurements &measurements);
+ std::optional<bsp::KeyCodes> WorkerEventHandler();
+
+ BaseType_t IRQHandler();
+ void enableIRQ();
+ } // namespace magnetometer
+
+} // namespace bsp
M module-bsp/targets/Target_RT1051.cmake => module-bsp/targets/Target_RT1051.cmake +3 -2
@@ 95,8 95,9 @@ set(BOARD_SOURCES ${BOARD_SOURCES}
"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/drivers/RT1051DriverDMAMux.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/drivers/RT1051DriverDMA.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/drivers/RT1051DriverGPIO.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/magnetometer/magnetometer.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/torch/torch.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/magnetometer/magnetometer.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/magnetometer/ALS31300.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/torch/torch.cpp"
CACHE INTERNAL ""
)
M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +14 -2
@@ 43,7 43,7 @@ extern "C"
bool WorkerEvent::handleMessage(uint32_t queueID)
{
- QueueHandle_t queue = queues[queueID];
+ xQueueHandle queue = queues[queueID];
// service queue
if (queueID == static_cast<uint32_t>(WorkerEventQueues::queueService)) {
@@ 173,6 173,18 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
}
}
+ if (queueID == static_cast<uint32_t>(WorkerEventQueues::queueMagnetometerIRQ)) {
+ uint8_t notification;
+ if (xQueueReceive(queue, ¬ification, 0) != pdTRUE) {
+ return false;
+ }
+
+ if (std::optional<bsp::KeyCodes> key = bsp::magnetometer::WorkerEventHandler()) {
+ LOG_DEBUG("magneto IRQ handler: %s", c_str(*key));
+ processKeyEvent(bsp::KeyEvents::Pressed, *key);
+ }
+ }
+
return true;
}
@@ 189,7 201,7 @@ bool WorkerEvent::init(std::list<sys::WorkerQueueInfo> queues)
bsp::rtc_Init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueRTC)]);
bsp::harness::Init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueHarness)]);
bsp::cellular::init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueCellular)]);
- bsp::magnetometer::init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueMagnetometer)]);
+ bsp::magnetometer::init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueMagnetometerIRQ)]);
bsp::torch::init(qhandles[static_cast<int32_t>(WorkerEventQueues::queueTorch)]);
time_t timestamp;
M module-services/service-evtmgr/WorkerEvent.hpp => module-services/service-evtmgr/WorkerEvent.hpp +1 -1
@@ 37,7 37,7 @@ enum class WorkerEventQueues
queueRTC,
queueHarness,
queueCellular,
- queueMagnetometer,
+ queueMagnetometerIRQ,
queueTorch,
};
M module-utils/Utils.hpp => module-utils/Utils.hpp +11 -0
@@ 182,4 182,15 @@ namespace utils
return false;
}
+
+ static inline uint32_t swapBytes(uint32_t toSwap)
+ {
+#ifdef __GNUC__
+ return __builtin_bswap32(toSwap);
+#else
+ return ((((toSwap)&0xff000000) >> 24) | (((toSwap)&0x00ff0000) >> 8) | (((toSwap)&0x0000ff00) << 8) |
+ (((toSwap)&0x000000ff) << 24));
+#endif
+ }
+
} // namespace utils
M module-utils/test/unittest_utils.cpp => module-utils/test/unittest_utils.cpp +28 -0
@@ 180,3 180,31 @@ TEST_CASE("Get value from string")
REQUIRE(testValue == target);
}
}
+
+TEST_CASE("Swap endianness")
+{
+ uint32_t as_long = 0x11223344;
+
+ SECTION("endiannes check")
+ {
+ uint8_t *as_array;
+ as_array = reinterpret_cast<uint8_t *>(&as_long);
+ if (as_array[0] == 0x11) {
+ REQUIRE(BYTE_ORDER == BIG_ENDIAN);
+ }
+ else if (as_array[0] == 0x44) {
+ REQUIRE(BYTE_ORDER == LITTLE_ENDIAN);
+ }
+ else {
+ FAIL("cannot determine endiannes");
+ }
+ }
+ SECTION("swap endiannes uint32")
+ {
+ uint32_t as_long_swapped = utils::swapBytes(as_long);
+ REQUIRE(((as_long >> 8 * 3) & 0xFF) == ((as_long_swapped >> 8 * 0) & 0xFF));
+ REQUIRE(((as_long >> 8 * 2) & 0xFF) == ((as_long_swapped >> 8 * 1) & 0xFF));
+ REQUIRE(((as_long >> 8 * 1) & 0xFF) == ((as_long_swapped >> 8 * 2) & 0xFF));
+ REQUIRE(((as_long >> 8 * 0) & 0xFF) == ((as_long_swapped >> 8 * 3) & 0xFF));
+ }
+}