Formatting the C/C++ files
This commit is contained in:
@@ -9,56 +9,55 @@
|
||||
#include <array>
|
||||
|
||||
bool BMA223::detect() {
|
||||
if (FRToSI2C::probe(BMA223_ADDRESS)) {
|
||||
//Read chip id to ensure its not an address collision
|
||||
uint8_t id = 0;
|
||||
if (FRToSI2C::Mem_Read(BMA223_ADDRESS, BMA223_BGW_CHIPID, &id, 1)) {
|
||||
return id == 0b11111000;
|
||||
}
|
||||
}
|
||||
if (FRToSI2C::probe(BMA223_ADDRESS)) {
|
||||
// Read chip id to ensure its not an address collision
|
||||
uint8_t id = 0;
|
||||
if (FRToSI2C::Mem_Read(BMA223_ADDRESS, BMA223_BGW_CHIPID, &id, 1)) {
|
||||
return id == 0b11111000;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = { //
|
||||
//
|
||||
{ BMA223_PMU_RANGE, 0b00000011, 0 }, //2G range
|
||||
{ BMA223_PMU_BW, 0b00001101, 0 }, //250Hz filter
|
||||
{ BMA223_PMU_LPW, 0b00000000, 0 }, //Full power
|
||||
{ BMA223_ACCD_HBW, 0b00000000, 0 }, //filtered data out
|
||||
{ BMA223_INT_OUT_CTRL, 0b00001010, 0 }, //interrupt active low and OD to get it hi-z
|
||||
{ BMA223_INT_RST_LATCH, 0b10000000, 0 }, //interrupt active low and OD to get it hi-z
|
||||
{ BMA223_INT_EN_0, 0b01000000, 0 }, //Enable orientation
|
||||
{ BMA223_INT_A, 0b00100111, 0 }, //Setup orientation detection
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = {
|
||||
//
|
||||
//
|
||||
{BMA223_PMU_RANGE, 0b00000011, 0}, // 2G range
|
||||
{BMA223_PMU_BW, 0b00001101, 0}, // 250Hz filter
|
||||
{BMA223_PMU_LPW, 0b00000000, 0}, // Full power
|
||||
{BMA223_ACCD_HBW, 0b00000000, 0}, // filtered data out
|
||||
{BMA223_INT_OUT_CTRL, 0b00001010, 0}, // interrupt active low and OD to get it hi-z
|
||||
{BMA223_INT_RST_LATCH, 0b10000000, 0}, // interrupt active low and OD to get it hi-z
|
||||
{BMA223_INT_EN_0, 0b01000000, 0}, // Enable orientation
|
||||
{BMA223_INT_A, 0b00100111, 0}, // Setup orientation detection
|
||||
|
||||
//
|
||||
};
|
||||
//
|
||||
};
|
||||
bool BMA223::initalize() {
|
||||
//Setup acceleration readings
|
||||
//2G range
|
||||
//bandwidth = 250Hz
|
||||
//High pass filter on (Slow compensation)
|
||||
//Turn off IRQ output pins
|
||||
//Orientation recognition in symmetrical mode
|
||||
// Hysteresis is set to ~ 16 counts
|
||||
//Theta blocking is set to 0b10
|
||||
|
||||
return FRToSI2C::writeRegistersBulk(BMA223_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
// Setup acceleration readings
|
||||
// 2G range
|
||||
// bandwidth = 250Hz
|
||||
// High pass filter on (Slow compensation)
|
||||
// Turn off IRQ output pins
|
||||
// Orientation recognition in symmetrical mode
|
||||
// Hysteresis is set to ~ 16 counts
|
||||
// Theta blocking is set to 0b10
|
||||
|
||||
return FRToSI2C::writeRegistersBulk(BMA223_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
}
|
||||
|
||||
void BMA223::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
|
||||
//The BMA is odd in that its output data width is only 8 bits
|
||||
//And yet there are MSB and LSB registers _sigh_.
|
||||
uint8_t sensorData[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
if (FRToSI2C::Mem_Read(BMA223_ADDRESS, BMA223_ACCD_X_LSB, sensorData, 6) == false) {
|
||||
x = y = z = 0;
|
||||
return;
|
||||
}
|
||||
//Shift 6 to make its range ~= the other accelerometers
|
||||
x = sensorData[1] << 6;
|
||||
y = sensorData[3] << 6;
|
||||
z = sensorData[5] << 6;
|
||||
// The BMA is odd in that its output data width is only 8 bits
|
||||
// And yet there are MSB and LSB registers _sigh_.
|
||||
uint8_t sensorData[6] = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
if (FRToSI2C::Mem_Read(BMA223_ADDRESS, BMA223_ACCD_X_LSB, sensorData, 6) == false) {
|
||||
x = y = z = 0;
|
||||
return;
|
||||
}
|
||||
// Shift 6 to make its range ~= the other accelerometers
|
||||
x = sensorData[1] << 6;
|
||||
y = sensorData[3] << 6;
|
||||
z = sensorData[5] << 6;
|
||||
}
|
||||
|
||||
@@ -4,112 +4,112 @@
|
||||
* Created on: 29 May 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include <Buttons.hpp>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "gui.hpp"
|
||||
#include "task.h"
|
||||
#include <Buttons.hpp>
|
||||
uint32_t lastButtonTime = 0;
|
||||
|
||||
ButtonState getButtonState() {
|
||||
/*
|
||||
* Read in the buttons and then determine if a state change needs to occur
|
||||
*/
|
||||
/*
|
||||
* Read in the buttons and then determine if a state change needs to occur
|
||||
*/
|
||||
|
||||
/*
|
||||
* If the previous state was 00 Then we want to latch the new state if
|
||||
* different & update time
|
||||
* If the previous state was !00 Then we want to search if we trigger long
|
||||
* press (buttons still down), or if release we trigger press
|
||||
* (downtime>filter)
|
||||
*/
|
||||
static uint8_t previousState = 0;
|
||||
static uint32_t previousStateChange = 0;
|
||||
const uint16_t timeout = 400;
|
||||
uint8_t currentState;
|
||||
currentState = (getButtonA()) << 0;
|
||||
currentState |= (getButtonB()) << 1;
|
||||
/*
|
||||
* If the previous state was 00 Then we want to latch the new state if
|
||||
* different & update time
|
||||
* If the previous state was !00 Then we want to search if we trigger long
|
||||
* press (buttons still down), or if release we trigger press
|
||||
* (downtime>filter)
|
||||
*/
|
||||
static uint8_t previousState = 0;
|
||||
static uint32_t previousStateChange = 0;
|
||||
const uint16_t timeout = 400;
|
||||
uint8_t currentState;
|
||||
currentState = (getButtonA()) << 0;
|
||||
currentState |= (getButtonB()) << 1;
|
||||
|
||||
if (currentState)
|
||||
lastButtonTime = xTaskGetTickCount();
|
||||
if (currentState == previousState) {
|
||||
if (currentState == 0)
|
||||
return BUTTON_NONE;
|
||||
if ((xTaskGetTickCount() - previousStateChange) > timeout) {
|
||||
// User has been holding the button down
|
||||
// We want to send a button is held message
|
||||
if (currentState == 0x01)
|
||||
return BUTTON_F_LONG;
|
||||
else if (currentState == 0x02)
|
||||
return BUTTON_B_LONG;
|
||||
else
|
||||
return BUTTON_BOTH_LONG; // Both being held case
|
||||
} else
|
||||
return BUTTON_NONE;
|
||||
} else {
|
||||
// A change in button state has occurred
|
||||
ButtonState retVal = BUTTON_NONE;
|
||||
if (currentState) {
|
||||
// User has pressed a button down (nothing done on down)
|
||||
if (currentState != previousState) {
|
||||
// There has been a change in the button states
|
||||
// If there is a rising edge on one of the buttons from double press we
|
||||
// want to mask that out As users are having issues with not release
|
||||
// both at once
|
||||
if (previousState == 0x03)
|
||||
currentState = 0x03;
|
||||
}
|
||||
} else {
|
||||
// User has released buttons
|
||||
// If they previously had the buttons down we want to check if they were <
|
||||
// long hold and trigger a press
|
||||
if ((xTaskGetTickCount() - previousStateChange) < timeout) {
|
||||
// The user didn't hold the button for long
|
||||
// So we send button press
|
||||
if (currentState)
|
||||
lastButtonTime = xTaskGetTickCount();
|
||||
if (currentState == previousState) {
|
||||
if (currentState == 0)
|
||||
return BUTTON_NONE;
|
||||
if ((xTaskGetTickCount() - previousStateChange) > timeout) {
|
||||
// User has been holding the button down
|
||||
// We want to send a button is held message
|
||||
if (currentState == 0x01)
|
||||
return BUTTON_F_LONG;
|
||||
else if (currentState == 0x02)
|
||||
return BUTTON_B_LONG;
|
||||
else
|
||||
return BUTTON_BOTH_LONG; // Both being held case
|
||||
} else
|
||||
return BUTTON_NONE;
|
||||
} else {
|
||||
// A change in button state has occurred
|
||||
ButtonState retVal = BUTTON_NONE;
|
||||
if (currentState) {
|
||||
// User has pressed a button down (nothing done on down)
|
||||
if (currentState != previousState) {
|
||||
// There has been a change in the button states
|
||||
// If there is a rising edge on one of the buttons from double press we
|
||||
// want to mask that out As users are having issues with not release
|
||||
// both at once
|
||||
if (previousState == 0x03)
|
||||
currentState = 0x03;
|
||||
}
|
||||
} else {
|
||||
// User has released buttons
|
||||
// If they previously had the buttons down we want to check if they were <
|
||||
// long hold and trigger a press
|
||||
if ((xTaskGetTickCount() - previousStateChange) < timeout) {
|
||||
// The user didn't hold the button for long
|
||||
// So we send button press
|
||||
|
||||
if (previousState == 0x01)
|
||||
retVal = BUTTON_F_SHORT;
|
||||
else if (previousState == 0x02)
|
||||
retVal = BUTTON_B_SHORT;
|
||||
else
|
||||
retVal = BUTTON_BOTH; // Both being held case
|
||||
}
|
||||
}
|
||||
previousState = currentState;
|
||||
previousStateChange = xTaskGetTickCount();
|
||||
return retVal;
|
||||
}
|
||||
return BUTTON_NONE;
|
||||
if (previousState == 0x01)
|
||||
retVal = BUTTON_F_SHORT;
|
||||
else if (previousState == 0x02)
|
||||
retVal = BUTTON_B_SHORT;
|
||||
else
|
||||
retVal = BUTTON_BOTH; // Both being held case
|
||||
}
|
||||
}
|
||||
previousState = currentState;
|
||||
previousStateChange = xTaskGetTickCount();
|
||||
return retVal;
|
||||
}
|
||||
return BUTTON_NONE;
|
||||
}
|
||||
|
||||
void waitForButtonPress() {
|
||||
// we are just lazy and sleep until user confirms button press
|
||||
// This also eats the button press event!
|
||||
ButtonState buttons = getButtonState();
|
||||
while (buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
}
|
||||
while (!buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
}
|
||||
// we are just lazy and sleep until user confirms button press
|
||||
// This also eats the button press event!
|
||||
ButtonState buttons = getButtonState();
|
||||
while (buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
}
|
||||
while (!buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
}
|
||||
}
|
||||
|
||||
void waitForButtonPressOrTimeout(uint32_t timeout) {
|
||||
timeout += xTaskGetTickCount();
|
||||
// calculate the exit point
|
||||
timeout += xTaskGetTickCount();
|
||||
// calculate the exit point
|
||||
|
||||
ButtonState buttons = getButtonState();
|
||||
while (buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
if (xTaskGetTickCount() > timeout)
|
||||
return;
|
||||
}
|
||||
while (!buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
if (xTaskGetTickCount() > timeout)
|
||||
return;
|
||||
}
|
||||
ButtonState buttons = getButtonState();
|
||||
while (buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
if (xTaskGetTickCount() > timeout)
|
||||
return;
|
||||
}
|
||||
while (!buttons) {
|
||||
buttons = getButtonState();
|
||||
GUIDelay();
|
||||
if (xTaskGetTickCount() > timeout)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,23 @@
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
#include <fusbpd.h>
|
||||
#include <pd.h>
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
#include "fusb302b.h"
|
||||
#include "int_n.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
#include "protocol_tx.h"
|
||||
#include "int_n.h"
|
||||
#include <fusbpd.h>
|
||||
#include <pd.h>
|
||||
|
||||
void fusb302_start_processing() {
|
||||
/* Initialize the FUSB302B */
|
||||
if (fusb_setup()) {
|
||||
PolicyEngine::init();
|
||||
ProtocolTransmit::init();
|
||||
ProtocolReceive::init();
|
||||
InterruptHandler::init();
|
||||
}
|
||||
/* Initialize the FUSB302B */
|
||||
if (fusb_setup()) {
|
||||
PolicyEngine::init();
|
||||
ProtocolTransmit::init();
|
||||
ProtocolReceive::init();
|
||||
InterruptHandler::init();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -16,65 +16,63 @@
|
||||
*/
|
||||
|
||||
#include "int_n.h"
|
||||
#include "fusbpd.h"
|
||||
#include <pd.h>
|
||||
#include "BSP.h"
|
||||
#include "fusb302b.h"
|
||||
#include "protocol_rx.h"
|
||||
#include "protocol_tx.h"
|
||||
#include "fusbpd.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
#include "protocol_tx.h"
|
||||
#include "task.h"
|
||||
#include "BSP.h"
|
||||
#include <pd.h>
|
||||
|
||||
osThreadId InterruptHandler::TaskHandle = NULL;
|
||||
uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize];
|
||||
osThreadId InterruptHandler::TaskHandle = NULL;
|
||||
uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize];
|
||||
osStaticThreadDef_t InterruptHandler::TaskControlBlock;
|
||||
|
||||
void InterruptHandler::init() {
|
||||
osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||
TaskHandle = osThreadCreate(osThread(intTask), NULL);
|
||||
osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||
TaskHandle = osThreadCreate(osThread(intTask), NULL);
|
||||
}
|
||||
|
||||
void InterruptHandler::Thread(const void *arg) {
|
||||
(void) arg;
|
||||
union fusb_status status;
|
||||
while (true) {
|
||||
/* If the INT_N line is low */
|
||||
if (xTaskNotifyWait(0x00, 0x0F, NULL, PolicyEngine::setupCompleteOrTimedOut() ? 1000 : 10) == pdPASS) {
|
||||
//delay slightly so we catch the crc with better timing
|
||||
osDelay(1);
|
||||
}
|
||||
/* Read the FUSB302B status and interrupt registers */
|
||||
fusb_get_status(&status);
|
||||
/* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX
|
||||
* thread */
|
||||
if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) {
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_TXSENT);
|
||||
}
|
||||
if (status.interrupta & FUSB_INTERRUPTA_I_RETRYFAIL) {
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_RETRYFAIL);
|
||||
}
|
||||
(void)arg;
|
||||
union fusb_status status;
|
||||
while (true) {
|
||||
/* If the INT_N line is low */
|
||||
if (xTaskNotifyWait(0x00, 0x0F, NULL, PolicyEngine::setupCompleteOrTimedOut() ? 1000 : 10) == pdPASS) {
|
||||
// delay slightly so we catch the crc with better timing
|
||||
osDelay(1);
|
||||
}
|
||||
/* Read the FUSB302B status and interrupt registers */
|
||||
fusb_get_status(&status);
|
||||
/* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX
|
||||
* thread */
|
||||
if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) {
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_TXSENT);
|
||||
}
|
||||
if (status.interrupta & FUSB_INTERRUPTA_I_RETRYFAIL) {
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_RETRYFAIL);
|
||||
}
|
||||
|
||||
/* If the I_GCRCSENT flag is set, tell the Protocol RX thread */
|
||||
//This means a message was recieved with a good CRC
|
||||
if (status.interruptb & FUSB_INTERRUPTB_I_GCRCSENT) {
|
||||
ProtocolReceive::notify(PDB_EVT_PRLRX_I_GCRCSENT);
|
||||
}
|
||||
/* If the I_GCRCSENT flag is set, tell the Protocol RX thread */
|
||||
// This means a message was recieved with a good CRC
|
||||
if (status.interruptb & FUSB_INTERRUPTB_I_GCRCSENT) {
|
||||
ProtocolReceive::notify(PDB_EVT_PRLRX_I_GCRCSENT);
|
||||
}
|
||||
|
||||
/* If the I_OCP_TEMP and OVRTEMP flags are set, tell the Policy
|
||||
* Engine thread */
|
||||
if ((status.interrupta & FUSB_INTERRUPTA_I_OCP_TEMP) && (status.status1 & FUSB_STATUS1_OVRTEMP)) {
|
||||
PolicyEngine::notify(PDB_EVT_PE_I_OVRTEMP);
|
||||
}
|
||||
}
|
||||
/* If the I_OCP_TEMP and OVRTEMP flags are set, tell the Policy
|
||||
* Engine thread */
|
||||
if ((status.interrupta & FUSB_INTERRUPTA_I_OCP_TEMP) && (status.status1 & FUSB_STATUS1_OVRTEMP)) {
|
||||
PolicyEngine::notify(PDB_EVT_PE_I_OVRTEMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
void InterruptHandler::irqCallback() {
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
if (TaskHandle != NULL) {
|
||||
BaseType_t taskWoke = pdFALSE;
|
||||
xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke);
|
||||
portYIELD_FROM_ISR(taskWoke);
|
||||
}
|
||||
}
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
if (TaskHandle != NULL) {
|
||||
BaseType_t taskWoke = pdFALSE;
|
||||
xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke);
|
||||
portYIELD_FROM_ISR(taskWoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,9 @@
|
||||
* Created on: 14 Jun 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "BSP_PD.h"
|
||||
#include "pd.h"
|
||||
#include "policy_engine.h"
|
||||
#include "BSP_PD.h"
|
||||
/* The current draw when the output is disabled */
|
||||
#define DPM_MIN_CURRENT PD_MA2PDI(50)
|
||||
/*
|
||||
@@ -16,212 +16,178 @@
|
||||
* If there is no such PDO, returns -1 instead.
|
||||
*/
|
||||
static int8_t dpm_get_range_fixed_pdo_index(const union pd_msg *caps) {
|
||||
/* Get the number of PDOs */
|
||||
uint8_t numobj = PD_NUMOBJ_GET(caps);
|
||||
/* Get the number of PDOs */
|
||||
uint8_t numobj = PD_NUMOBJ_GET(caps);
|
||||
|
||||
/* Get ready to iterate over the PDOs */
|
||||
int8_t i;
|
||||
int8_t step;
|
||||
i = numobj - 1;
|
||||
step = -1;
|
||||
uint16_t current = 100; // in centiamps
|
||||
uint16_t voltagemin = 8000;
|
||||
uint16_t voltagemax = 10000;
|
||||
/* Look at the PDOs to see if one falls in our voltage range. */
|
||||
while (0 <= i && i < numobj) {
|
||||
/* If we have a fixed PDO, its V is within our range, and its I is at
|
||||
* least our desired I */
|
||||
uint16_t v = PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]);
|
||||
if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
if ( PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= current) {
|
||||
if (v >= PD_MV2PDV(voltagemin) && v <= PD_MV2PDV(voltagemax)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += step;
|
||||
}
|
||||
return -1;
|
||||
/* Get ready to iterate over the PDOs */
|
||||
int8_t i;
|
||||
int8_t step;
|
||||
i = numobj - 1;
|
||||
step = -1;
|
||||
uint16_t current = 100; // in centiamps
|
||||
uint16_t voltagemin = 8000;
|
||||
uint16_t voltagemax = 10000;
|
||||
/* Look at the PDOs to see if one falls in our voltage range. */
|
||||
while (0 <= i && i < numobj) {
|
||||
/* If we have a fixed PDO, its V is within our range, and its I is at
|
||||
* least our desired I */
|
||||
uint16_t v = PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]);
|
||||
if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
if (PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= current) {
|
||||
if (v >= PD_MV2PDV(voltagemin) && v <= PD_MV2PDV(voltagemax)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += step;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bool PolicyEngine::pdbs_dpm_evaluate_capability(
|
||||
const union pd_msg *capabilities, union pd_msg *request) {
|
||||
bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg *request) {
|
||||
|
||||
/* Get the number of PDOs */
|
||||
uint8_t numobj = PD_NUMOBJ_GET(capabilities);
|
||||
/* Get the number of PDOs */
|
||||
uint8_t numobj = PD_NUMOBJ_GET(capabilities);
|
||||
|
||||
/* Get whether or not the power supply is constrained */
|
||||
_unconstrained_power =
|
||||
capabilities->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED;
|
||||
/* Get whether or not the power supply is constrained */
|
||||
_unconstrained_power = capabilities->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED;
|
||||
|
||||
/* Make sure we have configuration */
|
||||
/* Look at the PDOs to see if one matches our desires */
|
||||
//Look against USB_PD_Desired_Levels to select in order of preference
|
||||
for (uint8_t desiredLevel = 0; desiredLevel < USB_PD_Desired_Levels_Len;
|
||||
desiredLevel++) {
|
||||
for (uint8_t i = 0; i < numobj; i++) {
|
||||
/* If we have a fixed PDO, its V equals our desired V, and its I is
|
||||
* at least our desired I */
|
||||
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
//This is a fixed PDO entry
|
||||
int voltage = PD_PDV2MV(
|
||||
PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i]));
|
||||
int current = PD_PDO_SRC_FIXED_CURRENT_GET(
|
||||
capabilities->obj[i]);
|
||||
uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel
|
||||
* 2) + 0];
|
||||
uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel
|
||||
* 2) + 1];
|
||||
//As pd stores current in 10mA increments, divide by 10
|
||||
desiredminCurrent /= 10;
|
||||
if (voltage == desiredVoltage) {
|
||||
if (current >= desiredminCurrent) {
|
||||
/* We got what we wanted, so build a request for that */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST
|
||||
| PD_NUMOBJ(1);
|
||||
/* Make sure we have configuration */
|
||||
/* Look at the PDOs to see if one matches our desires */
|
||||
// Look against USB_PD_Desired_Levels to select in order of preference
|
||||
for (uint8_t desiredLevel = 0; desiredLevel < USB_PD_Desired_Levels_Len; desiredLevel++) {
|
||||
for (uint8_t i = 0; i < numobj; i++) {
|
||||
/* If we have a fixed PDO, its V equals our desired V, and its I is
|
||||
* at least our desired I */
|
||||
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
// This is a fixed PDO entry
|
||||
int voltage = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i]));
|
||||
int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]);
|
||||
uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel * 2) + 0];
|
||||
uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel * 2) + 1];
|
||||
// As pd stores current in 10mA increments, divide by 10
|
||||
desiredminCurrent /= 10;
|
||||
if (voltage == desiredVoltage) {
|
||||
if (current >= desiredminCurrent) {
|
||||
/* We got what we wanted, so build a request for that */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||
|
||||
/* GiveBack disabled */
|
||||
request->obj[0] =
|
||||
PD_RDO_FV_MAX_CURRENT_SET(
|
||||
current) | PD_RDO_FV_CURRENT_SET(current)
|
||||
| PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
|
||||
//We support usb comms (ish)
|
||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
/* GiveBack disabled */
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current) | PD_RDO_FV_CURRENT_SET(current) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
|
||||
// We support usb comms (ish)
|
||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = voltage;
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = voltage;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* Nothing matched (or no configuration), so get 5 V at low current */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1);
|
||||
/* If the output is enabled and we got here, it must be a capability
|
||||
* mismatch. */
|
||||
if (pdNegotiationComplete) {
|
||||
request->obj[0] |= PD_RDO_CAP_MISMATCH;
|
||||
}
|
||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
|
||||
/* Nothing matched (or no configuration), so get 5 V at low current */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||
request->obj[0] =
|
||||
PD_RDO_FV_MAX_CURRENT_SET(
|
||||
DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND
|
||||
| PD_RDO_OBJPOS_SET(1);
|
||||
/* If the output is enabled and we got here, it must be a capability
|
||||
* mismatch. */
|
||||
if (pdNegotiationComplete) {
|
||||
request->obj[0] |= PD_RDO_CAP_MISMATCH;
|
||||
}
|
||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = 5000;
|
||||
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = 5000;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
|
||||
/* Keep track of how many PDOs we've added */
|
||||
int numobj = 0;
|
||||
/* Keep track of how many PDOs we've added */
|
||||
int numobj = 0;
|
||||
|
||||
/* If we have no configuration or want something other than 5 V, add a PDO
|
||||
* for vSafe5V */
|
||||
/* Minimum current, 5 V, and higher capability. */
|
||||
cap->obj[numobj++] =
|
||||
PD_PDO_TYPE_FIXED
|
||||
| PD_PDO_SNK_FIXED_VOLTAGE_SET(
|
||||
PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT);
|
||||
/* If we have no configuration or want something other than 5 V, add a PDO
|
||||
* for vSafe5V */
|
||||
/* Minimum current, 5 V, and higher capability. */
|
||||
cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT);
|
||||
|
||||
/* Get the current we want */
|
||||
uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps
|
||||
uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv
|
||||
/* Add a PDO for the desired power. */
|
||||
cap->obj[numobj++] = PD_PDO_TYPE_FIXED
|
||||
| PD_PDO_SNK_FIXED_VOLTAGE_SET(
|
||||
PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
||||
/* Get the current we want */
|
||||
uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps
|
||||
uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv
|
||||
/* Add a PDO for the desired power. */
|
||||
cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
||||
|
||||
/* Get the PDO from the voltage range */
|
||||
int8_t i = dpm_get_range_fixed_pdo_index(cap);
|
||||
/* Get the PDO from the voltage range */
|
||||
int8_t i = dpm_get_range_fixed_pdo_index(cap);
|
||||
|
||||
/* If it's vSafe5V, set our vSafe5V's current to what we want */
|
||||
if (i == 0) {
|
||||
cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT;
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
||||
} else {
|
||||
/* If we want more than 5 V, set the Higher Capability flag */
|
||||
if (PD_MV2PDV(voltage) != PD_MV2PDV(5000)) {
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_HIGHER_CAP;
|
||||
}
|
||||
/* If it's vSafe5V, set our vSafe5V's current to what we want */
|
||||
if (i == 0) {
|
||||
cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT;
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
||||
} else {
|
||||
/* If we want more than 5 V, set the Higher Capability flag */
|
||||
if (PD_MV2PDV(voltage) != PD_MV2PDV(5000)) {
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_HIGHER_CAP;
|
||||
}
|
||||
|
||||
/* If the range PDO is a different voltage than the preferred
|
||||
* voltage, add it to the array. */
|
||||
if (i
|
||||
> 0&& PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i]) != PD_MV2PDV(voltage)) {
|
||||
cap->obj[numobj++] =
|
||||
PD_PDO_TYPE_FIXED
|
||||
| PD_PDO_SNK_FIXED_VOLTAGE_SET(
|
||||
PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i])) | PD_PDO_SNK_FIXED_CURRENT_SET(
|
||||
PD_PDO_SRC_FIXED_CURRENT_GET(cap->obj[i]));
|
||||
}
|
||||
/* If the range PDO is a different voltage than the preferred
|
||||
* voltage, add it to the array. */
|
||||
if (i > 0 && PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i]) != PD_MV2PDV(voltage)) {
|
||||
cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i])) | PD_PDO_SNK_FIXED_CURRENT_SET(PD_PDO_SRC_FIXED_CURRENT_GET(cap->obj[i]));
|
||||
}
|
||||
|
||||
/* If we have three PDOs at this point, make sure the last two are
|
||||
* sorted by voltage. */
|
||||
if (numobj == 3
|
||||
&& (cap->obj[1] & PD_PDO_SNK_FIXED_VOLTAGE)
|
||||
> (cap->obj[2] & PD_PDO_SNK_FIXED_VOLTAGE)) {
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
cap->obj[2] ^= cap->obj[1];
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
}
|
||||
}
|
||||
/* If we have three PDOs at this point, make sure the last two are
|
||||
* sorted by voltage. */
|
||||
if (numobj == 3 && (cap->obj[1] & PD_PDO_SNK_FIXED_VOLTAGE) > (cap->obj[2] & PD_PDO_SNK_FIXED_VOLTAGE)) {
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
cap->obj[2] ^= cap->obj[1];
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the unconstrained power flag. */
|
||||
if (_unconstrained_power) {
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_UNCONSTRAINED;
|
||||
}
|
||||
/* Set the USB communications capable flag. */
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_USB_COMMS;
|
||||
/* Set the unconstrained power flag. */
|
||||
if (_unconstrained_power) {
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_UNCONSTRAINED;
|
||||
}
|
||||
/* Set the USB communications capable flag. */
|
||||
cap->obj[0] |= PD_PDO_SNK_FIXED_USB_COMMS;
|
||||
|
||||
/* Set the Sink_Capabilities message header */
|
||||
cap->hdr = hdr_template | PD_MSGTYPE_SINK_CAPABILITIES | PD_NUMOBJ(numobj);
|
||||
/* Set the Sink_Capabilities message header */
|
||||
cap->hdr = hdr_template | PD_MSGTYPE_SINK_CAPABILITIES | PD_NUMOBJ(numobj);
|
||||
}
|
||||
|
||||
bool PolicyEngine::pdbs_dpm_evaluate_typec_current(
|
||||
enum fusb_typec_current tcc) {
|
||||
(void) tcc;
|
||||
//This is for evaluating 5V static current advertised by resistors
|
||||
/* We don't control the voltage anymore; it will always be 5 V. */
|
||||
current_voltage_mv = _requested_voltage = 5000;
|
||||
//For the soldering iron we accept this as a fallback, but it sucks
|
||||
pdNegotiationComplete = false;
|
||||
return true;
|
||||
bool PolicyEngine::pdbs_dpm_evaluate_typec_current(enum fusb_typec_current tcc) {
|
||||
(void)tcc;
|
||||
// This is for evaluating 5V static current advertised by resistors
|
||||
/* We don't control the voltage anymore; it will always be 5 V. */
|
||||
current_voltage_mv = _requested_voltage = 5000;
|
||||
// For the soldering iron we accept this as a fallback, but it sucks
|
||||
pdNegotiationComplete = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_transition_default() {
|
||||
/* Cast the dpm_data to the right type */
|
||||
/* Cast the dpm_data to the right type */
|
||||
|
||||
/* Pretend we requested 5 V */
|
||||
current_voltage_mv = 5000;
|
||||
/* Turn the output off */
|
||||
pdNegotiationComplete = false;
|
||||
/* Pretend we requested 5 V */
|
||||
current_voltage_mv = 5000;
|
||||
/* Turn the output off */
|
||||
pdNegotiationComplete = false;
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_transition_requested() {
|
||||
/* Cast the dpm_data to the right type */
|
||||
pdNegotiationComplete = true;
|
||||
/* Cast the dpm_data to the right type */
|
||||
pdNegotiationComplete = true;
|
||||
}
|
||||
|
||||
void PolicyEngine::handleMessage(union pd_msg *msg) {
|
||||
xQueueSend(messagesWaiting, msg, 100);
|
||||
}
|
||||
void PolicyEngine::handleMessage(union pd_msg *msg) { xQueueSend(messagesWaiting, msg, 100); }
|
||||
|
||||
bool PolicyEngine::messageWaiting() {
|
||||
return uxQueueMessagesWaiting(messagesWaiting) > 0;
|
||||
}
|
||||
bool PolicyEngine::messageWaiting() { return uxQueueMessagesWaiting(messagesWaiting) > 0; }
|
||||
|
||||
bool PolicyEngine::readMessage() {
|
||||
return xQueueReceive(messagesWaiting, &tempMessage, 0) == pdTRUE;
|
||||
}
|
||||
bool PolicyEngine::readMessage() { return xQueueReceive(messagesWaiting, &tempMessage, 0) == pdTRUE; }
|
||||
|
||||
void PolicyEngine::pdbs_dpm_transition_typec() {
|
||||
//This means PD failed, so we either have a dump 5V only type C or a QC charger
|
||||
//For now; treat this as failed neg
|
||||
pdNegotiationComplete = false;
|
||||
// This means PD failed, so we either have a dump 5V only type C or a QC charger
|
||||
// For now; treat this as failed neg
|
||||
pdNegotiationComplete = false;
|
||||
}
|
||||
|
||||
@@ -17,173 +17,167 @@
|
||||
|
||||
#include "protocol_rx.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "string.h"
|
||||
#include <pd.h>
|
||||
#include "fusb302b.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_tx.h"
|
||||
#include "fusb302b.h"
|
||||
osThreadId ProtocolReceive::TaskHandle = NULL;
|
||||
EventGroupHandle_t ProtocolReceive::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t ProtocolReceive::xCreatedEventGroup;
|
||||
uint32_t ProtocolReceive::TaskBuffer[ProtocolReceive::TaskStackSize];
|
||||
#include "string.h"
|
||||
#include <pd.h>
|
||||
#include <stdlib.h>
|
||||
osThreadId ProtocolReceive::TaskHandle = NULL;
|
||||
EventGroupHandle_t ProtocolReceive::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t ProtocolReceive::xCreatedEventGroup;
|
||||
uint32_t ProtocolReceive::TaskBuffer[ProtocolReceive::TaskStackSize];
|
||||
osStaticThreadDef_t ProtocolReceive::TaskControlBlock;
|
||||
union pd_msg ProtocolReceive::tempMessage;
|
||||
uint8_t ProtocolReceive::_rx_messageid;
|
||||
uint8_t ProtocolReceive::_tx_messageidcounter;
|
||||
union pd_msg ProtocolReceive::tempMessage;
|
||||
uint8_t ProtocolReceive::_rx_messageid;
|
||||
uint8_t ProtocolReceive::_tx_messageidcounter;
|
||||
/*
|
||||
* PRL_Rx_Wait_for_PHY_Message state
|
||||
*/
|
||||
ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_wait_phy() {
|
||||
/* Wait for an event */
|
||||
_rx_messageid = 0;
|
||||
eventmask_t evt = waitForEvent(
|
||||
PDB_EVT_PRLRX_RESET | PDB_EVT_PRLRX_I_GCRCSENT | PDB_EVT_PRLRX_I_RXPEND);
|
||||
/* Wait for an event */
|
||||
_rx_messageid = 0;
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PRLRX_RESET | PDB_EVT_PRLRX_I_GCRCSENT | PDB_EVT_PRLRX_I_RXPEND);
|
||||
|
||||
/* If we got a reset event, reset */
|
||||
if (evt & PDB_EVT_PRLRX_RESET) {
|
||||
waitForEvent(PDB_EVT_PRLRX_RESET, 0);
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
/* If we got an I_GCRCSENT event, read the message and decide what to do */
|
||||
if (evt & PDB_EVT_PRLRX_I_GCRCSENT) {
|
||||
/* Get a buffer to read the message into. Guaranteed to not fail
|
||||
* because we have a big enough pool and are careful. */
|
||||
union pd_msg *_rx_message = &tempMessage;
|
||||
memset(&tempMessage, 0, sizeof(tempMessage));
|
||||
/* Read the message */
|
||||
fusb_read_message(_rx_message);
|
||||
/* If it's a Soft_Reset, go to the soft reset state */
|
||||
if (PD_MSGTYPE_GET(_rx_message) == PD_MSGTYPE_SOFT_RESET
|
||||
&& PD_NUMOBJ_GET(_rx_message) == 0) {
|
||||
return PRLRxReset;
|
||||
} else {
|
||||
/* Otherwise, check the message ID */
|
||||
return PRLRxCheckMessageID;
|
||||
}
|
||||
} else if (evt & PDB_EVT_PRLRX_I_RXPEND) {
|
||||
//There is an RX message pending that is not a Good CRC
|
||||
union pd_msg *_rx_message = &tempMessage;
|
||||
/* Read the message */
|
||||
fusb_read_message(_rx_message);
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
/* If we got a reset event, reset */
|
||||
if (evt & PDB_EVT_PRLRX_RESET) {
|
||||
waitForEvent(PDB_EVT_PRLRX_RESET, 0);
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
/* If we got an I_GCRCSENT event, read the message and decide what to do */
|
||||
if (evt & PDB_EVT_PRLRX_I_GCRCSENT) {
|
||||
/* Get a buffer to read the message into. Guaranteed to not fail
|
||||
* because we have a big enough pool and are careful. */
|
||||
union pd_msg *_rx_message = &tempMessage;
|
||||
memset(&tempMessage, 0, sizeof(tempMessage));
|
||||
/* Read the message */
|
||||
fusb_read_message(_rx_message);
|
||||
/* If it's a Soft_Reset, go to the soft reset state */
|
||||
if (PD_MSGTYPE_GET(_rx_message) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(_rx_message) == 0) {
|
||||
return PRLRxReset;
|
||||
} else {
|
||||
/* Otherwise, check the message ID */
|
||||
return PRLRxCheckMessageID;
|
||||
}
|
||||
} else if (evt & PDB_EVT_PRLRX_I_RXPEND) {
|
||||
// There is an RX message pending that is not a Good CRC
|
||||
union pd_msg *_rx_message = &tempMessage;
|
||||
/* Read the message */
|
||||
fusb_read_message(_rx_message);
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
|
||||
return PRLRxWaitPHY;
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Rx_Layer_Reset_for_Receive state
|
||||
*/
|
||||
ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_reset() {
|
||||
/* Reset MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
/* Reset MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
|
||||
/* Clear stored MessageID */
|
||||
_rx_messageid = -1;
|
||||
/* Clear stored MessageID */
|
||||
_rx_messageid = -1;
|
||||
|
||||
/* TX transitions to its reset state */
|
||||
ProtocolTransmit::notify(
|
||||
ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET);
|
||||
taskYIELD();
|
||||
/* TX transitions to its reset state */
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET);
|
||||
taskYIELD();
|
||||
|
||||
/* If we got a RESET signal, reset the machine */
|
||||
if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) != 0) {
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
/* If we got a RESET signal, reset the machine */
|
||||
if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) != 0) {
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
|
||||
/* Go to the Check_MessageID state */
|
||||
return PRLRxCheckMessageID;
|
||||
/* Go to the Check_MessageID state */
|
||||
return PRLRxCheckMessageID;
|
||||
}
|
||||
volatile uint32_t rxCounter = 0;
|
||||
/*
|
||||
* PRL_Rx_Check_MessageID state
|
||||
*/
|
||||
ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_check_messageid() {
|
||||
/* If we got a RESET signal, reset the machine */
|
||||
// if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) == PDB_EVT_PRLRX_RESET) {
|
||||
// return PRLRxWaitPHY;
|
||||
// }
|
||||
/* If the message has the stored ID, we've seen this message before. Free
|
||||
* it and don't pass it to the policy engine. */
|
||||
/* If we got a RESET signal, reset the machine */
|
||||
// if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) == PDB_EVT_PRLRX_RESET) {
|
||||
// return PRLRxWaitPHY;
|
||||
// }
|
||||
/* If the message has the stored ID, we've seen this message before. Free
|
||||
* it and don't pass it to the policy engine. */
|
||||
|
||||
/* Otherwise, there's either no stored ID or this message has an ID we
|
||||
* haven't just seen. Transition to the Store_MessageID state. */
|
||||
// if (PD_MESSAGEID_GET(&tempMessage) == _rx_messageid) {
|
||||
// return PRLRxWaitPHY;
|
||||
// } else
|
||||
{
|
||||
rxCounter++;
|
||||
return PRLRxStoreMessageID;
|
||||
}
|
||||
/* Otherwise, there's either no stored ID or this message has an ID we
|
||||
* haven't just seen. Transition to the Store_MessageID state. */
|
||||
// if (PD_MESSAGEID_GET(&tempMessage) == _rx_messageid) {
|
||||
// return PRLRxWaitPHY;
|
||||
// } else
|
||||
{
|
||||
rxCounter++;
|
||||
return PRLRxStoreMessageID;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Rx_Store_MessageID state
|
||||
*/
|
||||
ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_store_messageid() {
|
||||
/* Tell ProtocolTX to discard the message being transmitted */
|
||||
/* Tell ProtocolTX to discard the message being transmitted */
|
||||
|
||||
ProtocolTransmit::notify(
|
||||
ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD);
|
||||
|
||||
/* Update the stored MessageID */
|
||||
_rx_messageid = PD_MESSAGEID_GET(&tempMessage);
|
||||
/* Update the stored MessageID */
|
||||
_rx_messageid = PD_MESSAGEID_GET(&tempMessage);
|
||||
|
||||
/* Pass the message to the policy engine. */
|
||||
/* Pass the message to the policy engine. */
|
||||
|
||||
PolicyEngine::handleMessage(&tempMessage);
|
||||
PolicyEngine::notify(PDB_EVT_PE_MSG_RX);
|
||||
taskYIELD();
|
||||
/* Don't check if we got a RESET because we'd do nothing different. */
|
||||
PolicyEngine::handleMessage(&tempMessage);
|
||||
PolicyEngine::notify(PDB_EVT_PE_MSG_RX);
|
||||
taskYIELD();
|
||||
/* Don't check if we got a RESET because we'd do nothing different. */
|
||||
|
||||
return PRLRxWaitPHY;
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
|
||||
void ProtocolReceive::init() {
|
||||
osThreadStaticDef(protRX, thread, PDB_PRIO_PRL, 0, TaskStackSize,
|
||||
TaskBuffer, &TaskControlBlock);
|
||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||
TaskHandle = osThreadCreate(osThread(protRX), NULL);
|
||||
osThreadStaticDef(protRX, thread, PDB_PRIO_PRL, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||
TaskHandle = osThreadCreate(osThread(protRX), NULL);
|
||||
}
|
||||
|
||||
void ProtocolReceive::thread(const void *args) {
|
||||
(void) args;
|
||||
ProtocolReceive::protocol_rx_state state = PRLRxWaitPHY;
|
||||
(void)args;
|
||||
ProtocolReceive::protocol_rx_state state = PRLRxWaitPHY;
|
||||
|
||||
while (true) {
|
||||
switch (state) {
|
||||
case PRLRxWaitPHY:
|
||||
state = protocol_rx_wait_phy();
|
||||
break;
|
||||
case PRLRxReset:
|
||||
state = protocol_rx_reset();
|
||||
break;
|
||||
case PRLRxCheckMessageID:
|
||||
state = protocol_rx_check_messageid();
|
||||
break;
|
||||
case PRLRxStoreMessageID:
|
||||
state = protocol_rx_store_messageid();
|
||||
break;
|
||||
default:
|
||||
/* This is an error. It really shouldn't happen. We might
|
||||
* want to handle it anyway, though. */
|
||||
state = PRLRxWaitPHY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
switch (state) {
|
||||
case PRLRxWaitPHY:
|
||||
state = protocol_rx_wait_phy();
|
||||
break;
|
||||
case PRLRxReset:
|
||||
state = protocol_rx_reset();
|
||||
break;
|
||||
case PRLRxCheckMessageID:
|
||||
state = protocol_rx_check_messageid();
|
||||
break;
|
||||
case PRLRxStoreMessageID:
|
||||
state = protocol_rx_store_messageid();
|
||||
break;
|
||||
default:
|
||||
/* This is an error. It really shouldn't happen. We might
|
||||
* want to handle it anyway, though. */
|
||||
state = PRLRxWaitPHY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolReceive::notify(uint32_t notification) {
|
||||
if (xEventGroupHandle != NULL) {
|
||||
xEventGroupSetBits(xEventGroupHandle, notification);
|
||||
}
|
||||
if (xEventGroupHandle != NULL) {
|
||||
xEventGroupSetBits(xEventGroupHandle, notification);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ProtocolReceive::waitForEvent(uint32_t mask, TickType_t ticksToWait) {
|
||||
if (xEventGroupHandle != NULL) {
|
||||
return xEventGroupWaitBits(xEventGroupHandle, mask, mask,
|
||||
pdFALSE, ticksToWait);
|
||||
}
|
||||
return 0;
|
||||
if (xEventGroupHandle != NULL) {
|
||||
return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,283 +16,268 @@
|
||||
*/
|
||||
|
||||
#include "protocol_tx.h"
|
||||
#include <pd.h>
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusbpd.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
#include <pd.h>
|
||||
|
||||
osThreadId ProtocolTransmit::TaskHandle = NULL;
|
||||
uint32_t ProtocolTransmit::TaskBuffer[ProtocolTransmit::TaskStackSize];
|
||||
osThreadId ProtocolTransmit::TaskHandle = NULL;
|
||||
uint32_t ProtocolTransmit::TaskBuffer[ProtocolTransmit::TaskStackSize];
|
||||
osStaticThreadDef_t ProtocolTransmit::TaskControlBlock;
|
||||
StaticQueue_t ProtocolTransmit::xStaticQueue;
|
||||
bool ProtocolTransmit::messageSending = false;
|
||||
uint8_t ProtocolTransmit::ucQueueStorageArea[PDB_MSG_POOL_SIZE
|
||||
* sizeof(union pd_msg)];
|
||||
QueueHandle_t ProtocolTransmit::messagesWaiting = NULL;
|
||||
uint8_t ProtocolTransmit::_tx_messageidcounter;
|
||||
union pd_msg ProtocolTransmit::temp_msg;
|
||||
EventGroupHandle_t ProtocolTransmit::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t ProtocolTransmit::xCreatedEventGroup;
|
||||
StaticQueue_t ProtocolTransmit::xStaticQueue;
|
||||
bool ProtocolTransmit::messageSending = false;
|
||||
uint8_t ProtocolTransmit::ucQueueStorageArea[PDB_MSG_POOL_SIZE * sizeof(union pd_msg)];
|
||||
QueueHandle_t ProtocolTransmit::messagesWaiting = NULL;
|
||||
uint8_t ProtocolTransmit::_tx_messageidcounter;
|
||||
union pd_msg ProtocolTransmit::temp_msg;
|
||||
EventGroupHandle_t ProtocolTransmit::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t ProtocolTransmit::xCreatedEventGroup;
|
||||
/*
|
||||
* PRL_Tx_PHY_Layer_Reset state
|
||||
*/
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() {
|
||||
/* Reset the PHY */
|
||||
fusb_reset();
|
||||
/* Reset the PHY */
|
||||
fusb_reset();
|
||||
|
||||
/* If a message was pending when we got here, tell the policy engine that
|
||||
* we failed to send it */
|
||||
if (messagePending()) {
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify( PDB_EVT_PE_TX_ERR);
|
||||
/* Finish failing to send the message */
|
||||
while (messagePending()) {
|
||||
getMessage(); //Discard
|
||||
}
|
||||
}
|
||||
/* If a message was pending when we got here, tell the policy engine that
|
||||
* we failed to send it */
|
||||
if (messagePending()) {
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_ERR);
|
||||
/* Finish failing to send the message */
|
||||
while (messagePending()) {
|
||||
getMessage(); // Discard
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for a message request */
|
||||
return PRLTxWaitMessage;
|
||||
/* Wait for a message request */
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Tx_Wait_for_Message_Request state
|
||||
*/
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_message() {
|
||||
/* Wait for an event */
|
||||
ProtocolTransmit::Notifications evt = waitForEvent(
|
||||
(uint32_t) Notifications::PDB_EVT_PRLTX_RESET
|
||||
| (uint32_t) Notifications::PDB_EVT_PRLTX_DISCARD
|
||||
| (uint32_t) Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
/* Wait for an event */
|
||||
ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_RESET | (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD | (uint32_t)Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_RESET) {
|
||||
return PRLTxPHYReset;
|
||||
}
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_RESET) {
|
||||
return PRLTxPHYReset;
|
||||
}
|
||||
|
||||
/* If the policy engine is trying to send a message */
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_MSG_TX) {
|
||||
/* Get the message */
|
||||
getMessage();
|
||||
/* If the policy engine is trying to send a message */
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_MSG_TX) {
|
||||
/* Get the message */
|
||||
getMessage();
|
||||
|
||||
/* If it's a Soft_Reset, reset the TX layer first */
|
||||
if (PD_MSGTYPE_GET(&temp_msg) == PD_MSGTYPE_SOFT_RESET
|
||||
&& PD_NUMOBJ_GET(&(temp_msg)) == 0) {
|
||||
return PRLTxReset;
|
||||
/* Otherwise, just send the message */
|
||||
} else {
|
||||
return PRLTxConstructMessage;
|
||||
}
|
||||
}
|
||||
/* If it's a Soft_Reset, reset the TX layer first */
|
||||
if (PD_MSGTYPE_GET(&temp_msg) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&(temp_msg)) == 0) {
|
||||
return PRLTxReset;
|
||||
/* Otherwise, just send the message */
|
||||
} else {
|
||||
return PRLTxConstructMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/* Silence the compiler warning */
|
||||
return PRLTxWaitMessage;
|
||||
/* Silence the compiler warning */
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() {
|
||||
/* Clear MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
/* Clear MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
|
||||
/* Tell the Protocol RX thread to reset */
|
||||
ProtocolReceive::notify( PDB_EVT_PRLRX_RESET);
|
||||
taskYIELD();
|
||||
/* Tell the Protocol RX thread to reset */
|
||||
ProtocolReceive::notify(PDB_EVT_PRLRX_RESET);
|
||||
taskYIELD();
|
||||
|
||||
return PRLTxConstructMessage;
|
||||
return PRLTxConstructMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Tx_Construct_Message state
|
||||
*/
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_message() {
|
||||
/* Set the correct MessageID in the message */
|
||||
temp_msg.hdr &= ~PD_HDR_MESSAGEID;
|
||||
temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
|
||||
/* Set the correct MessageID in the message */
|
||||
temp_msg.hdr &= ~PD_HDR_MESSAGEID;
|
||||
temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
|
||||
|
||||
/* PD 3.0 collision avoidance */
|
||||
// if (PolicyEngine::isPD3_0()) {
|
||||
// /* If we're starting an AMS, wait for permission to transmit */
|
||||
// evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS,
|
||||
// 0);
|
||||
// if ((uint32_t) evt
|
||||
// & (uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS) {
|
||||
// while (fusb_get_typec_current() != fusb_sink_tx_ok) {
|
||||
// osDelay(1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
messageSending = true;
|
||||
/* Send the message to the PHY */
|
||||
fusb_send_message(&temp_msg);
|
||||
/* PD 3.0 collision avoidance */
|
||||
// if (PolicyEngine::isPD3_0()) {
|
||||
// /* If we're starting an AMS, wait for permission to transmit */
|
||||
// evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS,
|
||||
// 0);
|
||||
// if ((uint32_t) evt
|
||||
// & (uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS) {
|
||||
// while (fusb_get_typec_current() != fusb_sink_tx_ok) {
|
||||
// osDelay(1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
messageSending = true;
|
||||
/* Send the message to the PHY */
|
||||
fusb_send_message(&temp_msg);
|
||||
|
||||
return PRLTxWaitResponse;
|
||||
return PRLTxWaitResponse;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Tx_Wait_for_PHY_Response state
|
||||
*/
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_response() {
|
||||
/* Wait for an event. There is no need to run CRCReceiveTimer, since the
|
||||
* FUSB302B handles that as part of its retry mechanism. */
|
||||
ProtocolTransmit::Notifications evt = waitForEvent(
|
||||
(uint32_t) Notifications::PDB_EVT_PRLTX_RESET
|
||||
| (uint32_t) Notifications::PDB_EVT_PRLTX_DISCARD
|
||||
| (uint32_t) Notifications::PDB_EVT_PRLTX_I_TXSENT
|
||||
| (uint32_t) Notifications::PDB_EVT_PRLTX_I_RETRYFAIL);
|
||||
/* Wait for an event. There is no need to run CRCReceiveTimer, since the
|
||||
* FUSB302B handles that as part of its retry mechanism. */
|
||||
ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_RESET | (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD | (uint32_t)Notifications::PDB_EVT_PRLTX_I_TXSENT
|
||||
| (uint32_t)Notifications::PDB_EVT_PRLTX_I_RETRYFAIL);
|
||||
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_RESET) {
|
||||
return PRLTxPHYReset;
|
||||
}
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_DISCARD) {
|
||||
return PRLTxDiscardMessage;
|
||||
}
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_RESET) {
|
||||
return PRLTxPHYReset;
|
||||
}
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD) {
|
||||
return PRLTxDiscardMessage;
|
||||
}
|
||||
|
||||
/* If the message was sent successfully */
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_I_TXSENT) {
|
||||
return PRLTxMatchMessageID;
|
||||
}
|
||||
/* If the message failed to be sent */
|
||||
if ((uint32_t) evt & (uint32_t) Notifications::PDB_EVT_PRLTX_I_RETRYFAIL) {
|
||||
return PRLTxTransmissionError;
|
||||
}
|
||||
/* If the message was sent successfully */
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_I_TXSENT) {
|
||||
return PRLTxMatchMessageID;
|
||||
}
|
||||
/* If the message failed to be sent */
|
||||
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_I_RETRYFAIL) {
|
||||
return PRLTxTransmissionError;
|
||||
}
|
||||
|
||||
/* Silence the compiler warning */
|
||||
return PRLTxDiscardMessage;
|
||||
/* Silence the compiler warning */
|
||||
return PRLTxDiscardMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Tx_Match_MessageID state
|
||||
*/
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_match_messageid() {
|
||||
union pd_msg goodcrc;
|
||||
union pd_msg goodcrc;
|
||||
|
||||
/* Read the GoodCRC */
|
||||
fusb_read_message(&goodcrc);
|
||||
/* Read the GoodCRC */
|
||||
fusb_read_message(&goodcrc);
|
||||
|
||||
/* Check that the message is correct */
|
||||
if (PD_MSGTYPE_GET(&goodcrc) == PD_MSGTYPE_GOODCRC
|
||||
&& PD_NUMOBJ_GET(&goodcrc) == 0
|
||||
&& PD_MESSAGEID_GET(&goodcrc) == _tx_messageidcounter) {
|
||||
return PRLTxMessageSent;
|
||||
} else {
|
||||
return PRLTxTransmissionError;
|
||||
}
|
||||
/* Check that the message is correct */
|
||||
if (PD_MSGTYPE_GET(&goodcrc) == PD_MSGTYPE_GOODCRC && PD_NUMOBJ_GET(&goodcrc) == 0 && PD_MESSAGEID_GET(&goodcrc) == _tx_messageidcounter) {
|
||||
return PRLTxMessageSent;
|
||||
} else {
|
||||
return PRLTxTransmissionError;
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_error() {
|
||||
/* Increment MessageIDCounter */
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
/* Increment MessageIDCounter */
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify( PDB_EVT_PE_TX_ERR);
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_ERR);
|
||||
|
||||
return PRLTxWaitMessage;
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent() {
|
||||
messageSending = false;
|
||||
/* Increment MessageIDCounter */
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
messageSending = false;
|
||||
/* Increment MessageIDCounter */
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
|
||||
/* Tell the policy engine that we succeeded */
|
||||
PolicyEngine::notify( PDB_EVT_PE_TX_DONE);
|
||||
/* Tell the policy engine that we succeeded */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_DONE);
|
||||
|
||||
return PRLTxWaitMessage;
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
|
||||
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_discard_message() {
|
||||
/* If we were working on sending a message, increment MessageIDCounter */
|
||||
if (messageSending) {
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
/* If we were working on sending a message, increment MessageIDCounter */
|
||||
if (messageSending) {
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
|
||||
return PRLTxPHYReset;
|
||||
} else {
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
return PRLTxPHYReset;
|
||||
} else {
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
}
|
||||
void ProtocolTransmit::thread(const void *args) {
|
||||
(void) args;
|
||||
ProtocolTransmit::protocol_tx_state state = PRLTxPHYReset;
|
||||
(void)args;
|
||||
ProtocolTransmit::protocol_tx_state state = PRLTxPHYReset;
|
||||
|
||||
//Init the incoming message queue
|
||||
// Init the incoming message queue
|
||||
|
||||
while (true) {
|
||||
switch (state) {
|
||||
case PRLTxPHYReset:
|
||||
state = protocol_tx_phy_reset();
|
||||
break;
|
||||
case PRLTxWaitMessage:
|
||||
state = protocol_tx_wait_message();
|
||||
break;
|
||||
case PRLTxReset:
|
||||
state = protocol_tx_reset();
|
||||
break;
|
||||
case PRLTxConstructMessage:
|
||||
state = protocol_tx_construct_message();
|
||||
break;
|
||||
case PRLTxWaitResponse:
|
||||
state = protocol_tx_wait_response();
|
||||
break;
|
||||
case PRLTxMatchMessageID:
|
||||
state = protocol_tx_match_messageid();
|
||||
break;
|
||||
case PRLTxTransmissionError:
|
||||
state = protocol_tx_transmission_error();
|
||||
break;
|
||||
case PRLTxMessageSent:
|
||||
state = protocol_tx_message_sent();
|
||||
break;
|
||||
case PRLTxDiscardMessage:
|
||||
state = protocol_tx_discard_message();
|
||||
break;
|
||||
default:
|
||||
state = PRLTxPHYReset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
switch (state) {
|
||||
case PRLTxPHYReset:
|
||||
state = protocol_tx_phy_reset();
|
||||
break;
|
||||
case PRLTxWaitMessage:
|
||||
state = protocol_tx_wait_message();
|
||||
break;
|
||||
case PRLTxReset:
|
||||
state = protocol_tx_reset();
|
||||
break;
|
||||
case PRLTxConstructMessage:
|
||||
state = protocol_tx_construct_message();
|
||||
break;
|
||||
case PRLTxWaitResponse:
|
||||
state = protocol_tx_wait_response();
|
||||
break;
|
||||
case PRLTxMatchMessageID:
|
||||
state = protocol_tx_match_messageid();
|
||||
break;
|
||||
case PRLTxTransmissionError:
|
||||
state = protocol_tx_transmission_error();
|
||||
break;
|
||||
case PRLTxMessageSent:
|
||||
state = protocol_tx_message_sent();
|
||||
break;
|
||||
case PRLTxDiscardMessage:
|
||||
state = protocol_tx_discard_message();
|
||||
break;
|
||||
default:
|
||||
state = PRLTxPHYReset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolTransmit::notify(ProtocolTransmit::Notifications notification) {
|
||||
if (xEventGroupHandle != NULL) {
|
||||
xEventGroupSetBits(xEventGroupHandle, (uint32_t) notification);
|
||||
}
|
||||
if (xEventGroupHandle != NULL) {
|
||||
xEventGroupSetBits(xEventGroupHandle, (uint32_t)notification);
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolTransmit::init() {
|
||||
messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE,
|
||||
sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue);
|
||||
messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue);
|
||||
|
||||
osThreadStaticDef(pd_txTask, thread, PDB_PRIO_PRL, 0, TaskStackSize,
|
||||
TaskBuffer, &TaskControlBlock);
|
||||
TaskHandle = osThreadCreate(osThread(pd_txTask), NULL);
|
||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||
osThreadStaticDef(pd_txTask, thread, PDB_PRIO_PRL, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||
TaskHandle = osThreadCreate(osThread(pd_txTask), NULL);
|
||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||
}
|
||||
|
||||
void ProtocolTransmit::pushMessage(union pd_msg *msg) {
|
||||
if (messagesWaiting) {
|
||||
xQueueSend(messagesWaiting, msg, 100);
|
||||
}
|
||||
if (messagesWaiting) {
|
||||
xQueueSend(messagesWaiting, msg, 100);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProtocolTransmit::messagePending() {
|
||||
if (messagesWaiting) {
|
||||
return uxQueueMessagesWaiting(messagesWaiting) > 0;
|
||||
}
|
||||
return false;
|
||||
if (messagesWaiting) {
|
||||
return uxQueueMessagesWaiting(messagesWaiting) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProtocolTransmit::getMessage() {
|
||||
//Loads the pending message into the buffer
|
||||
if (messagesWaiting) {
|
||||
xQueueReceive(messagesWaiting, &temp_msg, 1);
|
||||
}
|
||||
// Loads the pending message into the buffer
|
||||
if (messagesWaiting) {
|
||||
xQueueReceive(messagesWaiting, &temp_msg, 1);
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolTransmit::Notifications ProtocolTransmit::waitForEvent(uint32_t mask,
|
||||
TickType_t ticksToWait) {
|
||||
if (xEventGroupHandle) {
|
||||
return (Notifications) xEventGroupWaitBits(xEventGroupHandle, mask,
|
||||
mask,
|
||||
pdFALSE, ticksToWait);
|
||||
}
|
||||
return (Notifications)0;
|
||||
ProtocolTransmit::Notifications ProtocolTransmit::waitForEvent(uint32_t mask, TickType_t ticksToWait) {
|
||||
if (xEventGroupHandle) {
|
||||
return (Notifications)xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait);
|
||||
}
|
||||
return (Notifications)0;
|
||||
}
|
||||
|
||||
@@ -6,308 +6,299 @@
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#ifdef I2C_SOFT
|
||||
#include <I2CBB.hpp>
|
||||
#include "FreeRTOS.h"
|
||||
#include <I2CBB.hpp>
|
||||
SemaphoreHandle_t I2CBB::I2CSemaphore = NULL;
|
||||
StaticSemaphore_t I2CBB::xSemaphoreBuffer;
|
||||
SemaphoreHandle_t I2CBB::I2CSemaphore2 = NULL;
|
||||
StaticSemaphore_t I2CBB::xSemaphoreBuffer2;
|
||||
void I2CBB::init() {
|
||||
//Set GPIO's to output open drain
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStruct.Pin = SDA2_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(SDA2_GPIO_Port, &GPIO_InitStruct);
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStruct.Pin = SCL2_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(SCL2_GPIO_Port, &GPIO_InitStruct);
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_SCL_HIGH();
|
||||
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
|
||||
I2CSemaphore2 = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer2);
|
||||
unlock();
|
||||
unlock2();
|
||||
|
||||
void I2CBB::init() {
|
||||
// Set GPIO's to output open drain
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStruct.Pin = SDA2_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(SDA2_GPIO_Port, &GPIO_InitStruct);
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStruct.Pin = SCL2_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(SCL2_GPIO_Port, &GPIO_InitStruct);
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_SCL_HIGH();
|
||||
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
|
||||
I2CSemaphore2 = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer2);
|
||||
unlock();
|
||||
unlock2();
|
||||
}
|
||||
|
||||
bool I2CBB::probe(uint8_t address) {
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(address);
|
||||
stop();
|
||||
unlock();
|
||||
return ack;
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(address);
|
||||
stop();
|
||||
unlock();
|
||||
return ack;
|
||||
}
|
||||
|
||||
bool I2CBB::Mem_Read(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData,
|
||||
uint16_t Size) {
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
ack = send(MemAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
SOFT_SCL_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
// stop();
|
||||
start();
|
||||
ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
while (Size) {
|
||||
pData[0] = read(Size > 1);
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
return true;
|
||||
bool I2CBB::Mem_Read(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size) {
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
ack = send(MemAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
SOFT_SCL_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
// stop();
|
||||
start();
|
||||
ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
while (Size) {
|
||||
pData[0] = read(Size > 1);
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2CBB::Mem_Write(uint16_t DevAddress, uint16_t MemAddress,
|
||||
const uint8_t *pData, uint16_t Size) {
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
ack = send(MemAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
while (Size) {
|
||||
resetWatchdog();
|
||||
ack = send(pData[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
return true;
|
||||
bool I2CBB::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, const uint8_t *pData, uint16_t Size) {
|
||||
if (!lock())
|
||||
return false;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
ack = send(MemAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
while (Size) {
|
||||
resetWatchdog();
|
||||
ack = send(pData[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
asm("bkpt");
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2CBB::Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size) {
|
||||
if (!lock())
|
||||
return;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size) {
|
||||
ack = send(pData[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
|
||||
if (!lock())
|
||||
return;
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size) {
|
||||
ack = send(pData[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2CBB::Receive(uint16_t DevAddress, uint8_t *pData, uint16_t Size) {
|
||||
if (!lock())
|
||||
return;
|
||||
start();
|
||||
bool ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size) {
|
||||
pData[0] = read(Size > 1);
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
if (!lock())
|
||||
return;
|
||||
start();
|
||||
bool ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size) {
|
||||
pData[0] = read(Size > 1);
|
||||
pData++;
|
||||
Size--;
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2CBB::TransmitReceive(uint16_t DevAddress, uint8_t *pData_tx,
|
||||
uint16_t Size_tx, uint8_t *pData_rx, uint16_t Size_rx) {
|
||||
if (Size_tx == 0 && Size_rx == 0)
|
||||
return;
|
||||
if (lock() == false)
|
||||
return;
|
||||
if (Size_tx) {
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size_tx) {
|
||||
ack = send(pData_tx[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
pData_tx++;
|
||||
Size_tx--;
|
||||
}
|
||||
}
|
||||
if (Size_rx) {
|
||||
start();
|
||||
bool ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size_rx) {
|
||||
pData_rx[0] = read(Size_rx > 1);
|
||||
pData_rx++;
|
||||
Size_rx--;
|
||||
}
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
void I2CBB::TransmitReceive(uint16_t DevAddress, uint8_t *pData_tx, uint16_t Size_tx, uint8_t *pData_rx, uint16_t Size_rx) {
|
||||
if (Size_tx == 0 && Size_rx == 0)
|
||||
return;
|
||||
if (lock() == false)
|
||||
return;
|
||||
if (Size_tx) {
|
||||
start();
|
||||
bool ack = send(DevAddress);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size_tx) {
|
||||
ack = send(pData_tx[0]);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
pData_tx++;
|
||||
Size_tx--;
|
||||
}
|
||||
}
|
||||
if (Size_rx) {
|
||||
start();
|
||||
bool ack = send(DevAddress | 1);
|
||||
if (!ack) {
|
||||
stop();
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
while (Size_rx) {
|
||||
pData_rx[0] = read(Size_rx > 1);
|
||||
pData_rx++;
|
||||
Size_rx--;
|
||||
}
|
||||
}
|
||||
stop();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2CBB::start() {
|
||||
/* I2C Start condition, data line goes low when clock is high */
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_HIGH();
|
||||
/* I2C Start condition, data line goes low when clock is high */
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_HIGH();
|
||||
}
|
||||
|
||||
void I2CBB::stop() {
|
||||
/* I2C Stop condition, clock goes high when data is low */
|
||||
SOFT_SDA_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
/* I2C Stop condition, clock goes high when data is low */
|
||||
SOFT_SDA_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
}
|
||||
|
||||
bool I2CBB::send(uint8_t value) {
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
write_bit(value & 0x80); // write the most-significant bit
|
||||
value <<= 1;
|
||||
}
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
write_bit(value & 0x80); // write the most-significant bit
|
||||
value <<= 1;
|
||||
}
|
||||
|
||||
SOFT_SDA_HIGH();
|
||||
bool ack = (read_bit() == 0);
|
||||
return ack;
|
||||
SOFT_SDA_HIGH();
|
||||
bool ack = (read_bit() == 0);
|
||||
return ack;
|
||||
}
|
||||
|
||||
uint8_t I2CBB::read(bool ack) {
|
||||
uint8_t B = 0;
|
||||
uint8_t B = 0;
|
||||
|
||||
uint8_t i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
B <<= 1;
|
||||
B |= read_bit();
|
||||
}
|
||||
uint8_t i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
B <<= 1;
|
||||
B |= read_bit();
|
||||
}
|
||||
|
||||
SOFT_SDA_HIGH();
|
||||
if (ack)
|
||||
write_bit(0);
|
||||
else
|
||||
write_bit(1);
|
||||
return B;
|
||||
SOFT_SDA_HIGH();
|
||||
if (ack)
|
||||
write_bit(0);
|
||||
else
|
||||
write_bit(1);
|
||||
return B;
|
||||
}
|
||||
|
||||
uint8_t I2CBB::read_bit() {
|
||||
uint8_t b;
|
||||
uint8_t b;
|
||||
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
|
||||
if (SOFT_SDA_READ())
|
||||
b = 1;
|
||||
else
|
||||
b = 0;
|
||||
if (SOFT_SDA_READ())
|
||||
b = 1;
|
||||
else
|
||||
b = 0;
|
||||
|
||||
SOFT_SCL_LOW();
|
||||
return b;
|
||||
SOFT_SCL_LOW();
|
||||
return b;
|
||||
}
|
||||
|
||||
void I2CBB::unlock() {
|
||||
xSemaphoreGive(I2CSemaphore);
|
||||
}
|
||||
void I2CBB::unlock() { xSemaphoreGive(I2CSemaphore); }
|
||||
|
||||
bool I2CBB::lock() {
|
||||
if (I2CSemaphore == NULL) {
|
||||
asm("bkpt");
|
||||
}
|
||||
bool a = xSemaphoreTake(I2CSemaphore, (TickType_t) 100) == pdTRUE;
|
||||
return a;
|
||||
if (I2CSemaphore == NULL) {
|
||||
asm("bkpt");
|
||||
}
|
||||
bool a = xSemaphoreTake(I2CSemaphore, (TickType_t)100) == pdTRUE;
|
||||
return a;
|
||||
}
|
||||
|
||||
void I2CBB::write_bit(uint8_t val) {
|
||||
if (val) {
|
||||
SOFT_SDA_HIGH();
|
||||
} else {
|
||||
SOFT_SDA_LOW();
|
||||
}
|
||||
if (val) {
|
||||
SOFT_SDA_HIGH();
|
||||
} else {
|
||||
SOFT_SDA_LOW();
|
||||
}
|
||||
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_LOW();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_HIGH();
|
||||
SOFT_I2C_DELAY();
|
||||
SOFT_SCL_LOW();
|
||||
}
|
||||
|
||||
void I2CBB::unlock2() {
|
||||
xSemaphoreGive(I2CSemaphore2);
|
||||
}
|
||||
void I2CBB::unlock2() { xSemaphoreGive(I2CSemaphore2); }
|
||||
|
||||
bool I2CBB::lock2() {
|
||||
if (I2CSemaphore2 == NULL) {
|
||||
asm("bkpt");
|
||||
}
|
||||
bool a = xSemaphoreTake(I2CSemaphore2, (TickType_t) 500) == pdTRUE;
|
||||
if (I2CSemaphore2 == NULL) {
|
||||
asm("bkpt");
|
||||
}
|
||||
bool a = xSemaphoreTake(I2CSemaphore2, (TickType_t)500) == pdTRUE;
|
||||
|
||||
return a;
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,34 +10,30 @@
|
||||
#include "LIS2DH12.hpp"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = { { LIS_CTRL_REG1, 0x17, 0 }, // 25Hz
|
||||
{ LIS_CTRL_REG2, 0b00001000, 0 }, // Highpass filter off
|
||||
{ LIS_CTRL_REG3, 0b01100000, 0 }, // Setup interrupt pins
|
||||
{ LIS_CTRL_REG4, 0b00001000, 0 }, // Block update mode off, HR on
|
||||
{ LIS_CTRL_REG5, 0b00000010, 0 }, //
|
||||
{ LIS_CTRL_REG6, 0b01100010, 0 },
|
||||
//Basically setup the unit to run, and enable 4D orientation detection
|
||||
{ LIS_INT2_CFG, 0b01111110, 0 }, //setup for movement detection
|
||||
{ LIS_INT2_THS, 0x28, 0 }, //
|
||||
{ LIS_INT2_DURATION, 64, 0 }, //
|
||||
{ LIS_INT1_CFG, 0b01111110, 0 }, //
|
||||
{ LIS_INT1_THS, 0x28, 0 }, //
|
||||
{ LIS_INT1_DURATION, 64, 0 } };
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = {{LIS_CTRL_REG1, 0x17, 0}, // 25Hz
|
||||
{LIS_CTRL_REG2, 0b00001000, 0}, // Highpass filter off
|
||||
{LIS_CTRL_REG3, 0b01100000, 0}, // Setup interrupt pins
|
||||
{LIS_CTRL_REG4, 0b00001000, 0}, // Block update mode off, HR on
|
||||
{LIS_CTRL_REG5, 0b00000010, 0}, //
|
||||
{LIS_CTRL_REG6, 0b01100010, 0},
|
||||
// Basically setup the unit to run, and enable 4D orientation detection
|
||||
{LIS_INT2_CFG, 0b01111110, 0}, // setup for movement detection
|
||||
{LIS_INT2_THS, 0x28, 0}, //
|
||||
{LIS_INT2_DURATION, 64, 0}, //
|
||||
{LIS_INT1_CFG, 0b01111110, 0}, //
|
||||
{LIS_INT1_THS, 0x28, 0}, //
|
||||
{LIS_INT1_DURATION, 64, 0}};
|
||||
|
||||
bool LIS2DH12::initalize() {
|
||||
return FRToSI2C::writeRegistersBulk(LIS2DH_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
}
|
||||
bool LIS2DH12::initalize() { return FRToSI2C::writeRegistersBulk(LIS2DH_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0])); }
|
||||
|
||||
void LIS2DH12::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
|
||||
std::array<int16_t, 3> sensorData;
|
||||
std::array<int16_t, 3> sensorData;
|
||||
|
||||
FRToSI2C::Mem_Read(LIS2DH_I2C_ADDRESS, 0xA8, reinterpret_cast<uint8_t*>(sensorData.begin()), sensorData.size() * sizeof(int16_t));
|
||||
FRToSI2C::Mem_Read(LIS2DH_I2C_ADDRESS, 0xA8, reinterpret_cast<uint8_t *>(sensorData.begin()), sensorData.size() * sizeof(int16_t));
|
||||
|
||||
x = sensorData[0];
|
||||
y = sensorData[1];
|
||||
z = sensorData[2];
|
||||
x = sensorData[0];
|
||||
y = sensorData[1];
|
||||
z = sensorData[2];
|
||||
}
|
||||
|
||||
bool LIS2DH12::detect() {
|
||||
return FRToSI2C::probe(LIS2DH_I2C_ADDRESS);
|
||||
}
|
||||
bool LIS2DH12::detect() { return FRToSI2C::probe(LIS2DH_I2C_ADDRESS); }
|
||||
|
||||
@@ -10,54 +10,48 @@
|
||||
#include "MMA8652FC.hpp"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = { { CTRL_REG2, 0, 0 }, //Normal mode
|
||||
{ CTRL_REG2, 0x40, 2 }, // Reset all registers to POR values
|
||||
{ FF_MT_CFG_REG, 0x78, 0 }, // Enable motion detection for X, Y, Z axis, latch disabled
|
||||
{ PL_CFG_REG, 0x40, 0 }, //Enable the orientation detection
|
||||
{ PL_COUNT_REG, 200, 0 }, //200 count debounce
|
||||
{ PL_BF_ZCOMP_REG, 0b01000111, 0 }, //Set the threshold to 42 degrees
|
||||
{ P_L_THS_REG, 0b10011100, 0 }, //Up the trip angles
|
||||
{ CTRL_REG4, 0x01 | (1 << 4), 0 }, // Enable dataready interrupt & orientation interrupt
|
||||
{ CTRL_REG5, 0x01, 0 }, // Route data ready interrupts to INT1 ->PB5 ->EXTI5, leaving orientation routed to INT2
|
||||
{ CTRL_REG2, 0x12, 0 }, //Set maximum resolution oversampling
|
||||
{ XYZ_DATA_CFG_REG, (1 << 4), 0 }, //select high pass filtered data
|
||||
{ HP_FILTER_CUTOFF_REG, 0x03, 0 }, //select high pass filtered data
|
||||
{ CTRL_REG1, 0x19, 0 } // ODR=12 Hz, Active mode
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = {
|
||||
{CTRL_REG2, 0, 0}, // Normal mode
|
||||
{CTRL_REG2, 0x40, 2}, // Reset all registers to POR values
|
||||
{FF_MT_CFG_REG, 0x78, 0}, // Enable motion detection for X, Y, Z axis, latch disabled
|
||||
{PL_CFG_REG, 0x40, 0}, // Enable the orientation detection
|
||||
{PL_COUNT_REG, 200, 0}, // 200 count debounce
|
||||
{PL_BF_ZCOMP_REG, 0b01000111, 0}, // Set the threshold to 42 degrees
|
||||
{P_L_THS_REG, 0b10011100, 0}, // Up the trip angles
|
||||
{CTRL_REG4, 0x01 | (1 << 4), 0}, // Enable dataready interrupt & orientation interrupt
|
||||
{CTRL_REG5, 0x01, 0}, // Route data ready interrupts to INT1 ->PB5 ->EXTI5, leaving orientation routed to INT2
|
||||
{CTRL_REG2, 0x12, 0}, // Set maximum resolution oversampling
|
||||
{XYZ_DATA_CFG_REG, (1 << 4), 0}, // select high pass filtered data
|
||||
{HP_FILTER_CUTOFF_REG, 0x03, 0}, // select high pass filtered data
|
||||
{CTRL_REG1, 0x19, 0} // ODR=12 Hz, Active mode
|
||||
};
|
||||
|
||||
bool MMA8652FC::initalize() {
|
||||
return FRToSI2C::writeRegistersBulk(MMA8652FC_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
|
||||
}
|
||||
bool MMA8652FC::initalize() { return FRToSI2C::writeRegistersBulk(MMA8652FC_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0])); }
|
||||
|
||||
Orientation MMA8652FC::getOrientation() {
|
||||
//First read the PL_STATUS register
|
||||
uint8_t plStatus = FRToSI2C::I2C_RegisterRead(MMA8652FC_I2C_ADDRESS,
|
||||
PL_STATUS_REG);
|
||||
if ((plStatus & 0b10000000) == 0b10000000) {
|
||||
plStatus >>= 1; //We don't need the up/down bit
|
||||
plStatus &= 0x03; //mask to the two lower bits
|
||||
// First read the PL_STATUS register
|
||||
uint8_t plStatus = FRToSI2C::I2C_RegisterRead(MMA8652FC_I2C_ADDRESS, PL_STATUS_REG);
|
||||
if ((plStatus & 0b10000000) == 0b10000000) {
|
||||
plStatus >>= 1; // We don't need the up/down bit
|
||||
plStatus &= 0x03; // mask to the two lower bits
|
||||
|
||||
//0 == left handed
|
||||
//1 == right handed
|
||||
// 0 == left handed
|
||||
// 1 == right handed
|
||||
|
||||
return static_cast<Orientation>(plStatus);
|
||||
}
|
||||
return static_cast<Orientation>(plStatus);
|
||||
}
|
||||
|
||||
return ORIENTATION_FLAT;
|
||||
return ORIENTATION_FLAT;
|
||||
}
|
||||
|
||||
void MMA8652FC::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
|
||||
std::array<int16_t, 3> sensorData;
|
||||
std::array<int16_t, 3> sensorData;
|
||||
|
||||
FRToSI2C::Mem_Read(MMA8652FC_I2C_ADDRESS, OUT_X_MSB_REG, reinterpret_cast<uint8_t*>(sensorData.begin()), sensorData.size() * sizeof(int16_t));
|
||||
FRToSI2C::Mem_Read(MMA8652FC_I2C_ADDRESS, OUT_X_MSB_REG, reinterpret_cast<uint8_t *>(sensorData.begin()), sensorData.size() * sizeof(int16_t));
|
||||
|
||||
x = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[0])));
|
||||
y = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[1])));
|
||||
z = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[2])));
|
||||
x = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t *>(&sensorData[0])));
|
||||
y = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t *>(&sensorData[1])));
|
||||
z = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t *>(&sensorData[2])));
|
||||
}
|
||||
|
||||
bool MMA8652FC::detect() {
|
||||
return FRToSI2C::probe(MMA8652FC_I2C_ADDRESS);
|
||||
}
|
||||
bool MMA8652FC::detect() { return FRToSI2C::probe(MMA8652FC_I2C_ADDRESS); }
|
||||
|
||||
@@ -5,46 +5,42 @@
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#include <MSA301.h>
|
||||
#include "MSA301_defines.h"
|
||||
#include <MSA301.h>
|
||||
#define MSA301_I2C_ADDRESS 0x4C
|
||||
bool MSA301::detect() {
|
||||
return FRToSI2C::probe(MSA301_I2C_ADDRESS);
|
||||
}
|
||||
bool MSA301::detect() { return FRToSI2C::probe(MSA301_I2C_ADDRESS); }
|
||||
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = { //
|
||||
//
|
||||
{ MSA301_REG_ODR, 0b00001000, 1 }, //X/Y/Z enabled @ 250Hz
|
||||
{ MSA301_REG_POWERMODE, 0b0001001, 1 }, // Normal mode
|
||||
{ MSA301_REG_RESRANGE, 0b00000001, 0 }, // 14bit resolution @ 4G range
|
||||
{ MSA301_REG_ORIENT_HY, 0b01000000, 0 }, // 4*62.5mg hyst, no blocking, symmetrical
|
||||
{ MSA301_REG_INTSET0, 1 << 6, 0 }, // Turn on orientation detection (by enabling its interrupt)
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = {
|
||||
//
|
||||
//
|
||||
{MSA301_REG_ODR, 0b00001000, 1}, // X/Y/Z enabled @ 250Hz
|
||||
{MSA301_REG_POWERMODE, 0b0001001, 1}, // Normal mode
|
||||
{MSA301_REG_RESRANGE, 0b00000001, 0}, // 14bit resolution @ 4G range
|
||||
{MSA301_REG_ORIENT_HY, 0b01000000, 0}, // 4*62.5mg hyst, no blocking, symmetrical
|
||||
{MSA301_REG_INTSET0, 1 << 6, 0}, // Turn on orientation detection (by enabling its interrupt)
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
bool MSA301::initalize() {
|
||||
return FRToSI2C::writeRegistersBulk(MSA301_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
}
|
||||
bool MSA301::initalize() { return FRToSI2C::writeRegistersBulk(MSA301_I2C_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0])); }
|
||||
|
||||
Orientation MSA301::getOrientation() {
|
||||
uint8_t temp = 0;
|
||||
FRToSI2C::Mem_Read(MSA301_I2C_ADDRESS, MSA301_REG_ORIENT_STATUS, &temp, 1);
|
||||
switch (temp) {
|
||||
case 112:
|
||||
return Orientation::ORIENTATION_LEFT_HAND;
|
||||
case 96:
|
||||
return Orientation::ORIENTATION_RIGHT_HAND;
|
||||
default:
|
||||
return Orientation::ORIENTATION_FLAT;
|
||||
}
|
||||
uint8_t temp = 0;
|
||||
FRToSI2C::Mem_Read(MSA301_I2C_ADDRESS, MSA301_REG_ORIENT_STATUS, &temp, 1);
|
||||
switch (temp) {
|
||||
case 112:
|
||||
return Orientation::ORIENTATION_LEFT_HAND;
|
||||
case 96:
|
||||
return Orientation::ORIENTATION_RIGHT_HAND;
|
||||
default:
|
||||
return Orientation::ORIENTATION_FLAT;
|
||||
}
|
||||
}
|
||||
|
||||
void MSA301::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
|
||||
uint8_t temp[6];
|
||||
//Bulk read all 6 regs
|
||||
FRToSI2C::Mem_Read(MSA301_I2C_ADDRESS, MSA301_REG_OUT_X_L, temp, 6);
|
||||
x = int16_t(((int16_t) temp[1]) << 8 | temp[0]) >> 2;
|
||||
y = int16_t(((int16_t) temp[3]) << 8 | temp[2]) >> 2;
|
||||
z = int16_t(((int16_t) temp[5]) << 8 | temp[4]) >> 2;
|
||||
|
||||
uint8_t temp[6];
|
||||
// Bulk read all 6 regs
|
||||
FRToSI2C::Mem_Read(MSA301_I2C_ADDRESS, MSA301_REG_OUT_X_L, temp, 6);
|
||||
x = int16_t(((int16_t)temp[1]) << 8 | temp[0]) >> 2;
|
||||
y = int16_t(((int16_t)temp[3]) << 8 | temp[2]) >> 2;
|
||||
z = int16_t(((int16_t)temp[5]) << 8 | temp[4]) >> 2;
|
||||
}
|
||||
|
||||
@@ -5,63 +5,63 @@
|
||||
* Author: Ben V. Brown
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <OLED.hpp>
|
||||
#include <stdlib.h>
|
||||
#include "../../configuration.h"
|
||||
#include "Translation.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "../../configuration.h"
|
||||
#include <OLED.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
const uint8_t *OLED::currentFont; // Pointer to the current font used for
|
||||
const uint8_t *OLED::currentFont; // Pointer to the current font used for
|
||||
// rendering to the buffer
|
||||
uint8_t *OLED::firstStripPtr; // Pointers to the strips to allow for buffer
|
||||
uint8_t *OLED::firstStripPtr; // Pointers to the strips to allow for buffer
|
||||
// having extra content
|
||||
uint8_t *OLED::secondStripPtr; // Pointers to the strips
|
||||
bool OLED::inLeftHandedMode; // Whether the screen is in left or not (used for
|
||||
uint8_t *OLED::secondStripPtr; // Pointers to the strips
|
||||
bool OLED::inLeftHandedMode; // Whether the screen is in left or not (used for
|
||||
// offsets in GRAM)
|
||||
OLED::DisplayState OLED::displayState;
|
||||
uint8_t OLED::fontWidth, OLED::fontHeight;
|
||||
int16_t OLED::cursor_x, OLED::cursor_y;
|
||||
bool OLED::initDone = false;
|
||||
uint8_t OLED::displayOffset;
|
||||
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer
|
||||
uint8_t OLED::secondFrameBuffer[OLED_WIDTH * 2];
|
||||
uint8_t OLED::fontWidth, OLED::fontHeight;
|
||||
int16_t OLED::cursor_x, OLED::cursor_y;
|
||||
bool OLED::initDone = false;
|
||||
uint8_t OLED::displayOffset;
|
||||
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer
|
||||
uint8_t OLED::secondFrameBuffer[OLED_WIDTH * 2];
|
||||
|
||||
/*Setup params for the OLED screen*/
|
||||
/*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/
|
||||
/*All commands are prefixed with 0x80*/
|
||||
/*Data packets are prefixed with 0x40*/
|
||||
FRToSI2C::I2C_REG OLED_Setup_Array[] = {
|
||||
/**/
|
||||
{ 0x80, 0xAE, 0 }, /*Display off*/
|
||||
{ 0x80, 0xD5, 0 }, /*Set display clock divide ratio / osc freq*/
|
||||
{ 0x80, 0x52, 0 }, /*Divide ratios*/
|
||||
{ 0x80, 0xA8, 0 }, /*Set Multiplex Ratio*/
|
||||
{ 0x80, 0x0F, 0 }, /*16 == max brightness,39==dimmest*/
|
||||
{ 0x80, 0xC0, 0 }, /*Set COM Scan direction*/
|
||||
{ 0x80, 0xD3, 0 }, /*Set vertical Display offset*/
|
||||
{ 0x80, 0x00, 0 }, /*0 Offset*/
|
||||
{ 0x80, 0x40, 0 }, /*Set Display start line to 0*/
|
||||
{ 0x80, 0xA0, 0 }, /*Set Segment remap to normal*/
|
||||
{ 0x80, 0x8D, 0 }, /*Charge Pump*/
|
||||
{ 0x80, 0x14, 0 }, /*Charge Pump settings*/
|
||||
{ 0x80, 0xDA, 0 }, /*Set VCOM Pins hardware config*/
|
||||
{ 0x80, 0x02, 0 }, /*Combination 2*/
|
||||
{ 0x80, 0x81, 0 }, /*Contrast*/
|
||||
{ 0x80, 0x33, 0 }, /*^51*/
|
||||
{ 0x80, 0xD9, 0 }, /*Set pre-charge period*/
|
||||
{ 0x80, 0xF1, 0 }, /*Pre charge period*/
|
||||
{ 0x80, 0xDB, 0 }, /*Adjust VCOMH regulator ouput*/
|
||||
{ 0x80, 0x30, 0 }, /*VCOM level*/
|
||||
{ 0x80, 0xA4, 0 }, /*Enable the display GDDR*/
|
||||
{ 0x80, 0XA6, 0 }, /*Normal display*/
|
||||
{ 0x80, 0x20, 0 }, /*Memory Mode*/
|
||||
{ 0x80, 0x00, 0 }, /*Wrap memory*/
|
||||
{ 0x80, 0xAF, 0 }, /*Display on*/
|
||||
/**/
|
||||
{0x80, 0xAE, 0}, /*Display off*/
|
||||
{0x80, 0xD5, 0}, /*Set display clock divide ratio / osc freq*/
|
||||
{0x80, 0x52, 0}, /*Divide ratios*/
|
||||
{0x80, 0xA8, 0}, /*Set Multiplex Ratio*/
|
||||
{0x80, 0x0F, 0}, /*16 == max brightness,39==dimmest*/
|
||||
{0x80, 0xC0, 0}, /*Set COM Scan direction*/
|
||||
{0x80, 0xD3, 0}, /*Set vertical Display offset*/
|
||||
{0x80, 0x00, 0}, /*0 Offset*/
|
||||
{0x80, 0x40, 0}, /*Set Display start line to 0*/
|
||||
{0x80, 0xA0, 0}, /*Set Segment remap to normal*/
|
||||
{0x80, 0x8D, 0}, /*Charge Pump*/
|
||||
{0x80, 0x14, 0}, /*Charge Pump settings*/
|
||||
{0x80, 0xDA, 0}, /*Set VCOM Pins hardware config*/
|
||||
{0x80, 0x02, 0}, /*Combination 2*/
|
||||
{0x80, 0x81, 0}, /*Contrast*/
|
||||
{0x80, 0x33, 0}, /*^51*/
|
||||
{0x80, 0xD9, 0}, /*Set pre-charge period*/
|
||||
{0x80, 0xF1, 0}, /*Pre charge period*/
|
||||
{0x80, 0xDB, 0}, /*Adjust VCOMH regulator ouput*/
|
||||
{0x80, 0x30, 0}, /*VCOM level*/
|
||||
{0x80, 0xA4, 0}, /*Enable the display GDDR*/
|
||||
{0x80, 0XA6, 0}, /*Normal display*/
|
||||
{0x80, 0x20, 0}, /*Memory Mode*/
|
||||
{0x80, 0x00, 0}, /*Wrap memory*/
|
||||
{0x80, 0xAF, 0}, /*Display on*/
|
||||
};
|
||||
// Setup based on the SSD1307 and modified for the SSD1306
|
||||
|
||||
const uint8_t REFRESH_COMMANDS[17] = { 0x80, 0xAF, 0x80, 0x21, 0x80, 0x20, 0x80, 0x7F, 0x80, 0xC0, 0x80, 0x22, 0x80, 0x00, 0x80, 0x01, 0x40 };
|
||||
const uint8_t REFRESH_COMMANDS[17] = {0x80, 0xAF, 0x80, 0x21, 0x80, 0x20, 0x80, 0x7F, 0x80, 0xC0, 0x80, 0x22, 0x80, 0x00, 0x80, 0x01, 0x40};
|
||||
|
||||
/*
|
||||
* Animation timing function that follows a bezier curve.
|
||||
@@ -69,9 +69,7 @@ const uint8_t REFRESH_COMMANDS[17] = { 0x80, 0xAF, 0x80, 0x21, 0x80, 0x20, 0x80,
|
||||
* Returns a new percentage value with ease in and ease out.
|
||||
* Original floating point formula: t * t * (3.0f - 2.0f * t);
|
||||
*/
|
||||
static uint8_t easeInOutTiming(uint8_t t) {
|
||||
return t * t * (300 - 2 * t) / 10000;
|
||||
}
|
||||
static uint8_t easeInOutTiming(uint8_t t) { return t * t * (300 - 2 * t) / 10000; }
|
||||
|
||||
/*
|
||||
* Returns the value between a and b, using a percentage value t.
|
||||
@@ -79,41 +77,39 @@ static uint8_t easeInOutTiming(uint8_t t) {
|
||||
* @param b The value associated with 100%
|
||||
* @param t The percentage [0..<100]
|
||||
*/
|
||||
static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) {
|
||||
return a + t * (b - a) / 100;
|
||||
}
|
||||
static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) { return a + t * (b - a) / 100; }
|
||||
|
||||
void OLED::initialize() {
|
||||
cursor_x = cursor_y = 0;
|
||||
currentFont = USER_FONT_12;
|
||||
fontWidth = 12;
|
||||
inLeftHandedMode = false;
|
||||
firstStripPtr = &screenBuffer[FRAMEBUFFER_START];
|
||||
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
|
||||
fontHeight = 16;
|
||||
displayOffset = 0;
|
||||
memcpy(&screenBuffer[0], &REFRESH_COMMANDS[0], sizeof(REFRESH_COMMANDS));
|
||||
cursor_x = cursor_y = 0;
|
||||
currentFont = USER_FONT_12;
|
||||
fontWidth = 12;
|
||||
inLeftHandedMode = false;
|
||||
firstStripPtr = &screenBuffer[FRAMEBUFFER_START];
|
||||
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
|
||||
fontHeight = 16;
|
||||
displayOffset = 0;
|
||||
memcpy(&screenBuffer[0], &REFRESH_COMMANDS[0], sizeof(REFRESH_COMMANDS));
|
||||
|
||||
// Set the display to be ON once the settings block is sent and send the
|
||||
// initialisation data to the OLED.
|
||||
// Set the display to be ON once the settings block is sent and send the
|
||||
// initialisation data to the OLED.
|
||||
|
||||
for (int tries = 0; tries < 10; tries++) {
|
||||
if (FRToSI2C::writeRegistersBulk(DEVICEADDR_OLED, OLED_Setup_Array, sizeof(OLED_Setup_Array) / sizeof(OLED_Setup_Array[0]))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setDisplayState(DisplayState::ON);
|
||||
initDone = true;
|
||||
for (int tries = 0; tries < 10; tries++) {
|
||||
if (FRToSI2C::writeRegistersBulk(DEVICEADDR_OLED, OLED_Setup_Array, sizeof(OLED_Setup_Array) / sizeof(OLED_Setup_Array[0]))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setDisplayState(DisplayState::ON);
|
||||
initDone = true;
|
||||
}
|
||||
void OLED::setFramebuffer(uint8_t *buffer) {
|
||||
if (buffer == NULL) {
|
||||
firstStripPtr = &screenBuffer[FRAMEBUFFER_START];
|
||||
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
|
||||
return;
|
||||
}
|
||||
if (buffer == NULL) {
|
||||
firstStripPtr = &screenBuffer[FRAMEBUFFER_START];
|
||||
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
|
||||
return;
|
||||
}
|
||||
|
||||
firstStripPtr = &buffer[0];
|
||||
secondStripPtr = &buffer[OLED_WIDTH];
|
||||
firstStripPtr = &buffer[0];
|
||||
secondStripPtr = &buffer[OLED_WIDTH];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -122,18 +118,18 @@ void OLED::setFramebuffer(uint8_t *buffer) {
|
||||
* Precursor is the command char that is used to select the table.
|
||||
*/
|
||||
void OLED::drawChar(char c) {
|
||||
if (c == '\x01' && cursor_y == 0) { // 0x01 is used as new line char
|
||||
cursor_x = 0;
|
||||
cursor_y = 8;
|
||||
return;
|
||||
} else if (c == 0) {
|
||||
return;
|
||||
}
|
||||
uint16_t index = c - 2; //First index is \x02
|
||||
uint8_t *charPointer;
|
||||
charPointer = ((uint8_t*) currentFont) + ((fontWidth * (fontHeight / 8)) * index);
|
||||
drawArea(cursor_x, cursor_y, fontWidth, fontHeight, charPointer);
|
||||
cursor_x += fontWidth;
|
||||
if (c == '\x01' && cursor_y == 0) { // 0x01 is used as new line char
|
||||
cursor_x = 0;
|
||||
cursor_y = 8;
|
||||
return;
|
||||
} else if (c == 0) {
|
||||
return;
|
||||
}
|
||||
uint16_t index = c - 2; // First index is \x02
|
||||
uint8_t *charPointer;
|
||||
charPointer = ((uint8_t *)currentFont) + ((fontWidth * (fontHeight / 8)) * index);
|
||||
drawArea(cursor_x, cursor_y, fontWidth, fontHeight, charPointer);
|
||||
cursor_x += fontWidth;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -141,18 +137,18 @@ void OLED::drawChar(char c) {
|
||||
* of the indicator in pixels (0..<16).
|
||||
*/
|
||||
void OLED::drawScrollIndicator(uint8_t y, uint8_t height) {
|
||||
union u_type {
|
||||
uint16_t whole;
|
||||
uint8_t strips[2];
|
||||
} column;
|
||||
union u_type {
|
||||
uint16_t whole;
|
||||
uint8_t strips[2];
|
||||
} column;
|
||||
|
||||
column.whole = (1 << height) - 1;
|
||||
column.whole <<= y;
|
||||
column.whole = (1 << height) - 1;
|
||||
column.whole <<= y;
|
||||
|
||||
// Draw a one pixel wide bar to the left with a single pixel as
|
||||
// the scroll indicator.
|
||||
fillArea(OLED_WIDTH - 1, 0, 1, 8, column.strips[0]);
|
||||
fillArea(OLED_WIDTH - 1, 8, 1, 8, column.strips[1]);
|
||||
// Draw a one pixel wide bar to the left with a single pixel as
|
||||
// the scroll indicator.
|
||||
fillArea(OLED_WIDTH - 1, 0, 1, 8, column.strips[0]);
|
||||
fillArea(OLED_WIDTH - 1, 8, 1, 8, column.strips[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,327 +159,323 @@ void OLED::drawScrollIndicator(uint8_t y, uint8_t height) {
|
||||
* Otherwise a rewinding navigation animation is shown to the second framebuffer contents.
|
||||
*/
|
||||
void OLED::transitionSecondaryFramebuffer(bool forwardNavigation) {
|
||||
uint8_t *firstBackStripPtr = &secondFrameBuffer[0];
|
||||
uint8_t *secondBackStripPtr = &secondFrameBuffer[OLED_WIDTH];
|
||||
uint8_t *firstBackStripPtr = &secondFrameBuffer[0];
|
||||
uint8_t *secondBackStripPtr = &secondFrameBuffer[OLED_WIDTH];
|
||||
|
||||
uint32_t totalDuration = 50; // 500ms
|
||||
uint32_t duration = 0;
|
||||
uint32_t start = xTaskGetTickCount();
|
||||
uint8_t offset = 0;
|
||||
uint32_t totalDuration = 50; // 500ms
|
||||
uint32_t duration = 0;
|
||||
uint32_t start = xTaskGetTickCount();
|
||||
uint8_t offset = 0;
|
||||
|
||||
while (duration <= totalDuration) {
|
||||
duration = xTaskGetTickCount() - start;
|
||||
uint8_t progress = duration * TICKS_SECOND / totalDuration;
|
||||
progress = easeInOutTiming(progress);
|
||||
progress = lerp(0, OLED_WIDTH, progress);
|
||||
if (progress > OLED_WIDTH) {
|
||||
progress = OLED_WIDTH;
|
||||
}
|
||||
while (duration <= totalDuration) {
|
||||
duration = xTaskGetTickCount() - start;
|
||||
uint8_t progress = duration * TICKS_SECOND / totalDuration;
|
||||
progress = easeInOutTiming(progress);
|
||||
progress = lerp(0, OLED_WIDTH, progress);
|
||||
if (progress > OLED_WIDTH) {
|
||||
progress = OLED_WIDTH;
|
||||
}
|
||||
|
||||
// When forward, current contents move to the left out.
|
||||
// Otherwise the contents move to the right out.
|
||||
uint8_t oldStart = forwardNavigation ? 0 : progress;
|
||||
uint8_t oldPrevious = forwardNavigation ? progress - offset : offset;
|
||||
// When forward, current contents move to the left out.
|
||||
// Otherwise the contents move to the right out.
|
||||
uint8_t oldStart = forwardNavigation ? 0 : progress;
|
||||
uint8_t oldPrevious = forwardNavigation ? progress - offset : offset;
|
||||
|
||||
// Content from the second framebuffer moves in from the right (forward)
|
||||
// or from the left (not forward).
|
||||
uint8_t newStart = forwardNavigation ? OLED_WIDTH - progress : 0;
|
||||
uint8_t newEnd = forwardNavigation ? 0 : OLED_WIDTH - progress;
|
||||
// Content from the second framebuffer moves in from the right (forward)
|
||||
// or from the left (not forward).
|
||||
uint8_t newStart = forwardNavigation ? OLED_WIDTH - progress : 0;
|
||||
uint8_t newEnd = forwardNavigation ? 0 : OLED_WIDTH - progress;
|
||||
|
||||
offset = progress;
|
||||
offset = progress;
|
||||
|
||||
memmove(&firstStripPtr[oldStart], &firstStripPtr[oldPrevious],
|
||||
OLED_WIDTH - progress);
|
||||
memmove(&secondStripPtr[oldStart], &secondStripPtr[oldPrevious],
|
||||
OLED_WIDTH - progress);
|
||||
memmove(&firstStripPtr[oldStart], &firstStripPtr[oldPrevious], OLED_WIDTH - progress);
|
||||
memmove(&secondStripPtr[oldStart], &secondStripPtr[oldPrevious], OLED_WIDTH - progress);
|
||||
|
||||
memmove(&firstStripPtr[newStart], &firstBackStripPtr[newEnd], progress);
|
||||
memmove(&secondStripPtr[newStart], &secondBackStripPtr[newEnd], progress);
|
||||
memmove(&firstStripPtr[newStart], &firstBackStripPtr[newEnd], progress);
|
||||
memmove(&secondStripPtr[newStart], &secondBackStripPtr[newEnd], progress);
|
||||
|
||||
refresh();
|
||||
osDelay(40);
|
||||
}
|
||||
refresh();
|
||||
osDelay(40);
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::useSecondaryFramebuffer(bool useSecondary) {
|
||||
if (useSecondary) {
|
||||
setFramebuffer(secondFrameBuffer);
|
||||
} else {
|
||||
setFramebuffer(NULL);
|
||||
}
|
||||
if (useSecondary) {
|
||||
setFramebuffer(secondFrameBuffer);
|
||||
} else {
|
||||
setFramebuffer(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::setRotation(bool leftHanded) {
|
||||
#ifdef OLED_FLIP
|
||||
leftHanded = !leftHanded;
|
||||
leftHanded = !leftHanded;
|
||||
#endif
|
||||
if (inLeftHandedMode == leftHanded) {
|
||||
return;
|
||||
}
|
||||
if (inLeftHandedMode == leftHanded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// send command struct again with changes
|
||||
if (leftHanded) {
|
||||
OLED_Setup_Array[5].val = 0xC8; // c1?
|
||||
OLED_Setup_Array[9].val = 0xA1;
|
||||
} else {
|
||||
OLED_Setup_Array[5].val = 0xC0;
|
||||
OLED_Setup_Array[9].val = 0xA0;
|
||||
}
|
||||
FRToSI2C::writeRegistersBulk(DEVICEADDR_OLED, OLED_Setup_Array, sizeof(OLED_Setup_Array) / sizeof(OLED_Setup_Array[0]));
|
||||
// send command struct again with changes
|
||||
if (leftHanded) {
|
||||
OLED_Setup_Array[5].val = 0xC8; // c1?
|
||||
OLED_Setup_Array[9].val = 0xA1;
|
||||
} else {
|
||||
OLED_Setup_Array[5].val = 0xC0;
|
||||
OLED_Setup_Array[9].val = 0xA0;
|
||||
}
|
||||
FRToSI2C::writeRegistersBulk(DEVICEADDR_OLED, OLED_Setup_Array, sizeof(OLED_Setup_Array) / sizeof(OLED_Setup_Array[0]));
|
||||
|
||||
inLeftHandedMode = leftHanded;
|
||||
inLeftHandedMode = leftHanded;
|
||||
|
||||
screenBuffer[5] = inLeftHandedMode ? 0 : 32; // display is shifted by 32 in left handed
|
||||
// mode as driver ram is 128 wide
|
||||
screenBuffer[7] = inLeftHandedMode ? 95 : 0x7F; // End address of the ram segment we are writing to (96 wide)
|
||||
screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0;
|
||||
screenBuffer[5] = inLeftHandedMode ? 0 : 32; // display is shifted by 32 in left handed
|
||||
// mode as driver ram is 128 wide
|
||||
screenBuffer[7] = inLeftHandedMode ? 95 : 0x7F; // End address of the ram segment we are writing to (96 wide)
|
||||
screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0;
|
||||
}
|
||||
|
||||
// print a string to the current cursor location
|
||||
void OLED::print(const char *str) {
|
||||
while (str[0]) {
|
||||
drawChar(str[0]);
|
||||
str++;
|
||||
}
|
||||
while (str[0]) {
|
||||
drawChar(str[0]);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::setFont(uint8_t fontNumber) {
|
||||
if (fontNumber == 1) {
|
||||
// small font
|
||||
currentFont = USER_FONT_6x8;
|
||||
fontHeight = 8;
|
||||
fontWidth = 6;
|
||||
} else if (fontNumber == 2) {
|
||||
currentFont = ExtraFontChars;
|
||||
fontHeight = 16;
|
||||
fontWidth = 12;
|
||||
} else {
|
||||
currentFont = USER_FONT_12;
|
||||
fontHeight = 16;
|
||||
fontWidth = 12;
|
||||
}
|
||||
if (fontNumber == 1) {
|
||||
// small font
|
||||
currentFont = USER_FONT_6x8;
|
||||
fontHeight = 8;
|
||||
fontWidth = 6;
|
||||
} else if (fontNumber == 2) {
|
||||
currentFont = ExtraFontChars;
|
||||
fontHeight = 16;
|
||||
fontWidth = 12;
|
||||
} else {
|
||||
currentFont = USER_FONT_12;
|
||||
fontHeight = 16;
|
||||
fontWidth = 12;
|
||||
}
|
||||
}
|
||||
uint8_t OLED::getFont() {
|
||||
if (currentFont == USER_FONT_6x8)
|
||||
return 1;
|
||||
else if (currentFont == ExtraFontChars)
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
if (currentFont == USER_FONT_6x8)
|
||||
return 1;
|
||||
else if (currentFont == ExtraFontChars)
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
inline void stripLeaderZeros(char *buffer, uint8_t places) {
|
||||
//Removing the leading zero's by swapping them to SymbolSpace
|
||||
// Stop 1 short so that we dont blank entire number if its zero
|
||||
for (int i = 0; i < (places - 1); i++) {
|
||||
if (buffer[i] == 2) {
|
||||
buffer[i] = SymbolSpace[0];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Removing the leading zero's by swapping them to SymbolSpace
|
||||
// Stop 1 short so that we dont blank entire number if its zero
|
||||
for (int i = 0; i < (places - 1); i++) {
|
||||
if (buffer[i] == 2) {
|
||||
buffer[i] = SymbolSpace[0];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// maximum places is 5
|
||||
void OLED::printNumber(uint16_t number, uint8_t places, bool noLeaderZeros) {
|
||||
char buffer[7] = { 0 };
|
||||
char buffer[7] = {0};
|
||||
|
||||
if (places >= 5) {
|
||||
buffer[5] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places > 4) {
|
||||
buffer[4] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places >= 5) {
|
||||
buffer[5] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places > 4) {
|
||||
buffer[4] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
if (places > 3) {
|
||||
buffer[3] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places > 3) {
|
||||
buffer[3] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
if (places > 2) {
|
||||
buffer[2] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places > 2) {
|
||||
buffer[2] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
if (places > 1) {
|
||||
buffer[1] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
if (places > 1) {
|
||||
buffer[1] = 2 + number % 10;
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
buffer[0] = 2 + number % 10;
|
||||
if (noLeaderZeros)
|
||||
stripLeaderZeros(buffer, places);
|
||||
print(buffer);
|
||||
buffer[0] = 2 + number % 10;
|
||||
if (noLeaderZeros)
|
||||
stripLeaderZeros(buffer, places);
|
||||
print(buffer);
|
||||
}
|
||||
|
||||
void OLED::debugNumber(int32_t val) {
|
||||
if (abs(val) > 99999) {
|
||||
OLED::print(SymbolSpace); // out of bounds
|
||||
return;
|
||||
}
|
||||
if (val >= 0) {
|
||||
OLED::print(SymbolSpace);
|
||||
OLED::printNumber(val, 5);
|
||||
} else {
|
||||
OLED::print(SymbolMinus);
|
||||
OLED::printNumber(-val, 5);
|
||||
}
|
||||
if (abs(val) > 99999) {
|
||||
OLED::print(SymbolSpace); // out of bounds
|
||||
return;
|
||||
}
|
||||
if (val >= 0) {
|
||||
OLED::print(SymbolSpace);
|
||||
OLED::printNumber(val, 5);
|
||||
} else {
|
||||
OLED::print(SymbolMinus);
|
||||
OLED::printNumber(-val, 5);
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::drawSymbol(uint8_t symbolID) {
|
||||
// draw a symbol to the current cursor location
|
||||
setFont(2);
|
||||
drawChar(symbolID + 2);
|
||||
setFont(0);
|
||||
// draw a symbol to the current cursor location
|
||||
setFont(2);
|
||||
drawChar(symbolID + 2);
|
||||
setFont(0);
|
||||
}
|
||||
|
||||
// Draw an area, but y must be aligned on 0/8 offset
|
||||
void OLED::drawArea(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uint8_t *ptr) {
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
firstStripPtr[xx + x] = ptr[xx];
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
secondStripPtr[x + xx] = ptr[xx + (height == 16 ? wide : 0)];
|
||||
}
|
||||
}
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
firstStripPtr[xx + x] = ptr[xx];
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
secondStripPtr[x + xx] = ptr[xx + (height == 16 ? wide : 0)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw an area, but y must be aligned on 0/8 offset
|
||||
// For data which has octets swapped in a 16-bit word.
|
||||
void OLED::drawAreaSwapped(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uint8_t *ptr) {
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
|
||||
firstStripPtr[xx + x] = ptr[xx + 1];
|
||||
firstStripPtr[xx + x + 1] = ptr[xx];
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
|
||||
secondStripPtr[x + xx] = ptr[xx + 1 + (height == 16 ? wide : 0)];
|
||||
secondStripPtr[x + xx + 1] = ptr[xx + (height == 16 ? wide : 0)];
|
||||
}
|
||||
}
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
|
||||
firstStripPtr[xx + x] = ptr[xx + 1];
|
||||
firstStripPtr[xx + x + 1] = ptr[xx];
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
|
||||
secondStripPtr[x + xx] = ptr[xx + 1 + (height == 16 ? wide : 0)];
|
||||
secondStripPtr[x + xx + 1] = ptr[xx + (height == 16 ? wide : 0)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::fillArea(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uint8_t value) {
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
// Splat this from x->x+wide in two strides
|
||||
if (x <= -wide)
|
||||
return; // cutoffleft
|
||||
if (x > 96)
|
||||
return; // cutoff right
|
||||
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
uint8_t visibleStart = 0;
|
||||
uint8_t visibleEnd = wide;
|
||||
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
// trimming to draw partials
|
||||
if (x < 0) {
|
||||
visibleStart -= x; // subtract negative value == add absolute value
|
||||
}
|
||||
if (x + wide > 96) {
|
||||
visibleEnd = 96 - x;
|
||||
}
|
||||
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
firstStripPtr[xx + x] = value;
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
secondStripPtr[x + xx] = value;
|
||||
}
|
||||
}
|
||||
if (y == 0) {
|
||||
// Splat first line of data
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
firstStripPtr[xx + x] = value;
|
||||
}
|
||||
}
|
||||
if (y == 8 || height == 16) {
|
||||
// Splat the second line
|
||||
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
|
||||
secondStripPtr[x + xx] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OLED::drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool clear) {
|
||||
// Draw this in 3 sections
|
||||
// This is basically a N wide version of vertical line
|
||||
// Draw this in 3 sections
|
||||
// This is basically a N wide version of vertical line
|
||||
|
||||
// Step 1 : Draw in the top few pixels that are not /8 aligned
|
||||
// LSB is at the top of the screen
|
||||
uint8_t mask = 0xFF;
|
||||
if (y0) {
|
||||
mask = mask << (y0 % 8);
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
if (clear)
|
||||
firstStripPtr[(y0 / 8) * 96 + col] &= ~mask;
|
||||
else
|
||||
firstStripPtr[(y0 / 8) * 96 + col] |= mask;
|
||||
}
|
||||
// Next loop down the line the total number of solids
|
||||
if (y0 / 8 != y1 / 8)
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
for (uint8_t r = (y0 / 8); r < (y1 / 8); r++) {
|
||||
// This gives us the row index r
|
||||
if (clear)
|
||||
firstStripPtr[(r * 96) + col] = 0;
|
||||
else
|
||||
firstStripPtr[(r * 96) + col] = 0xFF;
|
||||
}
|
||||
// Step 1 : Draw in the top few pixels that are not /8 aligned
|
||||
// LSB is at the top of the screen
|
||||
uint8_t mask = 0xFF;
|
||||
if (y0) {
|
||||
mask = mask << (y0 % 8);
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
if (clear)
|
||||
firstStripPtr[(y0 / 8) * 96 + col] &= ~mask;
|
||||
else
|
||||
firstStripPtr[(y0 / 8) * 96 + col] |= mask;
|
||||
}
|
||||
// Next loop down the line the total number of solids
|
||||
if (y0 / 8 != y1 / 8)
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
for (uint8_t r = (y0 / 8); r < (y1 / 8); r++) {
|
||||
// This gives us the row index r
|
||||
if (clear)
|
||||
firstStripPtr[(r * 96) + col] = 0;
|
||||
else
|
||||
firstStripPtr[(r * 96) + col] = 0xFF;
|
||||
}
|
||||
|
||||
// Finally draw the tail
|
||||
mask = ~(mask << (y1 % 8));
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
if (clear)
|
||||
firstStripPtr[(y1 / 8) * 96 + col] &= ~mask;
|
||||
else
|
||||
firstStripPtr[(y1 / 8) * 96 + col] |= mask;
|
||||
// Finally draw the tail
|
||||
mask = ~(mask << (y1 % 8));
|
||||
for (uint8_t col = x0; col < x1; col++)
|
||||
if (clear)
|
||||
firstStripPtr[(y1 / 8) * 96 + col] &= ~mask;
|
||||
else
|
||||
firstStripPtr[(y1 / 8) * 96 + col] |= mask;
|
||||
}
|
||||
|
||||
void OLED::drawHeatSymbol(uint8_t state) {
|
||||
// Draw symbol 14
|
||||
// Then draw over it, the bottom 5 pixels always stay. 8 pixels above that are
|
||||
// the levels masks the symbol nicely
|
||||
state /= 31; // 0-> 8 range
|
||||
// Then we want to draw down (16-(5+state)
|
||||
uint8_t cursor_x_temp = cursor_x;
|
||||
drawSymbol(14);
|
||||
drawFilledRect(cursor_x_temp, 0, cursor_x_temp + 12, 2 + (8 - state), true);
|
||||
// Draw symbol 14
|
||||
// Then draw over it, the bottom 5 pixels always stay. 8 pixels above that are
|
||||
// the levels masks the symbol nicely
|
||||
state /= 31; // 0-> 8 range
|
||||
// Then we want to draw down (16-(5+state)
|
||||
uint8_t cursor_x_temp = cursor_x;
|
||||
drawSymbol(14);
|
||||
drawFilledRect(cursor_x_temp, 0, cursor_x_temp + 12, 2 + (8 - state), true);
|
||||
}
|
||||
|
||||
bool OLED::isInitDone() {
|
||||
return initDone;
|
||||
}
|
||||
bool OLED::isInitDone() { return initDone; }
|
||||
|
||||
@@ -10,60 +10,59 @@
|
||||
#include <array>
|
||||
|
||||
bool SC7A20::detect() {
|
||||
if (FRToSI2C::probe(SC7A20_ADDRESS)) {
|
||||
//Read chip id to ensure its not an address collision
|
||||
uint8_t id = 0;
|
||||
if (FRToSI2C::Mem_Read(SC7A20_ADDRESS, SC7A20_WHO_AMI_I, &id, 1)) {
|
||||
return id == 0b00010001;
|
||||
}
|
||||
}
|
||||
if (FRToSI2C::probe(SC7A20_ADDRESS)) {
|
||||
// Read chip id to ensure its not an address collision
|
||||
uint8_t id = 0;
|
||||
if (FRToSI2C::Mem_Read(SC7A20_ADDRESS, SC7A20_WHO_AMI_I, &id, 1)) {
|
||||
return id == 0b00010001;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = { //
|
||||
//
|
||||
{ SC7A20_CTRL_REG1, 0b01100111, 0 }, //200Hz, XYZ enabled
|
||||
{ SC7A20_CTRL_REG2, 0b00000000, 0 }, //Setup filter to 0x00 ??
|
||||
{ SC7A20_CTRL_REG3, 0b00000000, 0 }, //int1 off
|
||||
{ SC7A20_CTRL_REG4, 0b01001000, 0 }, //Block mode off,little-endian,2G,High-pres,self test off
|
||||
{ SC7A20_CTRL_REG5, 0b00000100, 0 }, //fifo off, D4D on int1
|
||||
{ SC7A20_CTRL_REG6, 0x00, 0 }, //INT2 off
|
||||
//Basically setup the unit to run, and enable 4D orientation detection
|
||||
{ SC7A20_INT2_CFG, 0b01111110, 0 }, //setup for movement detection
|
||||
{ SC7A20_INT2_THS, 0x28, 0 }, //
|
||||
{ SC7A20_INT2_DURATION, 64, 0 }, //
|
||||
{ SC7A20_INT1_CFG, 0b01111110, 0 }, //
|
||||
{ SC7A20_INT1_THS, 0x28, 0 }, //
|
||||
{ SC7A20_INT1_DURATION, 64, 0 }
|
||||
static const FRToSI2C::I2C_REG i2c_registers[] = {
|
||||
//
|
||||
//
|
||||
{SC7A20_CTRL_REG1, 0b01100111, 0}, // 200Hz, XYZ enabled
|
||||
{SC7A20_CTRL_REG2, 0b00000000, 0}, // Setup filter to 0x00 ??
|
||||
{SC7A20_CTRL_REG3, 0b00000000, 0}, // int1 off
|
||||
{SC7A20_CTRL_REG4, 0b01001000, 0}, // Block mode off,little-endian,2G,High-pres,self test off
|
||||
{SC7A20_CTRL_REG5, 0b00000100, 0}, // fifo off, D4D on int1
|
||||
{SC7A20_CTRL_REG6, 0x00, 0}, // INT2 off
|
||||
// Basically setup the unit to run, and enable 4D orientation detection
|
||||
{SC7A20_INT2_CFG, 0b01111110, 0}, // setup for movement detection
|
||||
{SC7A20_INT2_THS, 0x28, 0}, //
|
||||
{SC7A20_INT2_DURATION, 64, 0}, //
|
||||
{SC7A20_INT1_CFG, 0b01111110, 0}, //
|
||||
{SC7A20_INT1_THS, 0x28, 0}, //
|
||||
{SC7A20_INT1_DURATION, 64, 0}
|
||||
|
||||
//
|
||||
};
|
||||
//
|
||||
};
|
||||
bool SC7A20::initalize() {
|
||||
//Setup acceleration readings
|
||||
//2G range
|
||||
//bandwidth = 250Hz
|
||||
//High pass filter on (Slow compensation)
|
||||
//Turn off IRQ output pins
|
||||
//Orientation recognition in symmetrical mode
|
||||
// Hysteresis is set to ~ 16 counts
|
||||
//Theta blocking is set to 0b10
|
||||
|
||||
return FRToSI2C::writeRegistersBulk(SC7A20_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
// Setup acceleration readings
|
||||
// 2G range
|
||||
// bandwidth = 250Hz
|
||||
// High pass filter on (Slow compensation)
|
||||
// Turn off IRQ output pins
|
||||
// Orientation recognition in symmetrical mode
|
||||
// Hysteresis is set to ~ 16 counts
|
||||
// Theta blocking is set to 0b10
|
||||
|
||||
return FRToSI2C::writeRegistersBulk(SC7A20_ADDRESS, i2c_registers, sizeof(i2c_registers) / sizeof(i2c_registers[0]));
|
||||
}
|
||||
|
||||
void SC7A20::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
|
||||
//We can tell the accelerometer to output in LE mode which makes this simple
|
||||
uint16_t sensorData[3] = { 0, 0, 0 };
|
||||
|
||||
if (FRToSI2C::Mem_Read(SC7A20_ADDRESS, SC7A20_OUT_X_L, (uint8_t*) sensorData, 6) == false) {
|
||||
x = y = z = 0;
|
||||
return;
|
||||
}
|
||||
//Shift 6 to make its range ~= the other accelerometers
|
||||
x = sensorData[0];
|
||||
y = sensorData[1];
|
||||
z = sensorData[2];
|
||||
// We can tell the accelerometer to output in LE mode which makes this simple
|
||||
uint16_t sensorData[3] = {0, 0, 0};
|
||||
|
||||
if (FRToSI2C::Mem_Read(SC7A20_ADDRESS, SC7A20_OUT_X_L, (uint8_t *)sensorData, 6) == false) {
|
||||
x = y = z = 0;
|
||||
return;
|
||||
}
|
||||
// Shift 6 to make its range ~= the other accelerometers
|
||||
x = sensorData[0];
|
||||
y = sensorData[1];
|
||||
z = sensorData[2];
|
||||
}
|
||||
|
||||
@@ -10,175 +10,168 @@
|
||||
* This class is licensed as MIT to match this code base
|
||||
*/
|
||||
|
||||
#include <Si7210.h>
|
||||
#include "Si7210_defines.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
bool Si7210::detect() {
|
||||
return FRToSI2C::wakePart(SI7210_ADDRESS);
|
||||
|
||||
}
|
||||
#include "Si7210_defines.h"
|
||||
#include <Si7210.h>
|
||||
bool Si7210::detect() { return FRToSI2C::wakePart(SI7210_ADDRESS); }
|
||||
|
||||
bool Si7210::init() {
|
||||
//Turn on auto increment and sanity check ID
|
||||
//Load OTP cal
|
||||
// Turn on auto increment and sanity check ID
|
||||
// Load OTP cal
|
||||
|
||||
uint8_t temp;
|
||||
if (FRToSI2C::Mem_Read(SI7210_ADDRESS, SI7210_REG_ID, &temp, 1)) {
|
||||
// We don't really care what model it is etc, just probing to check its probably this iC
|
||||
if (temp != 0x00 && temp != 0xFF) {
|
||||
temp = 0x00;
|
||||
uint8_t temp;
|
||||
if (FRToSI2C::Mem_Read(SI7210_ADDRESS, SI7210_REG_ID, &temp, 1)) {
|
||||
// We don't really care what model it is etc, just probing to check its probably this iC
|
||||
if (temp != 0x00 && temp != 0xFF) {
|
||||
temp = 0x00;
|
||||
|
||||
/* Set device and internal driver settings */
|
||||
if (!write_reg( SI7210_CTRL1, (uint8_t) ~SW_LOW4FIELD_MASK, 0)) {
|
||||
return false;
|
||||
}
|
||||
/* Set device and internal driver settings */
|
||||
if (!write_reg(SI7210_CTRL1, (uint8_t)~SW_LOW4FIELD_MASK, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Disable periodic auto-wakeup by device, and tamper detect. */
|
||||
if ((!write_reg(SI7210_CTRL3, (uint8_t) ~SL_TIMEENA_MASK, 0)))
|
||||
return false;
|
||||
/* Disable periodic auto-wakeup by device, and tamper detect. */
|
||||
if ((!write_reg(SI7210_CTRL3, (uint8_t)~SL_TIMEENA_MASK, 0)))
|
||||
return false;
|
||||
|
||||
/* Disable tamper detection by setting sw_tamper to 63 */
|
||||
if (!write_reg(SI7210_CTRL3, SL_FAST_MASK | SL_TIMEENA_MASK, 63 << 2))
|
||||
return false;
|
||||
/* Disable tamper detection by setting sw_tamper to 63 */
|
||||
if (!write_reg(SI7210_CTRL3, SL_FAST_MASK | SL_TIMEENA_MASK, 63 << 2))
|
||||
return false;
|
||||
|
||||
if (!set_high_range())
|
||||
return false;
|
||||
if (!set_high_range())
|
||||
return false;
|
||||
|
||||
/* Stop the control loop by setting stop bit */
|
||||
if (!write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK)) /* WARNING: Removed USE_STORE MASK */
|
||||
return false;
|
||||
/* Stop the control loop by setting stop bit */
|
||||
if (!write_reg(SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK)) /* WARNING: Removed USE_STORE MASK */
|
||||
return false;
|
||||
|
||||
/* Use a burst size of 128/4096 samples in FIR and IIR modes */
|
||||
if (!write_reg(SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096))
|
||||
return false;
|
||||
/* Use a burst size of 128/4096 samples in FIR and IIR modes */
|
||||
if (!write_reg(SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096))
|
||||
return false;
|
||||
|
||||
/* Select field strength measurement */
|
||||
if (!write_reg( SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK))
|
||||
return false;
|
||||
/* Select field strength measurement */
|
||||
if (!write_reg(SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK))
|
||||
return false;
|
||||
|
||||
return true; //start_periodic_measurement();
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true; // start_periodic_measurement();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t Si7210::read() {
|
||||
//Read the two regs
|
||||
int16_t temp = 0;
|
||||
if (!get_field_strength(&temp)) {
|
||||
temp = 0;
|
||||
}
|
||||
return temp;
|
||||
// Read the two regs
|
||||
int16_t temp = 0;
|
||||
if (!get_field_strength(&temp)) {
|
||||
temp = 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool Si7210::write_reg(const uint8_t reg, const uint8_t mask, const uint8_t val) {
|
||||
uint8_t temp = 0;
|
||||
if (mask) {
|
||||
if (!read_reg(reg, &temp)) {
|
||||
return false;
|
||||
}
|
||||
temp &= mask;
|
||||
}
|
||||
temp |= val;
|
||||
return FRToSI2C::Mem_Write(SI7210_ADDRESS, reg, &temp, 1);
|
||||
uint8_t temp = 0;
|
||||
if (mask) {
|
||||
if (!read_reg(reg, &temp)) {
|
||||
return false;
|
||||
}
|
||||
temp &= mask;
|
||||
}
|
||||
temp |= val;
|
||||
return FRToSI2C::Mem_Write(SI7210_ADDRESS, reg, &temp, 1);
|
||||
}
|
||||
|
||||
bool Si7210::read_reg(const uint8_t reg, uint8_t* val) {
|
||||
return FRToSI2C::Mem_Read(SI7210_ADDRESS, reg, val, 1);
|
||||
}
|
||||
bool Si7210::read_reg(const uint8_t reg, uint8_t *val) { return FRToSI2C::Mem_Read(SI7210_ADDRESS, reg, val, 1); }
|
||||
|
||||
bool Si7210::start_periodic_measurement() {
|
||||
/* Enable periodic wakeup */
|
||||
if (!write_reg(SI7210_CTRL3, (uint8_t) ~SL_TIMEENA_MASK, SL_TIMEENA_MASK))
|
||||
return false;
|
||||
|
||||
/* Start measurement */
|
||||
/* Change to ~STOP_MASK with STOP_MASK */
|
||||
return write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, 0);
|
||||
/* Enable periodic wakeup */
|
||||
if (!write_reg(SI7210_CTRL3, (uint8_t)~SL_TIMEENA_MASK, SL_TIMEENA_MASK))
|
||||
return false;
|
||||
|
||||
/* Start measurement */
|
||||
/* Change to ~STOP_MASK with STOP_MASK */
|
||||
return write_reg(SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, 0);
|
||||
}
|
||||
|
||||
bool Si7210::get_field_strength(int16_t* field) {
|
||||
*field = 0;
|
||||
uint8_t val = 0;
|
||||
FRToSI2C::wakePart(SI7210_ADDRESS);
|
||||
bool Si7210::get_field_strength(int16_t *field) {
|
||||
*field = 0;
|
||||
uint8_t val = 0;
|
||||
FRToSI2C::wakePart(SI7210_ADDRESS);
|
||||
|
||||
if (!write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK))
|
||||
return false;
|
||||
if (!write_reg(SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, STOP_MASK))
|
||||
return false;
|
||||
|
||||
/* Read most-significant byte */
|
||||
if (!read_reg( SI7210_DSPSIGM, &val))
|
||||
return false;
|
||||
*field = (val & DSP_SIGM_DATA_MASK) << 8;
|
||||
/* Read most-significant byte */
|
||||
if (!read_reg(SI7210_DSPSIGM, &val))
|
||||
return false;
|
||||
*field = (val & DSP_SIGM_DATA_MASK) << 8;
|
||||
|
||||
/* Read least-significant byte of data */
|
||||
if (!read_reg( SI7210_DSPSIGL, &val))
|
||||
return false;
|
||||
/* Read least-significant byte of data */
|
||||
if (!read_reg(SI7210_DSPSIGL, &val))
|
||||
return false;
|
||||
|
||||
*field += val;
|
||||
*field -= 16384U;
|
||||
//field is now a +- measurement
|
||||
//In units of 0.0125 mT
|
||||
// Aka 12.5uT
|
||||
//Clear flags
|
||||
read_reg( SI7210_CTRL1, &val);
|
||||
read_reg( SI7210_CTRL2, &val);
|
||||
//Start next one
|
||||
*field += val;
|
||||
*field -= 16384U;
|
||||
// field is now a +- measurement
|
||||
// In units of 0.0125 mT
|
||||
// Aka 12.5uT
|
||||
// Clear flags
|
||||
read_reg(SI7210_CTRL1, &val);
|
||||
read_reg(SI7210_CTRL2, &val);
|
||||
// Start next one
|
||||
|
||||
/* Use a burst size of 128/4096 samples in FIR and IIR modes */
|
||||
write_reg( SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096);
|
||||
/* Use a burst size of 128/4096 samples in FIR and IIR modes */
|
||||
write_reg(SI7210_CTRL4, 0, DF_BURSTSIZE_128 | DF_BW_4096);
|
||||
|
||||
/* Selet field strength measurement */
|
||||
write_reg( SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK);
|
||||
/* Selet field strength measurement */
|
||||
write_reg(SI7210_DSPSIGSEL, 0, DSP_SIGSEL_FIELD_MASK);
|
||||
|
||||
/* Start measurement */
|
||||
write_reg( SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, ONEBURST_MASK);
|
||||
/* Start measurement */
|
||||
write_reg(SI7210_POWER_CTRL, MEAS_MASK | USESTORE_MASK, ONEBURST_MASK);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Si7210::set_high_range() {
|
||||
//To set the unit into 200mT range, no magnet temperature calibration
|
||||
// We want to copy OTP 0x27->0x2C into a0->a5
|
||||
uint8_t base_addr = 0x27; // You can change this to pick the temp calibration
|
||||
bool worked = true;
|
||||
uint8_t val = 0;
|
||||
// To set the unit into 200mT range, no magnet temperature calibration
|
||||
// We want to copy OTP 0x27->0x2C into a0->a5
|
||||
uint8_t base_addr = 0x27; // You can change this to pick the temp calibration
|
||||
bool worked = true;
|
||||
uint8_t val = 0;
|
||||
|
||||
/* Load A0 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A0, 0, val);
|
||||
/* Load A0 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A0, 0, val);
|
||||
|
||||
/* Load A1 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 1);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A1, 0, val);
|
||||
/* Load A1 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr + 1);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A1, 0, val);
|
||||
|
||||
/* Load A2 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 2);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A2, 0, val);
|
||||
/* Load A2 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr + 2);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A2, 0, val);
|
||||
|
||||
/* Load A3 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 3);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A3, 0, val);
|
||||
/* Load A3 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr + 3);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A3, 0, val);
|
||||
|
||||
/* Load A4 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 4);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A4, 0, val);
|
||||
/* Load A4 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr + 4);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A4, 0, val);
|
||||
|
||||
/* Load A5 register */
|
||||
worked &= write_reg( SI7210_OTP_ADDR, 0, base_addr + 5);
|
||||
worked &= write_reg( SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg( SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg( SI7210_A5, 0, val);
|
||||
return worked;
|
||||
/* Load A5 register */
|
||||
worked &= write_reg(SI7210_OTP_ADDR, 0, base_addr + 5);
|
||||
worked &= write_reg(SI7210_OTP_CTRL, 0, OTP_READ_EN_MASK);
|
||||
worked &= read_reg(SI7210_OTP_DATA, &val);
|
||||
worked &= write_reg(SI7210_A5, 0, val);
|
||||
return worked;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "TipThermoModel.h"
|
||||
#include "Settings.h"
|
||||
#include "BSP.h"
|
||||
#include "power.hpp"
|
||||
#include "../../configuration.h"
|
||||
#include "BSP.h"
|
||||
#include "Settings.h"
|
||||
#include "main.hpp"
|
||||
#include "power.hpp"
|
||||
/*
|
||||
* The hardware is laid out as a non-inverting op-amp
|
||||
* There is a pullup of 39k(TS100) from the +ve input to 3.9V (1M pulup on TS100)
|
||||
@@ -29,217 +29,211 @@
|
||||
*/
|
||||
|
||||
uint32_t TipThermoModel::convertTipRawADCTouV(uint16_t rawADC) {
|
||||
// This takes the raw ADC samples, converts these to uV
|
||||
// Then divides this down by the gain to convert to the uV on the input to the op-amp (A+B terminals)
|
||||
// Then remove the calibration value that is stored as a tip offset
|
||||
uint32_t vddRailmVX10 = 33000; //The vreg is +-2%, but we have no higher accuracy available
|
||||
// 4096 * 8 readings for full scale
|
||||
// Convert the input ADC reading back into mV times 10 format.
|
||||
uint32_t rawInputmVX10 = (rawADC * vddRailmVX10) / (4096 * 8);
|
||||
// This takes the raw ADC samples, converts these to uV
|
||||
// Then divides this down by the gain to convert to the uV on the input to the op-amp (A+B terminals)
|
||||
// Then remove the calibration value that is stored as a tip offset
|
||||
uint32_t vddRailmVX10 = 33000; // The vreg is +-2%, but we have no higher accuracy available
|
||||
// 4096 * 8 readings for full scale
|
||||
// Convert the input ADC reading back into mV times 10 format.
|
||||
uint32_t rawInputmVX10 = (rawADC * vddRailmVX10) / (4096 * 8);
|
||||
|
||||
uint32_t valueuV = rawInputmVX10 * 100; // shift into uV
|
||||
//Now to divide this down by the gain
|
||||
valueuV /= OP_AMP_GAIN_STAGE;
|
||||
uint32_t valueuV = rawInputmVX10 * 100; // shift into uV
|
||||
// Now to divide this down by the gain
|
||||
valueuV /= OP_AMP_GAIN_STAGE;
|
||||
|
||||
if (systemSettings.CalibrationOffset) {
|
||||
//Remove uV tipOffset
|
||||
if (valueuV >= systemSettings.CalibrationOffset)
|
||||
valueuV -= systemSettings.CalibrationOffset;
|
||||
else
|
||||
valueuV = 0;
|
||||
}
|
||||
if (systemSettings.CalibrationOffset) {
|
||||
// Remove uV tipOffset
|
||||
if (valueuV >= systemSettings.CalibrationOffset)
|
||||
valueuV -= systemSettings.CalibrationOffset;
|
||||
else
|
||||
valueuV = 0;
|
||||
}
|
||||
|
||||
return valueuV;
|
||||
return valueuV;
|
||||
}
|
||||
|
||||
uint32_t TipThermoModel::convertTipRawADCToDegC(uint16_t rawADC) {
|
||||
return convertuVToDegC(convertTipRawADCTouV(rawADC));
|
||||
}
|
||||
uint32_t TipThermoModel::convertTipRawADCToDegC(uint16_t rawADC) { return convertuVToDegC(convertTipRawADCTouV(rawADC)); }
|
||||
#ifdef ENABLED_FAHRENHEIT_SUPPORT
|
||||
uint32_t TipThermoModel::convertTipRawADCToDegF(uint16_t rawADC) {
|
||||
return convertuVToDegF(convertTipRawADCTouV(rawADC));
|
||||
}
|
||||
uint32_t TipThermoModel::convertTipRawADCToDegF(uint16_t rawADC) { return convertuVToDegF(convertTipRawADCTouV(rawADC)); }
|
||||
#endif
|
||||
|
||||
//Table that is designed to be walked to find the best sample for the lookup
|
||||
// Table that is designed to be walked to find the best sample for the lookup
|
||||
|
||||
//Extrapolate between two points
|
||||
// Extrapolate between two points
|
||||
// [x1, y1] = point 1
|
||||
// [x2, y2] = point 2
|
||||
// x = input value
|
||||
// output is x's interpolated y value
|
||||
int32_t LinearInterpolate(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x) {
|
||||
return y1 + (((((x - x1) * 1000) / (x2 - x1)) * (y2 - y1))) / 1000;
|
||||
}
|
||||
int32_t LinearInterpolate(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x) { return y1 + (((((x - x1) * 1000) / (x2 - x1)) * (y2 - y1))) / 1000; }
|
||||
#ifdef TEMP_uV_LOOKUP_HAKKO
|
||||
const uint16_t uVtoDegC[] = { //
|
||||
//
|
||||
0, 0, //
|
||||
266, 10, //
|
||||
522, 20, //
|
||||
770, 30, //
|
||||
1010, 40, //
|
||||
1244, 50, //
|
||||
1473, 60, //
|
||||
1697, 70, //
|
||||
1917, 80, //
|
||||
2135, 90, //
|
||||
2351, 100, //
|
||||
2566, 110, //
|
||||
2780, 120, //
|
||||
2994, 130, //
|
||||
3209, 140, //
|
||||
3426, 150, //
|
||||
3644, 160, //
|
||||
3865, 170, //
|
||||
4088, 180, //
|
||||
4314, 190, //
|
||||
4544, 200, //
|
||||
4777, 210, //
|
||||
5014, 220, //
|
||||
5255, 230, //
|
||||
5500, 240, //
|
||||
5750, 250, //
|
||||
6003, 260, //
|
||||
6261, 270, //
|
||||
6523, 280, //
|
||||
6789, 290, //
|
||||
7059, 300, //
|
||||
7332, 310, //
|
||||
7609, 320, //
|
||||
7889, 330, //
|
||||
8171, 340, //
|
||||
8456, 350, //
|
||||
8742, 360, //
|
||||
9030, 370, //
|
||||
9319, 380, //
|
||||
9607, 390, //
|
||||
9896, 400, //
|
||||
10183, 410, //
|
||||
10468, 420, //
|
||||
10750, 430, //
|
||||
11029, 440, //
|
||||
11304, 450, //
|
||||
11573, 460, //
|
||||
11835, 470, //
|
||||
12091, 480, //
|
||||
12337, 490, //
|
||||
12575, 500, //
|
||||
const uint16_t uVtoDegC[] = {
|
||||
//
|
||||
//
|
||||
0, 0, //
|
||||
266, 10, //
|
||||
522, 20, //
|
||||
770, 30, //
|
||||
1010, 40, //
|
||||
1244, 50, //
|
||||
1473, 60, //
|
||||
1697, 70, //
|
||||
1917, 80, //
|
||||
2135, 90, //
|
||||
2351, 100, //
|
||||
2566, 110, //
|
||||
2780, 120, //
|
||||
2994, 130, //
|
||||
3209, 140, //
|
||||
3426, 150, //
|
||||
3644, 160, //
|
||||
3865, 170, //
|
||||
4088, 180, //
|
||||
4314, 190, //
|
||||
4544, 200, //
|
||||
4777, 210, //
|
||||
5014, 220, //
|
||||
5255, 230, //
|
||||
5500, 240, //
|
||||
5750, 250, //
|
||||
6003, 260, //
|
||||
6261, 270, //
|
||||
6523, 280, //
|
||||
6789, 290, //
|
||||
7059, 300, //
|
||||
7332, 310, //
|
||||
7609, 320, //
|
||||
7889, 330, //
|
||||
8171, 340, //
|
||||
8456, 350, //
|
||||
8742, 360, //
|
||||
9030, 370, //
|
||||
9319, 380, //
|
||||
9607, 390, //
|
||||
9896, 400, //
|
||||
10183, 410, //
|
||||
10468, 420, //
|
||||
10750, 430, //
|
||||
11029, 440, //
|
||||
11304, 450, //
|
||||
11573, 460, //
|
||||
11835, 470, //
|
||||
12091, 480, //
|
||||
12337, 490, //
|
||||
12575, 500, //
|
||||
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_uV_LOOKUP_TS80
|
||||
|
||||
const uint16_t uVtoDegC[] = { //
|
||||
//
|
||||
530 , 0, //
|
||||
1282 , 10, //
|
||||
2034 , 20, //
|
||||
2786 , 30, //
|
||||
3538 , 40, //
|
||||
4290 , 50, //
|
||||
5043 , 60, //
|
||||
5795 , 70, //
|
||||
6547 , 80, //
|
||||
7299 , 90, //
|
||||
8051 , 100, //
|
||||
8803 , 110, //
|
||||
9555 , 120, //
|
||||
10308 , 130, //
|
||||
11060 , 140, //
|
||||
11812 , 150, //
|
||||
12564 , 160, //
|
||||
13316 , 170, //
|
||||
14068 , 180, //
|
||||
14820 , 190, //
|
||||
15573 , 200, //
|
||||
16325 , 210, //
|
||||
17077 , 220, //
|
||||
17829 , 230, //
|
||||
18581 , 240, //
|
||||
19333 , 250, //
|
||||
20085 , 260, //
|
||||
20838 , 270, //
|
||||
21590 , 280, //
|
||||
22342 , 290, //
|
||||
23094 , 300, //
|
||||
23846 , 310, //
|
||||
24598 , 320, //
|
||||
25350 , 330, //
|
||||
26103 , 340, //
|
||||
26855 , 350, //
|
||||
27607 , 360, //
|
||||
28359 , 370, //
|
||||
29111 , 380, //
|
||||
29863 , 390, //
|
||||
30615 , 400, //
|
||||
31368 , 410, //
|
||||
32120 , 420, //
|
||||
32872 , 430, //
|
||||
33624 , 440, //
|
||||
34376 , 450, //
|
||||
35128 , 460, //
|
||||
35880 , 470, //
|
||||
36632 , 480, //
|
||||
37385 , 490, //
|
||||
38137 , 500, //
|
||||
};
|
||||
const uint16_t uVtoDegC[] = {
|
||||
//
|
||||
//
|
||||
530, 0, //
|
||||
1282, 10, //
|
||||
2034, 20, //
|
||||
2786, 30, //
|
||||
3538, 40, //
|
||||
4290, 50, //
|
||||
5043, 60, //
|
||||
5795, 70, //
|
||||
6547, 80, //
|
||||
7299, 90, //
|
||||
8051, 100, //
|
||||
8803, 110, //
|
||||
9555, 120, //
|
||||
10308, 130, //
|
||||
11060, 140, //
|
||||
11812, 150, //
|
||||
12564, 160, //
|
||||
13316, 170, //
|
||||
14068, 180, //
|
||||
14820, 190, //
|
||||
15573, 200, //
|
||||
16325, 210, //
|
||||
17077, 220, //
|
||||
17829, 230, //
|
||||
18581, 240, //
|
||||
19333, 250, //
|
||||
20085, 260, //
|
||||
20838, 270, //
|
||||
21590, 280, //
|
||||
22342, 290, //
|
||||
23094, 300, //
|
||||
23846, 310, //
|
||||
24598, 320, //
|
||||
25350, 330, //
|
||||
26103, 340, //
|
||||
26855, 350, //
|
||||
27607, 360, //
|
||||
28359, 370, //
|
||||
29111, 380, //
|
||||
29863, 390, //
|
||||
30615, 400, //
|
||||
31368, 410, //
|
||||
32120, 420, //
|
||||
32872, 430, //
|
||||
33624, 440, //
|
||||
34376, 450, //
|
||||
35128, 460, //
|
||||
35880, 470, //
|
||||
36632, 480, //
|
||||
37385, 490, //
|
||||
38137, 500, //
|
||||
};
|
||||
#endif
|
||||
uint32_t TipThermoModel::convertuVToDegC(uint32_t tipuVDelta) {
|
||||
if (tipuVDelta) {
|
||||
int noItems = sizeof(uVtoDegC) / (2 * sizeof(uint16_t));
|
||||
for (int i = 1; i < (noItems - 1); i++) {
|
||||
//If current tip temp is less than current lookup, then this current lookup is the higher point to interpolate
|
||||
if (tipuVDelta < uVtoDegC[i * 2]) {
|
||||
return LinearInterpolate(uVtoDegC[(i - 1) * 2], uVtoDegC[((i - 1) * 2) + 1], uVtoDegC[i * 2], uVtoDegC[(i * 2) + 1], tipuVDelta);
|
||||
}
|
||||
}
|
||||
return LinearInterpolate(uVtoDegC[(noItems - 2) * 2], uVtoDegC[((noItems - 2) * 2) + 1], uVtoDegC[(noItems - 1) * 2], uVtoDegC[((noItems - 1) * 2) + 1], tipuVDelta);
|
||||
}
|
||||
return 0;
|
||||
if (tipuVDelta) {
|
||||
int noItems = sizeof(uVtoDegC) / (2 * sizeof(uint16_t));
|
||||
for (int i = 1; i < (noItems - 1); i++) {
|
||||
// If current tip temp is less than current lookup, then this current lookup is the higher point to interpolate
|
||||
if (tipuVDelta < uVtoDegC[i * 2]) {
|
||||
return LinearInterpolate(uVtoDegC[(i - 1) * 2], uVtoDegC[((i - 1) * 2) + 1], uVtoDegC[i * 2], uVtoDegC[(i * 2) + 1], tipuVDelta);
|
||||
}
|
||||
}
|
||||
return LinearInterpolate(uVtoDegC[(noItems - 2) * 2], uVtoDegC[((noItems - 2) * 2) + 1], uVtoDegC[(noItems - 1) * 2], uVtoDegC[((noItems - 1) * 2) + 1], tipuVDelta);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLED_FAHRENHEIT_SUPPORT
|
||||
uint32_t TipThermoModel::convertuVToDegF(uint32_t tipuVDelta) {
|
||||
return convertCtoF(convertuVToDegC(tipuVDelta));
|
||||
}
|
||||
uint32_t TipThermoModel::convertuVToDegF(uint32_t tipuVDelta) { return convertCtoF(convertuVToDegC(tipuVDelta)); }
|
||||
|
||||
uint32_t TipThermoModel::convertCtoF(uint32_t degC) {
|
||||
//(Y °C × 9/5) + 32 =Y°F
|
||||
return (32 + ((degC * 9) / 5));
|
||||
//(Y °C × 9/5) + 32 =Y°F
|
||||
return (32 + ((degC * 9) / 5));
|
||||
}
|
||||
|
||||
uint32_t TipThermoModel::convertFtoC(uint32_t degF) {
|
||||
//(Y°F − 32) × 5/9 = Y°C
|
||||
if (degF < 32) {
|
||||
return 0;
|
||||
}
|
||||
return ((degF - 32) * 5) / 9;
|
||||
//(Y°F − 32) × 5/9 = Y°C
|
||||
if (degF < 32) {
|
||||
return 0;
|
||||
}
|
||||
return ((degF - 32) * 5) / 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t TipThermoModel::getTipInC(bool sampleNow) {
|
||||
int32_t currentTipTempInC = TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(sampleNow));
|
||||
currentTipTempInC += getHandleTemperature() / 10; //Add handle offset
|
||||
// Power usage indicates that our tip temp is lower than our thermocouple temp.
|
||||
// I found a number that doesn't unbalance the existing PID, causing overshoot.
|
||||
// This could be tuned in concert with PID parameters...
|
||||
currentTipTempInC -= x10WattHistory.average() / 25;
|
||||
if (currentTipTempInC < 0)
|
||||
return 0;
|
||||
return currentTipTempInC;
|
||||
int32_t currentTipTempInC = TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(sampleNow));
|
||||
currentTipTempInC += getHandleTemperature() / 10; // Add handle offset
|
||||
// Power usage indicates that our tip temp is lower than our thermocouple temp.
|
||||
// I found a number that doesn't unbalance the existing PID, causing overshoot.
|
||||
// This could be tuned in concert with PID parameters...
|
||||
currentTipTempInC -= x10WattHistory.average() / 25;
|
||||
if (currentTipTempInC < 0)
|
||||
return 0;
|
||||
return currentTipTempInC;
|
||||
}
|
||||
#ifdef ENABLED_FAHRENHEIT_SUPPORT
|
||||
uint32_t TipThermoModel::getTipInF(bool sampleNow) {
|
||||
uint32_t currentTipTempInF = getTipInC(sampleNow);
|
||||
currentTipTempInF = convertCtoF(currentTipTempInF);
|
||||
return currentTipTempInF;
|
||||
uint32_t currentTipTempInF = getTipInC(sampleNow);
|
||||
currentTipTempInF = convertCtoF(currentTipTempInF);
|
||||
return currentTipTempInF;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t TipThermoModel::getTipMaxInC() {
|
||||
uint32_t maximumTipTemp = TipThermoModel::convertTipRawADCToDegC(0x7FFF - (21 * 5)); //back off approx 5 deg c from ADC max
|
||||
maximumTipTemp += getHandleTemperature() / 10; //Add handle offset
|
||||
return maximumTipTemp - 1;
|
||||
uint32_t maximumTipTemp = TipThermoModel::convertTipRawADCToDegC(0x7FFF - (21 * 5)); // back off approx 5 deg c from ADC max
|
||||
maximumTipTemp += getHandleTemperature() / 10; // Add handle offset
|
||||
return maximumTipTemp - 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user