Merge pull request #917 from Ralim/messing_with_pd
Improvements and restructure to USB-PD
This commit is contained in:
@@ -8,9 +8,6 @@
|
||||
#ifndef USER_BSP_PD_H_
|
||||
#define USER_BSP_PD_H_
|
||||
#include "BSP.h"
|
||||
/*
|
||||
* An array of all of the desired voltages & minimum currents in preferred order
|
||||
*/
|
||||
extern const uint16_t USB_PD_Desired_Levels[];
|
||||
extern const uint8_t USB_PD_Desired_Levels_Len;
|
||||
bool getFUS302IRQLow(); // Return true if the IRQ line is still held low
|
||||
|
||||
#endif /* USER_BSP_PD_H_ */
|
||||
|
||||
@@ -15,4 +15,5 @@ enum Orientation { ORIENTATION_LEFT_HAND = 0, ORIENTATION_RIGHT_HAND = 1, ORIENT
|
||||
#define TICKS_SECOND configTICK_RATE_HZ
|
||||
#define TICKS_MIN (60 * TICKS_SECOND)
|
||||
#define TICKS_100MS (TICKS_SECOND / 10)
|
||||
#define TICKS_10MS (TICKS_100MS / 10)
|
||||
#endif /* BSP_DEFINES_H_ */
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* BSP_PD.c
|
||||
*
|
||||
* Created on: 21 Jul 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#include "BSP_PD.h"
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
/*
|
||||
* An array of all of the desired voltages & minimum currents in preferred order
|
||||
*/
|
||||
const uint16_t USB_PD_Desired_Levels[] = {
|
||||
// mV desired input, mA minimum required current
|
||||
12000, 2400, // 12V @ 2.4A
|
||||
9000, 2000, // 9V @ 2A
|
||||
5000, 100, // 5V @ whatever
|
||||
|
||||
};
|
||||
const uint8_t USB_PD_Desired_Levels_Len = 3;
|
||||
#endif
|
||||
@@ -6,7 +6,9 @@
|
||||
*/
|
||||
|
||||
#include "IRQ.h"
|
||||
#include "Pins.h"
|
||||
#include "int_n.h"
|
||||
|
||||
/*
|
||||
* Catch the IRQ that says that the conversion is done on the temperature
|
||||
* readings coming in Once these have come in we can unblock the PID so that it
|
||||
@@ -32,3 +34,12 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
|
||||
(void)GPIO_Pin;
|
||||
InterruptHandler::irqCallback();
|
||||
}
|
||||
|
||||
bool getFUS302IRQLow() {
|
||||
#ifdef POW_PD
|
||||
// Return true if the IRQ line is still held low
|
||||
return HAL_GPIO_ReadPin(INT_PD_GPIO_Port, INT_PD_Pin) == GPIO_PIN_RESET;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -8,10 +8,12 @@
|
||||
#include "int_n.h"
|
||||
#include "policy_engine.h"
|
||||
bool FUSB302_present = false;
|
||||
bool FUSB302_probed = false;
|
||||
|
||||
void power_check() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_present) {
|
||||
PolicyEngine::PPSTimerCallback();
|
||||
// Cant start QC until either PD works or fails
|
||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||
return;
|
||||
@@ -27,7 +29,12 @@ void power_check() {
|
||||
}
|
||||
uint8_t usb_pd_detect() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_probed) {
|
||||
return FUSB302_present;
|
||||
} else {
|
||||
FUSB302_present = fusb302_detect();
|
||||
FUSB302_probed = true;
|
||||
}
|
||||
return FUSB302_present;
|
||||
#endif
|
||||
return false;
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* PD Buddy Firmware Library - USB Power Delivery for everyone
|
||||
* Copyright 2017-2018 Clayton G. Hobbs
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
#include "fusb302b.h"
|
||||
#include "int_n.h"
|
||||
#include <pd.h>
|
||||
/*
|
||||
* Read a single byte from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
*
|
||||
* Returns the value read from addr.
|
||||
*/
|
||||
static uint8_t fusb_read_byte(uint8_t addr) {
|
||||
uint8_t data[1];
|
||||
if (!I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) {
|
||||
return 0;
|
||||
}
|
||||
return data[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read multiple bytes from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
* size: The number of bytes to read
|
||||
* buf: The buffer into which data will be read
|
||||
*/
|
||||
static bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return I2CBB::Mem_Read(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
/*
|
||||
* Write a single byte to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* byte: The value to write
|
||||
*/
|
||||
static bool fusb_write_byte(uint8_t addr, uint8_t byte) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); }
|
||||
|
||||
/*
|
||||
* Write multiple bytes to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* size: The number of bytes to write
|
||||
* buf: The buffer to write
|
||||
*/
|
||||
static bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
void fusb_send_message(const union pd_msg *msg) {
|
||||
if (!I2CBB::lock2()) {
|
||||
return;
|
||||
}
|
||||
/* Token sequences for the FUSB302B */
|
||||
static uint8_t sop_seq[5] = {FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP2, FUSB_FIFO_TX_PACKSYM};
|
||||
static const uint8_t eop_seq[4] = {FUSB_FIFO_TX_JAM_CRC, FUSB_FIFO_TX_EOP, FUSB_FIFO_TX_TXOFF, FUSB_FIFO_TX_TXON};
|
||||
|
||||
/* Take the I2C2 mutex now so there can't be a race condition on sop_seq */
|
||||
/* Get the length of the message: a two-octet header plus NUMOBJ four-octet
|
||||
* data objects */
|
||||
uint8_t msg_len = 2 + 4 * PD_NUMOBJ_GET(msg);
|
||||
|
||||
/* Set the number of bytes to be transmitted in the packet */
|
||||
sop_seq[4] = FUSB_FIFO_TX_PACKSYM | msg_len;
|
||||
|
||||
/* Write all three parts of the message to the TX FIFO */
|
||||
fusb_write_buf(FUSB_FIFOS, 5, sop_seq);
|
||||
fusb_write_buf(FUSB_FIFOS, msg_len, msg->bytes);
|
||||
fusb_write_buf(FUSB_FIFOS, 4, eop_seq);
|
||||
|
||||
I2CBB::unlock2();
|
||||
}
|
||||
|
||||
uint8_t fusb_read_message(union pd_msg *msg) {
|
||||
if (!I2CBB::lock2()) {
|
||||
asm("bkpt");
|
||||
}
|
||||
static uint8_t garbage[4];
|
||||
uint8_t numobj;
|
||||
|
||||
// Read the header. If its not a SOP we dont actually want it at all
|
||||
// But on some revisions of the fusb if you dont both pick them up and read them out of the fifo, it gets stuck
|
||||
fusb_read_byte(FUSB_FIFOS);
|
||||
/* Read the message header into msg */
|
||||
fusb_read_buf(FUSB_FIFOS, 2, msg->bytes);
|
||||
/* Get the number of data objects */
|
||||
numobj = PD_NUMOBJ_GET(msg);
|
||||
/* If there is at least one data object, read the data objects */
|
||||
if (numobj > 0) {
|
||||
fusb_read_buf(FUSB_FIFOS, numobj * 4, msg->bytes + 2);
|
||||
}
|
||||
/* Throw the CRC32 in the garbage, since the PHY already checked it. */
|
||||
fusb_read_buf(FUSB_FIFOS, 4, garbage);
|
||||
|
||||
I2CBB::unlock2();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fusb_send_hardrst() {
|
||||
|
||||
if (!I2CBB::lock2()) {
|
||||
return;
|
||||
}
|
||||
/* Send a hard reset */
|
||||
fusb_write_byte(FUSB_CONTROL3, 0x07 | FUSB_CONTROL3_SEND_HARD_RESET);
|
||||
|
||||
I2CBB::unlock2();
|
||||
}
|
||||
|
||||
bool fusb_setup() {
|
||||
|
||||
if (!I2CBB::lock2()) {
|
||||
return false;
|
||||
}
|
||||
/* Fully reset the FUSB302B */
|
||||
// fusb_write_byte( FUSB_RESET, FUSB_RESET_SW_RES);
|
||||
// osDelay(2);
|
||||
if (!fusb_read_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Turn on all power */
|
||||
fusb_write_byte(FUSB_POWER, 0x0F);
|
||||
|
||||
/* Set interrupt masks */
|
||||
// Setting to 0 so interrupts are allowed
|
||||
fusb_write_byte(FUSB_MASK1, 0x00);
|
||||
fusb_write_byte(FUSB_MASKA, 0x00);
|
||||
fusb_write_byte(FUSB_MASKB, 0x00);
|
||||
fusb_write_byte(FUSB_CONTROL0, 0b11 << 2);
|
||||
|
||||
/* Enable automatic retransmission */
|
||||
fusb_write_byte(FUSB_CONTROL3, 0x07);
|
||||
// set defaults
|
||||
fusb_write_byte(FUSB_CONTROL2, 0x00);
|
||||
/* Flush the RX buffer */
|
||||
fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH);
|
||||
|
||||
/* Measure CC1 */
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x07);
|
||||
osDelay(10);
|
||||
uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||
|
||||
/* Measure CC2 */
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x0B);
|
||||
osDelay(10);
|
||||
uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||
|
||||
/* Select the correct CC line for BMC signaling; also enable AUTO_CRC */
|
||||
if (cc1 > cc2) {
|
||||
fusb_write_byte(FUSB_SWITCHES1, 0x25);
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x07);
|
||||
} else {
|
||||
fusb_write_byte(FUSB_SWITCHES1, 0x26);
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x0B);
|
||||
}
|
||||
I2CBB::unlock2();
|
||||
fusb_reset();
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_9;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||
return true;
|
||||
}
|
||||
|
||||
void fusb_get_status(union fusb_status *status) {
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
if (!I2CBB::lock2()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the interrupt and status flags into status */
|
||||
fusb_read_buf(FUSB_STATUS0A, 7, status->bytes);
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
I2CBB::unlock2();
|
||||
}
|
||||
}
|
||||
|
||||
enum fusb_typec_current fusb_get_typec_current() {
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
if (!I2CBB::lock2()) {
|
||||
return fusb_tcc_none;
|
||||
}
|
||||
}
|
||||
/* Read the BC_LVL into a variable */
|
||||
enum fusb_typec_current bc_lvl = (enum fusb_typec_current)(fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL);
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
I2CBB::unlock2();
|
||||
}
|
||||
return bc_lvl;
|
||||
}
|
||||
|
||||
void fusb_reset() {
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
if (!I2CBB::lock2()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush the TX buffer */
|
||||
fusb_write_byte(FUSB_CONTROL0, 0x44);
|
||||
/* Flush the RX buffer */
|
||||
fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH);
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
I2CBB::unlock2();
|
||||
}
|
||||
}
|
||||
|
||||
bool fusb_read_id() {
|
||||
// Return true if read of the revision ID is sane
|
||||
uint8_t version = 0;
|
||||
fusb_read_buf(FUSB_DEVICE_ID, 1, &version);
|
||||
if (version == 0 || version == 0xFF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
uint8_t fusb302_detect() {
|
||||
// Probe the I2C bus for its address
|
||||
return I2CBB::probe(FUSB302B_ADDR);
|
||||
}
|
||||
|
||||
#endif
|
||||
68
source/Core/BSP/Miniware/fusb_user.cpp
Normal file
68
source/Core/BSP/Miniware/fusb_user.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
#include "Setup.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusb_user.h"
|
||||
/*
|
||||
* Read a single byte from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
*
|
||||
* Returns the value read from addr.
|
||||
*/
|
||||
uint8_t fusb_read_byte(uint8_t addr) {
|
||||
uint8_t data[1];
|
||||
if (!I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) {
|
||||
return 0;
|
||||
}
|
||||
return data[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read multiple bytes from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
* size: The number of bytes to read
|
||||
* buf: The buffer into which data will be read
|
||||
*/
|
||||
bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return I2CBB::Mem_Read(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
/*
|
||||
* Write a single byte to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* byte: The value to write
|
||||
*/
|
||||
bool fusb_write_byte(uint8_t addr, uint8_t byte) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); }
|
||||
|
||||
/*
|
||||
* Write multiple bytes to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* size: The number of bytes to write
|
||||
* buf: The buffer to write
|
||||
*/
|
||||
bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
uint8_t fusb302_detect() {
|
||||
// Probe the I2C bus for its address
|
||||
return I2CBB::probe(FUSB302B_ADDR);
|
||||
}
|
||||
|
||||
void setupFUSBIRQ() {
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_9;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||
}
|
||||
#endif
|
||||
@@ -11,11 +11,4 @@
|
||||
#include "task.h"
|
||||
|
||||
// Initialisation to be performed with scheduler active
|
||||
void postRToSInit() {
|
||||
#ifdef POW_PD
|
||||
if (usb_pd_detect() == true) {
|
||||
// Spawn all of the USB-C processors
|
||||
fusb302_start_processing();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void postRToSInit() {}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* BSP_PD.c
|
||||
*
|
||||
* Created on: 21 Jul 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#include "BSP_PD.h"
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
/*
|
||||
* An array of all of the desired voltages & minimum currents in preferred order
|
||||
*/
|
||||
const uint16_t USB_PD_Desired_Levels[] = {
|
||||
// mV desired input, mA minimum required current
|
||||
// Tip is ~ 7.5 ohms
|
||||
20000, 2666, // 20V, 2.6A
|
||||
18000, 2400, // 18V, 2.4A
|
||||
15000, 2000, // 15V 2A
|
||||
12000, 1600, // 12V @ 1.6A
|
||||
9000, 1200, // 9V @ 1.2A
|
||||
5000, 100, // 5V @ whatever
|
||||
|
||||
};
|
||||
const uint8_t USB_PD_Desired_Levels_Len = 6;
|
||||
#endif
|
||||
@@ -118,6 +118,10 @@ void EXTI5_9_IRQHandler(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool getFUS302IRQLow() {
|
||||
// Return true if the IRQ line is still held low
|
||||
return (RESET == gpio_input_bit_get(FUSB302_IRQ_GPIO_Port, FUSB302_IRQ_Pin));
|
||||
}
|
||||
// These are unused for now
|
||||
void I2C0_EV_IRQHandler(void) {}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#include "int_n.h"
|
||||
#include "policy_engine.h"
|
||||
bool FUSB302_present = false;
|
||||
bool FUSB302_probed = false;
|
||||
|
||||
void power_check() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_present) {
|
||||
PolicyEngine::PPSTimerCallback();
|
||||
// Cant start QC until either PD works or fails
|
||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||
return;
|
||||
@@ -27,8 +29,12 @@ void power_check() {
|
||||
}
|
||||
uint8_t usb_pd_detect() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_probed) {
|
||||
return FUSB302_present;
|
||||
} else {
|
||||
FUSB302_present = fusb302_detect();
|
||||
|
||||
FUSB302_probed = true;
|
||||
}
|
||||
return FUSB302_present;
|
||||
#endif
|
||||
return false;
|
||||
|
||||
58
source/Core/BSP/Pine64/fusb_user.cpp
Normal file
58
source/Core/BSP/Pine64/fusb_user.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
#include "Setup.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusb_user.h"
|
||||
/*
|
||||
* Read a single byte from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
*
|
||||
* Returns the value read from addr.
|
||||
*/
|
||||
uint8_t fusb_read_byte(uint8_t addr) {
|
||||
uint8_t data[1];
|
||||
if (!FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) {
|
||||
return 0;
|
||||
}
|
||||
return data[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read multiple bytes from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
* size: The number of bytes to read
|
||||
* buf: The buffer into which data will be read
|
||||
*/
|
||||
bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
/*
|
||||
* Write a single byte to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* byte: The value to write
|
||||
*/
|
||||
bool fusb_write_byte(uint8_t addr, uint8_t byte) { return FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); }
|
||||
|
||||
/*
|
||||
* Write multiple bytes to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* size: The number of bytes to write
|
||||
* buf: The buffer to write
|
||||
*/
|
||||
bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)buf, size); }
|
||||
|
||||
uint8_t fusb302_detect() {
|
||||
// Probe the I2C bus for its address
|
||||
return FRToSI2C::probe(FUSB302B_ADDR);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,10 +19,6 @@ void postRToSInit() {
|
||||
hall_effect_present = Si7210::init();
|
||||
}
|
||||
#endif
|
||||
#ifdef POW_PD
|
||||
// Spawn all of the USB-C processors
|
||||
fusb302_start_processing();
|
||||
#endif
|
||||
}
|
||||
int16_t getRawHallEffect() {
|
||||
if (hall_effect_present) {
|
||||
|
||||
@@ -14,65 +14,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#ifdef POW_PD
|
||||
#include "fusb302b.h"
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
#include "Setup.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusb_user.h"
|
||||
#include "int_n.h"
|
||||
#include <pd.h>
|
||||
/*
|
||||
* Read a single byte from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
*
|
||||
* Returns the value read from addr.
|
||||
*/
|
||||
static uint8_t fusb_read_byte(uint8_t addr) {
|
||||
uint8_t data[1];
|
||||
if (!FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) {
|
||||
return 0;
|
||||
}
|
||||
return data[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read multiple bytes from the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address from which to read
|
||||
* size: The number of bytes to read
|
||||
* buf: The buffer into which data will be read
|
||||
*/
|
||||
static bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, buf, size); }
|
||||
|
||||
/*
|
||||
* Write a single byte to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* byte: The value to write
|
||||
*/
|
||||
static bool fusb_write_byte(uint8_t addr, uint8_t byte) {
|
||||
FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write multiple bytes to the FUSB302B
|
||||
*
|
||||
* cfg: The FUSB302B to communicate with
|
||||
* addr: The memory address to which we will write
|
||||
* size: The number of bytes to write
|
||||
* buf: The buffer to write
|
||||
*/
|
||||
static bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) {
|
||||
FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)buf, size);
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
void fusb_send_message(const union pd_msg *msg) {
|
||||
|
||||
/* Token sequences for the FUSB302B */
|
||||
@@ -122,15 +70,12 @@ void fusb_send_hardrst() {
|
||||
}
|
||||
|
||||
bool fusb_setup() {
|
||||
if (!FRToSI2C::probe(FUSB302B_ADDR)) {
|
||||
return false;
|
||||
}
|
||||
/* Fully reset the FUSB302B */
|
||||
fusb_write_byte(FUSB_RESET, FUSB_RESET_SW_RES);
|
||||
osDelay(2);
|
||||
vTaskDelay(TICKS_10MS);
|
||||
uint8_t tries = 0;
|
||||
while (!fusb_read_id()) {
|
||||
osDelay(10);
|
||||
vTaskDelay(TICKS_10MS);
|
||||
tries++;
|
||||
if (tries > 5) {
|
||||
return false; // Welp :(
|
||||
@@ -156,12 +101,12 @@ bool fusb_setup() {
|
||||
|
||||
/* Measure CC1 */
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x07);
|
||||
osDelay(10);
|
||||
vTaskDelay(TICKS_10MS);
|
||||
uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||
|
||||
/* Measure CC2 */
|
||||
fusb_write_byte(FUSB_SWITCHES0, 0x0B);
|
||||
osDelay(10);
|
||||
vTaskDelay(TICKS_10MS);
|
||||
uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||
|
||||
/* Select the correct CC line for BMC signaling; also enable AUTO_CRC */
|
||||
@@ -210,9 +155,3 @@ bool fusb_read_id() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
uint8_t fusb302_detect() {
|
||||
// Probe the I2C bus for its address
|
||||
return FRToSI2C::probe(FUSB302B_ADDR);
|
||||
}
|
||||
|
||||
#endif
|
||||
29
source/Core/Drivers/FUSB302/fusb_user.h
Normal file
29
source/Core/Drivers/FUSB302/fusb_user.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* PD Buddy Firmware Library - USB Power Delivery for everyone
|
||||
* Copyright 2017-2018 Clayton G. Hobbs
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PDB_FUSB_USER_H
|
||||
#define PDB_FUSB_USER_H
|
||||
|
||||
#include <stdint.h>
|
||||
uint8_t fusb_read_byte(uint8_t addr);
|
||||
bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf);
|
||||
bool fusb_write_byte(uint8_t addr, uint8_t byte);
|
||||
bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf);
|
||||
uint8_t fusb302_detect();
|
||||
void setupFUSBIRQ();
|
||||
|
||||
#endif /* PDB_FUSB302B_H */
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "fusb302b.h"
|
||||
#include "int_n.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
|
||||
#include "protocol_tx.h"
|
||||
#include <fusbpd.h>
|
||||
#include <pd.h>
|
||||
@@ -21,7 +21,6 @@ void fusb302_start_processing() {
|
||||
if (fusb_setup()) {
|
||||
PolicyEngine::init();
|
||||
ProtocolTransmit::init();
|
||||
ProtocolReceive::init();
|
||||
InterruptHandler::init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,34 +17,63 @@
|
||||
|
||||
#include "int_n.h"
|
||||
#include "BSP.h"
|
||||
#include "BSP_PD.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusbpd.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
|
||||
#include "protocol_tx.h"
|
||||
#include "task.h"
|
||||
#include <pd.h>
|
||||
#include <string.h>
|
||||
|
||||
osThreadId InterruptHandler::TaskHandle = NULL;
|
||||
volatile osThreadId InterruptHandler::TaskHandle = NULL;
|
||||
uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize];
|
||||
osStaticThreadDef_t InterruptHandler::TaskControlBlock;
|
||||
union pd_msg InterruptHandler::tempMessage;
|
||||
|
||||
void InterruptHandler::init() {
|
||||
TaskHandle = NULL;
|
||||
osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||
TaskHandle = osThreadCreate(osThread(intTask), NULL);
|
||||
}
|
||||
|
||||
void InterruptHandler::readPendingMessage() {
|
||||
/* Get a buffer to read the message into. Guaranteed to not fail
|
||||
* because we have a big enough pool and are careful. */
|
||||
memset(&tempMessage, 0, sizeof(tempMessage));
|
||||
/* Read the message */
|
||||
fusb_read_message(&tempMessage);
|
||||
/* If it's a Soft_Reset, go to the soft reset state */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
/* TX transitions to its reset state */
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET);
|
||||
} else {
|
||||
/* Tell ProtocolTX to discard the message being transmitted */
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD);
|
||||
|
||||
/* Pass the message to the policy engine. */
|
||||
PolicyEngine::handleMessage(&tempMessage);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
for (;;) {
|
||||
// If the irq is low continue, otherwise wait for irq or timeout
|
||||
if (!getFUS302IRQLow()) {
|
||||
xTaskNotifyWait(0x00, 0x0F, NULL, TICKS_SECOND * 30);
|
||||
}
|
||||
/* Read the FUSB302B status and interrupt registers */
|
||||
fusb_get_status(&status);
|
||||
|
||||
/* 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) {
|
||||
readPendingMessage();
|
||||
}
|
||||
|
||||
/* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX
|
||||
* thread */
|
||||
if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) {
|
||||
@@ -54,25 +83,17 @@ void InterruptHandler::Thread(const void *arg) {
|
||||
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_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);
|
||||
PolicyEngine::notify(PolicyEngine::Notifications::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
private:
|
||||
static void Thread(const void *arg);
|
||||
static osThreadId TaskHandle;
|
||||
static volatile osThreadId TaskHandle;
|
||||
static const size_t TaskStackSize = 1536 / 3;
|
||||
static uint32_t TaskBuffer[TaskStackSize];
|
||||
static osStaticThreadDef_t TaskControlBlock;
|
||||
@@ -44,6 +44,9 @@ private:
|
||||
static enum hardrst_state hardrst_hard_reset_requested();
|
||||
static enum hardrst_state hardrst_wait_pe();
|
||||
static enum hardrst_state hardrst_complete();
|
||||
// Mesage rx
|
||||
static void readPendingMessage();
|
||||
static union pd_msg tempMessage;
|
||||
};
|
||||
|
||||
#endif /* PDB_INT_N_OLD_H */
|
||||
|
||||
@@ -271,13 +271,13 @@
|
||||
* Where a range is specified, the middle of the range (rounded down to the
|
||||
* nearest millisecond) is used.
|
||||
*/
|
||||
#define PD_T_CHUNKING_NOT_SUPPORTED (450)
|
||||
#define PD_T_HARD_RESET_COMPLETE (1000)
|
||||
#define PD_T_PS_TRANSITION (5000)
|
||||
#define PD_T_SENDER_RESPONSE (2700)
|
||||
#define PD_T_SINK_REQUEST (1000)
|
||||
#define PD_T_TYPEC_SINK_WAIT_CAP (1000)
|
||||
#define PD_T_PD_DEBOUNCE (2000)
|
||||
#define PD_T_CHUNKING_NOT_SUPPORTED (TICKS_SECOND / 2)
|
||||
#define PD_T_HARD_RESET_COMPLETE (1 * TICKS_SECOND)
|
||||
#define PD_T_PS_TRANSITION (5 * TICKS_SECOND)
|
||||
#define PD_T_SENDER_RESPONSE (27 * TICKS_100MS)
|
||||
#define PD_T_SINK_REQUEST (1 * TICKS_SECOND)
|
||||
#define PD_T_TYPEC_SINK_WAIT_CAP (1 * TICKS_SECOND)
|
||||
#define PD_T_PD_DEBOUNCE (2 * TICKS_SECOND)
|
||||
|
||||
/*
|
||||
* Counter maximums
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
#define PDB_CONF_H
|
||||
|
||||
/* Number of messages in the message pool */
|
||||
#define PDB_MSG_POOL_SIZE 4
|
||||
#define PDB_MSG_POOL_SIZE 8
|
||||
|
||||
#define EVENT_MASK(x) (1 << x)
|
||||
#define eventmask_t uint32_t
|
||||
|
||||
/* PD Buddy thread priorities */
|
||||
#define PDB_PRIO_PE (osPriorityNormal)
|
||||
#define PDB_PRIO_PRL (osPriorityBelowNormal)
|
||||
#define PDB_PRIO_PRL_INT_N (osPriorityLow)
|
||||
#define PDB_PRIO_PE (osPriorityAboveNormal)
|
||||
#define PDB_PRIO_PRL (osPriorityAboveNormal)
|
||||
#define PDB_PRIO_PRL_INT_N (osPriorityAboveNormal)
|
||||
|
||||
#endif /* PDB_CONF_H */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "policy_engine.h"
|
||||
#include "Defines.h"
|
||||
#include "fusb302b.h"
|
||||
#include "int_n.h"
|
||||
#include "protocol_tx.h"
|
||||
@@ -31,7 +32,6 @@ bool PolicyEngine::_explicit_contract;
|
||||
int8_t PolicyEngine::_hard_reset_counter;
|
||||
int8_t PolicyEngine::_old_tcc_match;
|
||||
uint8_t PolicyEngine::_pps_index;
|
||||
uint8_t PolicyEngine::_last_pps;
|
||||
osThreadId PolicyEngine::TaskHandle = NULL;
|
||||
uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize];
|
||||
osStaticThreadDef_t PolicyEngine::TaskControlBlock;
|
||||
@@ -43,6 +43,8 @@ uint8_t PolicyEngine::ucQueueStorageArea[PDB_MSG_POOL_
|
||||
QueueHandle_t PolicyEngine::messagesWaiting = NULL;
|
||||
EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t PolicyEngine::xCreatedEventGroup;
|
||||
bool PolicyEngine::PPSTimerEnabled = false;
|
||||
TickType_t PolicyEngine::PPSTimeLastEvent = 0;
|
||||
void PolicyEngine::init() {
|
||||
messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue);
|
||||
// Create static thread at PDB_PRIO_PE priority
|
||||
@@ -51,9 +53,10 @@ void PolicyEngine::init() {
|
||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||
}
|
||||
|
||||
void PolicyEngine::notify(uint32_t notification) {
|
||||
void PolicyEngine::notify(PolicyEngine::Notifications notification) {
|
||||
EventBits_t val = (EventBits_t)notification;
|
||||
if (xEventGroupHandle != NULL) {
|
||||
xEventGroupSetBits(xEventGroupHandle, notification);
|
||||
xEventGroupSetBits(xEventGroupHandle, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +67,7 @@ void PolicyEngine::pe_task(const void *arg) {
|
||||
/* Initialize the old_tcc_match */
|
||||
_old_tcc_match = -1;
|
||||
/* Initialize the pps_index */
|
||||
_pps_index = 8;
|
||||
/* Initialize the last_pps */
|
||||
_last_pps = 8;
|
||||
_pps_index = 0xFF;
|
||||
|
||||
for (;;) {
|
||||
// Loop based on state
|
||||
@@ -133,7 +134,7 @@ void PolicyEngine::pe_task(const void *arg) {
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() {
|
||||
/* We don't have an explicit contract currently */
|
||||
_explicit_contract = false;
|
||||
|
||||
PPSTimerEnabled = false;
|
||||
// If desired could send an alert that PD is starting
|
||||
|
||||
/* No need to reset the protocol layer here. There are two ways into this
|
||||
@@ -154,31 +155,27 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_discovery() {
|
||||
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() {
|
||||
/* Fetch a message from the protocol layer */
|
||||
eventmask_t evt = 0;
|
||||
if (readMessage()) {
|
||||
evt = PDB_EVT_PE_MSG_RX_PEND;
|
||||
} else {
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_I_OVRTEMP | PDB_EVT_PE_RESET,
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP | (uint32_t)Notifications::PDB_EVT_PE_RESET,
|
||||
// Wait for cap timeout
|
||||
PD_T_TYPEC_SINK_WAIT_CAP);
|
||||
}
|
||||
|
||||
/* If we timed out waiting for Source_Capabilities, send a hard reset */
|
||||
if (evt == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkWaitCap;
|
||||
}
|
||||
/* If we're too hot, we shouldn't negotiate power yet */
|
||||
if (evt & PDB_EVT_PE_I_OVRTEMP) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP) {
|
||||
return PESinkWaitCap;
|
||||
}
|
||||
|
||||
/* If we got a message */
|
||||
if (evt & (PDB_EVT_PE_MSG_RX | PDB_EVT_PE_MSG_RX_PEND)) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_MSG_RX) {
|
||||
/* Get the message */
|
||||
while ((evt & PDB_EVT_PE_MSG_RX_PEND) || readMessage() == true) {
|
||||
while (readMessage()) {
|
||||
/* If we got a Source_Capabilities message, read it. */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||
/* First, determine what PD revision we're using */
|
||||
@@ -194,15 +191,13 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() {
|
||||
}
|
||||
}
|
||||
return PESinkEvalCap;
|
||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
||||
}
|
||||
evt = 0;
|
||||
}
|
||||
return PESinkWaitCap; // wait for more messages?
|
||||
}
|
||||
|
||||
/* If we failed to get a message, send a hard reset */
|
||||
return PESinkHardReset;
|
||||
/* If we failed to get a message, wait longer */
|
||||
return PESinkWaitCap;
|
||||
}
|
||||
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
@@ -211,7 +206,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
* PE_SNK_Select_Cap. */
|
||||
/* Start by assuming we won't find a PPS APDO (set the index greater
|
||||
* than the maximum possible) */
|
||||
_pps_index = 8;
|
||||
_pps_index = 0xFF;
|
||||
/* New capabilities also means we can't be making a request from the
|
||||
* same PPS APDO */
|
||||
/* Search for the first PPS APDO */
|
||||
for (int i = 0; i < PD_NUMOBJ_GET(&tempMessage); i++) {
|
||||
if ((tempMessage.obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (tempMessage.obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) {
|
||||
@@ -219,13 +216,18 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* New capabilities also means we can't be making a request from the
|
||||
* same PPS APDO */
|
||||
_last_pps = 8;
|
||||
|
||||
/* Ask the DPM what to request */
|
||||
if (pdbs_dpm_evaluate_capability(&tempMessage, &_last_dpm_request)) {
|
||||
|
||||
/* If we're using PD 3.0 */
|
||||
if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
||||
/* If the request was for a PPS APDO, start time callbacks if not started */
|
||||
if (PD_RDO_OBJPOS_GET(&_last_dpm_request) >= _pps_index) {
|
||||
PPSTimerEnabled = true;
|
||||
} else {
|
||||
PPSTimerEnabled = false;
|
||||
}
|
||||
}
|
||||
return PESinkSelectCap;
|
||||
}
|
||||
|
||||
@@ -235,29 +237,28 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
|
||||
/* Transmit the request */
|
||||
waitForEvent(0xFFFF, 0); // clear pending
|
||||
waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL, 0); // clear pending
|
||||
ProtocolTransmit::pushMessage(&_last_dpm_request);
|
||||
// Send indication that there is a message pending
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET || evt == 0) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET || evt == 0) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a hard reset */
|
||||
if ((evt & PDB_EVT_PE_TX_ERR) == PDB_EVT_PE_TX_ERR) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_ERR) == (uint32_t)Notifications::PDB_EVT_PE_TX_ERR) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
/* Wait for a response */
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE);
|
||||
evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If we didn't get a response before the timeout, send a hard reset */
|
||||
if (evt == 0) {
|
||||
return PESinkHardReset;
|
||||
return PESinkSoftReset;
|
||||
}
|
||||
|
||||
/* Get the response message */
|
||||
@@ -265,7 +266,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
readMessage();
|
||||
/* If the source accepted our request, wait for the new power */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkTransitionSink;
|
||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
@@ -280,7 +280,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
return PESinkReady;
|
||||
}
|
||||
} else {
|
||||
return PESinkSendSoftReset;
|
||||
return PESinkSoftReset;
|
||||
}
|
||||
}
|
||||
return PESinkHardReset;
|
||||
@@ -288,111 +288,97 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() {
|
||||
/* Wait for the PS_RDY message */
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_PS_TRANSITION);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_PS_TRANSITION);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If no message was received, send a hard reset */
|
||||
if (evt == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
/* If we received a message, read it */
|
||||
if (messageWaiting()) {
|
||||
while (messageWaiting()) {
|
||||
readMessage();
|
||||
/* If we got a PS_RDY, handle it */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PS_RDY && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
/* We just finished negotiating an explicit contract */
|
||||
_explicit_contract = true;
|
||||
|
||||
/* Set the output appropriately */
|
||||
/* Negotiation finished */
|
||||
pdbs_dpm_transition_requested();
|
||||
|
||||
return PESinkReady;
|
||||
/* If there was a protocol error, send a hard reset */
|
||||
} else {
|
||||
/* Turn off the power output before this hard reset to make sure we
|
||||
* don't supply an incorrect voltage to the device we're powering.
|
||||
*/
|
||||
pdbs_dpm_transition_default();
|
||||
|
||||
return PESinkHardReset;
|
||||
}
|
||||
}
|
||||
|
||||
return PESinkHardReset;
|
||||
return PESinkSoftReset;
|
||||
}
|
||||
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
||||
eventmask_t evt;
|
||||
|
||||
/* Wait for an event */
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP);
|
||||
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL);
|
||||
/* If SinkPPSPeriodicTimer ran out, send a new request */
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_PPS_REQUEST) {
|
||||
return PESinkSelectCap;
|
||||
}
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
|
||||
/* If we overheated, send a hard reset */
|
||||
if (evt & PDB_EVT_PE_I_OVRTEMP) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
/* If the DPM wants us to, send a Get_Source_Cap message */
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_GET_SOURCE_CAP) {
|
||||
return PESinkGetSourceCap;
|
||||
}
|
||||
/* If the DPM wants new power, let it figure out what power it wants
|
||||
* exactly. This isn't exactly the transition from the spec (that would be
|
||||
* SelectCap, not EvalCap), but this works better with the particular
|
||||
* design of this firmware. */
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_NEW_POWER) {
|
||||
/* Tell the protocol layer we're starting an AMS */
|
||||
return PESinkEvalCap;
|
||||
}
|
||||
|
||||
/* If we received a message */
|
||||
if (evt & PDB_EVT_PE_MSG_RX) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_MSG_RX) {
|
||||
if (messageWaiting()) {
|
||||
readMessage();
|
||||
/* Ignore vendor-defined messages */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VENDOR_DEFINED && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||
|
||||
return PESinkReady;
|
||||
/* Ignore Ping messages */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PING && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkReady;
|
||||
/* DR_Swap messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_DR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* Get_Source_Cap messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SOURCE_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* PR_Swap messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* VCONN_Swap messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VCONN_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* Request messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REQUEST && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* Sink_Capabilities messages are not supported */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SINK_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||
|
||||
return PESinkSendNotSupported;
|
||||
/* Handle GotoMin messages */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GOTOMIN && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
/* GiveBack is not supported */
|
||||
return PESinkSendNotSupported;
|
||||
|
||||
/* Evaluate new Source_Capabilities */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||
/* Don't free the message: we need to keep the
|
||||
* Source_Capabilities message so we can evaluate it. */
|
||||
return PESinkEvalCap;
|
||||
/* Give sink capabilities when asked */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SINK_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkGiveSinkCap;
|
||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkSoftReset;
|
||||
/* PD 3.0 messges */
|
||||
} else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
||||
@@ -411,9 +397,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
||||
|
||||
return PESinkSendSoftReset;
|
||||
}
|
||||
} else {
|
||||
/* if we get an unknown message code, silently ignore it*/
|
||||
return PESinkReady;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,15 +411,14 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_get_source_cap() {
|
||||
get_source_cap->hdr = hdr_template | PD_MSGTYPE_GET_SOURCE_CAP | PD_NUMOBJ(0);
|
||||
/* Transmit the Get_Source_Cap */
|
||||
ProtocolTransmit::pushMessage(get_source_cap);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
/* Free the sent message */
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a hard reset */
|
||||
if ((evt & PDB_EVT_PE_TX_DONE) == 0) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
@@ -451,17 +433,16 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_give_sink_cap() {
|
||||
|
||||
/* Transmit our capabilities */
|
||||
ProtocolTransmit::pushMessage(snk_cap);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
|
||||
/* Free the Sink_Capabilities message */
|
||||
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a hard reset */
|
||||
if ((evt & PDB_EVT_PE_TX_DONE) == 0) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
@@ -505,16 +486,15 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_soft_reset() {
|
||||
accept.hdr = hdr_template | PD_MSGTYPE_ACCEPT | PD_NUMOBJ(0);
|
||||
/* Transmit the Accept */
|
||||
ProtocolTransmit::pushMessage(&accept);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
/* Free the sent message */
|
||||
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a hard reset */
|
||||
if ((evt & PDB_EVT_PE_TX_DONE) == 0) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
@@ -531,21 +511,20 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() {
|
||||
softrst->hdr = hdr_template | PD_MSGTYPE_SOFT_RESET | PD_NUMOBJ(0);
|
||||
/* Transmit the soft reset */
|
||||
ProtocolTransmit::pushMessage(softrst);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a hard reset */
|
||||
if ((evt & PDB_EVT_PE_TX_DONE) == 0) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
/* Wait for a response */
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE);
|
||||
evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If we didn't get a response before the timeout, send a hard reset */
|
||||
@@ -575,27 +554,25 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() {
|
||||
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() {
|
||||
/* Get a message object */
|
||||
union pd_msg *not_supported = &tempMessage;
|
||||
|
||||
if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_2_0) {
|
||||
/* Make a Reject message */
|
||||
not_supported->hdr = hdr_template | PD_MSGTYPE_REJECT | PD_NUMOBJ(0);
|
||||
tempMessage.hdr = hdr_template | PD_MSGTYPE_REJECT | PD_NUMOBJ(0);
|
||||
} else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
||||
/* Make a Not_Supported message */
|
||||
not_supported->hdr = hdr_template | PD_MSGTYPE_NOT_SUPPORTED | PD_NUMOBJ(0);
|
||||
tempMessage.hdr = hdr_template | PD_MSGTYPE_NOT_SUPPORTED | PD_NUMOBJ(0);
|
||||
}
|
||||
|
||||
/* Transmit the message */
|
||||
ProtocolTransmit::pushMessage(not_supported);
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
||||
ProtocolTransmit::pushMessage(&tempMessage);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
|
||||
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
/* If the message transmission failed, send a soft reset */
|
||||
if ((evt & PDB_EVT_PE_TX_DONE) == 0) {
|
||||
if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) {
|
||||
return PESinkSendSoftReset;
|
||||
}
|
||||
|
||||
@@ -605,9 +582,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() {
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_chunk_received() {
|
||||
|
||||
/* Wait for tChunkingNotSupported */
|
||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_RESET, PD_T_CHUNKING_NOT_SUPPORTED);
|
||||
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_CHUNKING_NOT_SUPPORTED);
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||
return PESinkTransitionDefault;
|
||||
}
|
||||
|
||||
@@ -628,6 +605,23 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_source_unresponsive() {
|
||||
return PESinkSourceUnresponsive;
|
||||
}
|
||||
|
||||
uint32_t PolicyEngine::waitForEvent(uint32_t mask, TickType_t ticksToWait) { return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); }
|
||||
EventBits_t PolicyEngine::waitForEvent(uint32_t mask, TickType_t ticksToWait) { return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); }
|
||||
|
||||
bool PolicyEngine::isPD3_0() { return (hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0; }
|
||||
|
||||
void PolicyEngine::handleMessage(union pd_msg *msg) {
|
||||
xQueueSend(messagesWaiting, msg, 100);
|
||||
notify(PolicyEngine::Notifications::PDB_EVT_PE_MSG_RX);
|
||||
}
|
||||
|
||||
void PolicyEngine::PPSTimerCallback() {
|
||||
if (PPSTimerEnabled && state == policy_engine_state::PESinkReady) {
|
||||
// I believe even once per second is totally fine, but leaning on faster since everything seems cool with faster
|
||||
// Have seen everything from 10ms to 1 second :D
|
||||
if ((xTaskGetTickCount() - PPSTimeLastEvent) > (TICKS_SECOND)) {
|
||||
// Send a new PPS message
|
||||
PolicyEngine::notify(Notifications::PDB_EVT_PE_PPS_REQUEST);
|
||||
PPSTimeLastEvent = xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,22 +25,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define PDB_EVT_PE_RESET EVENT_MASK(0)
|
||||
#define PDB_EVT_PE_MSG_RX EVENT_MASK(1)
|
||||
#define PDB_EVT_PE_TX_DONE EVENT_MASK(2)
|
||||
#define PDB_EVT_PE_TX_ERR EVENT_MASK(3)
|
||||
#define PDB_EVT_PE_HARD_SENT EVENT_MASK(4)
|
||||
#define PDB_EVT_PE_I_OVRTEMP EVENT_MASK(5)
|
||||
#define PDB_EVT_PE_MSG_RX_PEND EVENT_MASK(7) /* Never SEND THIS DIRECTLY*/
|
||||
|
||||
class PolicyEngine {
|
||||
public:
|
||||
// Sets up internal state and registers the thread
|
||||
static void init();
|
||||
// Push an incoming message to the Policy Engine
|
||||
static void handleMessage(union pd_msg *msg);
|
||||
// Send a notification
|
||||
static void notify(uint32_t notification);
|
||||
// Returns true if headers indicate PD3.0 compliant
|
||||
static bool isPD3_0();
|
||||
static bool setupCompleteOrTimedOut() {
|
||||
@@ -53,7 +43,30 @@ public:
|
||||
return false;
|
||||
}
|
||||
// Has pd negotiation completed
|
||||
static bool pdHasNegotiated() { return pdNegotiationComplete; }
|
||||
static bool pdHasNegotiated() {
|
||||
if (state == policy_engine_state::PESinkSourceUnresponsive)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// Call this periodically, at least once every second
|
||||
static void PPSTimerCallback();
|
||||
|
||||
enum class Notifications {
|
||||
PDB_EVT_PE_RESET = EVENT_MASK(0),
|
||||
PDB_EVT_PE_MSG_RX = EVENT_MASK(1),
|
||||
PDB_EVT_PE_TX_DONE = EVENT_MASK(2),
|
||||
PDB_EVT_PE_TX_ERR = EVENT_MASK(3),
|
||||
PDB_EVT_PE_HARD_SENT = EVENT_MASK(4),
|
||||
PDB_EVT_PE_I_OVRTEMP = EVENT_MASK(5),
|
||||
PDB_EVT_PE_PPS_REQUEST = EVENT_MASK(6),
|
||||
PDB_EVT_PE_GET_SOURCE_CAP = EVENT_MASK(7),
|
||||
PDB_EVT_PE_NEW_POWER = EVENT_MASK(8),
|
||||
PDB_EVT_PE_ALL = (EVENT_MASK(9) - 1),
|
||||
};
|
||||
// Send a notification
|
||||
static void notify(Notifications notification);
|
||||
// Debugging allows looking at state
|
||||
static uint32_t getState() { return (uint32_t)state; }
|
||||
|
||||
private:
|
||||
static bool pdNegotiationComplete;
|
||||
@@ -72,17 +85,16 @@ private:
|
||||
static int8_t _old_tcc_match;
|
||||
/* The index of the first PPS APDO */
|
||||
static uint8_t _pps_index;
|
||||
/* The index of the just-requested PPS APDO */
|
||||
static uint8_t _last_pps;
|
||||
|
||||
static void pe_task(const void *arg);
|
||||
enum policy_engine_state {
|
||||
PESinkStartup,
|
||||
PESinkDiscovery,
|
||||
PESinkWaitCap,
|
||||
PESinkEvalCap,
|
||||
PESinkSelectCap,
|
||||
PESinkTransitionSink,
|
||||
PESinkReady,
|
||||
PESinkSelectCap, // 4
|
||||
PESinkTransitionSink, // 5
|
||||
PESinkReady, // 6
|
||||
PESinkGetSourceCap,
|
||||
PESinkGiveSinkCap,
|
||||
PESinkHardReset,
|
||||
@@ -113,7 +125,7 @@ private:
|
||||
static enum policy_engine_state pe_sink_source_unresponsive();
|
||||
static EventGroupHandle_t xEventGroupHandle;
|
||||
static StaticEventGroup_t xCreatedEventGroup;
|
||||
static uint32_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY);
|
||||
static EventBits_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY);
|
||||
// Task resources
|
||||
static osThreadId TaskHandle;
|
||||
static const size_t TaskStackSize = 2048 / 4;
|
||||
@@ -131,6 +143,8 @@ private:
|
||||
static bool messageWaiting();
|
||||
// Read a pending message into the temp message
|
||||
static bool readMessage();
|
||||
static bool PPSTimerEnabled;
|
||||
static TickType_t PPSTimeLastEvent;
|
||||
|
||||
// These callbacks are called to implement the logic for the iron to select the desired voltage
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "BSP_PD.h"
|
||||
#include "configuration.h"
|
||||
#include "pd.h"
|
||||
#include "policy_engine.h"
|
||||
|
||||
/* The current draw when the output is disabled */
|
||||
#define DPM_MIN_CURRENT PD_MA2PDI(50)
|
||||
#define DPM_MIN_CURRENT PD_MA2PDI(100)
|
||||
/*
|
||||
* Find the index of the first PDO from capabilities in the voltage range,
|
||||
* using the desired order.
|
||||
@@ -54,52 +56,88 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
|
||||
/* 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++) {
|
||||
uint8_t bestIndex = 0xFF;
|
||||
int bestIndexVoltage = 0;
|
||||
int bestIndexCurrent = 0;
|
||||
bool bestIsPPS = false;
|
||||
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) {
|
||||
// Evaluate if it can produve sufficient current based on the tipResistance (ohms*10)
|
||||
// V=I*R -> V/I => minimum resistance, if our tip resistance is >= this then we can use this supply
|
||||
|
||||
int voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); // voltage in mV units
|
||||
int current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // current in 10mA units
|
||||
int min_resistance_ohmsx10 = voltage_mv / current_a_x100;
|
||||
if (voltage_mv <= (USB_PD_VMAX * 1000)) {
|
||||
if (min_resistance_ohmsx10 <= tipResistance) {
|
||||
// This is a valid power source we can select as
|
||||
if (voltage_mv > bestIndexVoltage || bestIndex == 0xFF) {
|
||||
// Higher voltage and valid, select this instead
|
||||
bestIndex = i;
|
||||
bestIndexVoltage = voltage_mv;
|
||||
bestIndexCurrent = current_a_x100;
|
||||
bestIsPPS = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
||||
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (capabilities->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) {
|
||||
// If this is a PPS slot, calculate the max voltage in the PPS range that can we be used and maintain
|
||||
uint16_t max_voltage = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(capabilities->obj[i]));
|
||||
// uint16_t min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(capabilities->obj[i]));
|
||||
uint16_t max_current = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(capabilities->obj[i])); // max current in 10mA units
|
||||
// Using the current and tip resistance, calculate the ideal max voltage
|
||||
// if this is range, then we will work with this voltage
|
||||
// if this is not in range; then max_voltage can be safely selected
|
||||
int ideal_voltage_mv = (tipResistance * max_current);
|
||||
if (ideal_voltage_mv > max_voltage) {
|
||||
ideal_voltage_mv = max_voltage; // constrain
|
||||
}
|
||||
if (ideal_voltage_mv > (USB_PD_VMAX * 1000)) {
|
||||
ideal_voltage_mv = (USB_PD_VMAX * 1000); // constrain to model max
|
||||
}
|
||||
if (ideal_voltage_mv > bestIndexVoltage || bestIndex == 0xFF) {
|
||||
bestIndex = i;
|
||||
bestIndexVoltage = ideal_voltage_mv;
|
||||
bestIndexCurrent = max_current;
|
||||
bestIsPPS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestIndex != 0xFF) {
|
||||
/* 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;
|
||||
if (bestIsPPS) {
|
||||
request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(bestIndexCurrent)) | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(bestIndexVoltage)) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
|
||||
} else {
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(bestIndexCurrent) | PD_RDO_FV_CURRENT_SET(bestIndexCurrent) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
|
||||
}
|
||||
// We dont do usb
|
||||
// request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = voltage;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_requested_voltage = bestIndexVoltage;
|
||||
|
||||
} else {
|
||||
/* 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 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;
|
||||
// We dont do usb
|
||||
// request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
|
||||
/* Update requested voltage */
|
||||
_requested_voltage = 5000;
|
||||
|
||||
return false;
|
||||
}
|
||||
// Even if we didnt match, we return true as we would still like to handshake on 5V at the minimum
|
||||
return true;
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
|
||||
@@ -112,8 +150,12 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
|
||||
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
|
||||
uint16_t voltage = USB_PD_VMAX * 1000; // in mv
|
||||
if (_requested_voltage != 5000) {
|
||||
voltage = _requested_voltage;
|
||||
}
|
||||
uint16_t current = (voltage) / tipResistance; // In centi-amps
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -143,6 +185,11 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
|
||||
cap->obj[2] ^= cap->obj[1];
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
}
|
||||
/* If we're using PD 3.0, add a PPS APDO for our desired voltage */
|
||||
if ((hdr_template & PD_HDR_SPECREV) >= PD_SPECREV_3_0) {
|
||||
cap->obj[numobj++]
|
||||
= PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS | PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the unconstrained power flag. */
|
||||
@@ -167,7 +214,6 @@ bool PolicyEngine::pdbs_dpm_evaluate_typec_current(enum fusb_typec_current tcc)
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_transition_default() {
|
||||
/* Cast the dpm_data to the right type */
|
||||
|
||||
/* Pretend we requested 5 V */
|
||||
current_voltage_mv = 5000;
|
||||
@@ -175,12 +221,7 @@ void PolicyEngine::pdbs_dpm_transition_default() {
|
||||
pdNegotiationComplete = false;
|
||||
}
|
||||
|
||||
void PolicyEngine::pdbs_dpm_transition_requested() {
|
||||
/* Cast the dpm_data to the right type */
|
||||
pdNegotiationComplete = true;
|
||||
}
|
||||
|
||||
void PolicyEngine::handleMessage(union pd_msg *msg) { xQueueSend(messagesWaiting, msg, 100); }
|
||||
void PolicyEngine::pdbs_dpm_transition_requested() { pdNegotiationComplete = true; }
|
||||
|
||||
bool PolicyEngine::messageWaiting() { return uxQueueMessagesWaiting(messagesWaiting) > 0; }
|
||||
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* PD Buddy Firmware Library - USB Power Delivery for everyone
|
||||
* Copyright 2017-2018 Clayton G. Hobbs
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "protocol_rx.h"
|
||||
|
||||
#include "fusb302b.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_tx.h"
|
||||
#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;
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRL_Rx_Layer_Reset_for_Receive state
|
||||
*/
|
||||
ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_reset() {
|
||||
/* Reset MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
|
||||
/* Clear stored MessageID */
|
||||
_rx_messageid = -1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* 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 */
|
||||
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD);
|
||||
|
||||
/* Update the stored MessageID */
|
||||
_rx_messageid = PD_MESSAGEID_GET(&tempMessage);
|
||||
|
||||
/* 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. */
|
||||
|
||||
return PRLRxWaitPHY;
|
||||
}
|
||||
|
||||
void ProtocolReceive::init() {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ProtocolReceive::waitForEvent(uint32_t mask, TickType_t ticksToWait) {
|
||||
if (xEventGroupHandle != NULL) {
|
||||
return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* PD Buddy Firmware Library - USB Power Delivery for everyone
|
||||
* Copyright 2017-2018 Clayton G. Hobbs
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PDB_PROTOCOL_RX_H
|
||||
#define PDB_PROTOCOL_RX_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <pd.h>
|
||||
|
||||
/* Events for the Protocol RX thread */
|
||||
#define PDB_EVT_PRLRX_RESET EVENT_MASK(0)
|
||||
#define PDB_EVT_PRLRX_I_GCRCSENT EVENT_MASK(1)
|
||||
#define PDB_EVT_PRLRX_I_RXPEND EVENT_MASK(2)
|
||||
|
||||
class ProtocolReceive {
|
||||
public:
|
||||
static void init();
|
||||
static void notify(uint32_t notification);
|
||||
|
||||
private:
|
||||
static void thread(const void *args);
|
||||
|
||||
static EventGroupHandle_t xEventGroupHandle;
|
||||
static StaticEventGroup_t xCreatedEventGroup;
|
||||
static osThreadId TaskHandle;
|
||||
static const size_t TaskStackSize = 1024 / 4;
|
||||
static uint32_t TaskBuffer[TaskStackSize];
|
||||
static osStaticThreadDef_t TaskControlBlock;
|
||||
/*
|
||||
* Protocol RX machine states
|
||||
*
|
||||
* There is no Send_GoodCRC state because the PHY sends the GoodCRC for us.
|
||||
* All transitions that would go to that state instead go to Check_MessageID.
|
||||
*/
|
||||
enum protocol_rx_state { PRLRxWaitPHY, PRLRxReset, PRLRxCheckMessageID, PRLRxStoreMessageID };
|
||||
static protocol_rx_state protocol_rx_store_messageid();
|
||||
static protocol_rx_state protocol_rx_check_messageid();
|
||||
static protocol_rx_state protocol_rx_reset();
|
||||
static protocol_rx_state protocol_rx_wait_phy();
|
||||
static union pd_msg tempMessage;
|
||||
static uint8_t _rx_messageid;
|
||||
static uint8_t _tx_messageidcounter;
|
||||
static uint32_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY);
|
||||
};
|
||||
|
||||
#endif /* PDB_PROTOCOL_RX_H */
|
||||
@@ -16,10 +16,10 @@
|
||||
*/
|
||||
|
||||
#include "protocol_tx.h"
|
||||
#include "Defines.h"
|
||||
#include "fusb302b.h"
|
||||
#include "fusbpd.h"
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
#include <pd.h>
|
||||
|
||||
osThreadId ProtocolTransmit::TaskHandle = NULL;
|
||||
@@ -44,7 +44,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() {
|
||||
* we failed to send it */
|
||||
if (messagePending()) {
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_ERR);
|
||||
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR);
|
||||
/* Finish failing to send the message */
|
||||
while (messagePending()) {
|
||||
getMessage(); // Discard
|
||||
@@ -88,10 +88,6 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() {
|
||||
/* Clear MessageIDCounter */
|
||||
_tx_messageidcounter = 0;
|
||||
|
||||
/* Tell the Protocol RX thread to reset */
|
||||
ProtocolReceive::notify(PDB_EVT_PRLRX_RESET);
|
||||
taskYIELD();
|
||||
|
||||
return PRLTxConstructMessage;
|
||||
}
|
||||
|
||||
@@ -104,17 +100,12 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_mess
|
||||
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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (PolicyEngine::isPD3_0()) {
|
||||
/* If we're starting an AMS, wait for permission to transmit */
|
||||
while (fusb_get_typec_current() != fusb_sink_tx_ok) {
|
||||
vTaskDelay(TICKS_10MS);
|
||||
}
|
||||
}
|
||||
messageSending = true;
|
||||
/* Send the message to the PHY */
|
||||
fusb_send_message(&temp_msg);
|
||||
@@ -173,7 +164,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_e
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
|
||||
/* Tell the policy engine that we failed */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_ERR);
|
||||
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR);
|
||||
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
@@ -184,7 +175,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent()
|
||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||
|
||||
/* Tell the policy engine that we succeeded */
|
||||
PolicyEngine::notify(PDB_EVT_PE_TX_DONE);
|
||||
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_DONE);
|
||||
|
||||
return PRLTxWaitMessage;
|
||||
}
|
||||
@@ -257,7 +248,9 @@ void ProtocolTransmit::init() {
|
||||
|
||||
void ProtocolTransmit::pushMessage(union pd_msg *msg) {
|
||||
if (messagesWaiting) {
|
||||
xQueueSend(messagesWaiting, msg, 100);
|
||||
if (xQueueSend(messagesWaiting, msg, 100) == pdTRUE) {
|
||||
notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define PDB_PROTOCOL_TX_H
|
||||
|
||||
#include "policy_engine.h"
|
||||
#include "protocol_rx.h"
|
||||
|
||||
#include <pd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -38,7 +38,6 @@ public:
|
||||
PDB_EVT_PRLTX_I_RETRYFAIL = EVENT_MASK(2), //
|
||||
PDB_EVT_PRLTX_DISCARD = EVENT_MASK(3), //
|
||||
PDB_EVT_PRLTX_MSG_TX = EVENT_MASK(4), //
|
||||
PDB_EVT_PRLTX_START_AMS = EVENT_MASK(5), //
|
||||
};
|
||||
static void notify(Notifications notification);
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#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;
|
||||
@@ -29,9 +27,7 @@ void I2CBB::init() {
|
||||
SOFT_SDA_HIGH();
|
||||
SOFT_SCL_HIGH();
|
||||
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
|
||||
I2CSemaphore2 = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer2);
|
||||
unlock();
|
||||
unlock2();
|
||||
}
|
||||
|
||||
bool I2CBB::probe(uint8_t address) {
|
||||
@@ -291,14 +287,4 @@ void I2CBB::write_bit(uint8_t val) {
|
||||
SOFT_SCL_LOW();
|
||||
}
|
||||
|
||||
void I2CBB::unlock2() { xSemaphoreGive(I2CSemaphore2); }
|
||||
|
||||
bool I2CBB::lock2() {
|
||||
if (I2CSemaphore2 == NULL) {
|
||||
asm("bkpt");
|
||||
}
|
||||
bool a = xSemaphoreTake(I2CSemaphore2, (TickType_t)500) == pdTRUE;
|
||||
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,14 +28,10 @@ public:
|
||||
static void Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
|
||||
static void Receive(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
|
||||
static void TransmitReceive(uint16_t DevAddress, uint8_t *pData_tx, uint16_t Size_tx, uint8_t *pData_rx, uint16_t Size_rx);
|
||||
static void unlock2();
|
||||
static bool lock2();
|
||||
|
||||
private:
|
||||
static SemaphoreHandle_t I2CSemaphore;
|
||||
static StaticSemaphore_t xSemaphoreBuffer;
|
||||
static SemaphoreHandle_t I2CSemaphore2;
|
||||
static StaticSemaphore_t xSemaphoreBuffer2;
|
||||
static void unlock();
|
||||
static bool lock();
|
||||
static void start();
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* Author: Ben V. Brown
|
||||
*/
|
||||
|
||||
#include "../../configuration.h"
|
||||
#include "Translation.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "configuration.h"
|
||||
#include <OLED.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
#include "TipThermoModel.h"
|
||||
#include "../../configuration.h"
|
||||
#include "BSP.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "main.hpp"
|
||||
#include "power.hpp"
|
||||
/*
|
||||
|
||||
@@ -122,8 +122,9 @@
|
||||
#define POWER_LIMIT 0 // 0 watts default limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 5 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100
|
||||
#define TEMP_uV_LOOKUP_HAKKO
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 //
|
||||
#define TEMP_uV_LOOKUP_HAKKO //
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
@@ -133,8 +134,9 @@
|
||||
#define POWER_LIMIT 0 // 0 watts default limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 5 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100
|
||||
#define TEMP_uV_LOOKUP_HAKKO
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 // Uses TS100 resistors
|
||||
#define TEMP_uV_LOOKUP_HAKKO // Use Hakko lookup table
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80
|
||||
@@ -143,9 +145,10 @@
|
||||
#define CALIBRATION_OFFSET 900 // the adc offset in uV
|
||||
#define POWER_LIMIT 24 // 24 watts default power limit
|
||||
#define MAX_POWER_LIMIT 30 //
|
||||
#define POWER_LIMIT_STEPS 2
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80
|
||||
#define TEMP_uV_LOOKUP_TS80
|
||||
#define POWER_LIMIT_STEPS 2 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 //
|
||||
#define TEMP_uV_LOOKUP_TS80 //
|
||||
#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80P
|
||||
@@ -154,9 +157,10 @@
|
||||
#define CALIBRATION_OFFSET 1500 // the adc offset in uV
|
||||
#define POWER_LIMIT 30 // 30 watts default power limit
|
||||
#define MAX_POWER_LIMIT 35 //
|
||||
#define POWER_LIMIT_STEPS 2
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80
|
||||
#define TEMP_uV_LOOKUP_TS80
|
||||
#define POWER_LIMIT_STEPS 2 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 //
|
||||
#define TEMP_uV_LOOKUP_TS80 //
|
||||
#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
@@ -5,8 +5,8 @@
|
||||
* Authors: Ben V. Brown, David Hilton (David's Idea)
|
||||
*/
|
||||
|
||||
#include "../../configuration.h"
|
||||
#include "BSP.h"
|
||||
#include "configuration.h"
|
||||
#include "expMovingAverage.h"
|
||||
#include "stdint.h"
|
||||
#include <history.hpp>
|
||||
|
||||
@@ -81,12 +81,12 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
|
||||
return; // dont bother with small steps
|
||||
while (steps < 0) {
|
||||
QC_SeekContNeg();
|
||||
osDelay(30);
|
||||
vTaskDelay(3 * TICKS_10MS);
|
||||
steps++;
|
||||
}
|
||||
while (steps > 0) {
|
||||
QC_SeekContPlus();
|
||||
osDelay(30);
|
||||
vTaskDelay(3 * TICKS_10MS);
|
||||
steps--;
|
||||
}
|
||||
osDelay(100);
|
||||
@@ -140,7 +140,7 @@ void startQC(uint16_t divisor) {
|
||||
// Delay 1.25 seconds
|
||||
uint8_t enteredQC = 0;
|
||||
for (uint16_t i = 0; i < 200 && enteredQC == 0; i++) {
|
||||
osDelay(10); // 10mS pause
|
||||
vTaskDelay(TICKS_10MS); // 10mS pause
|
||||
if (i > 130) {
|
||||
if (QC_DM_PulledDown()) {
|
||||
enteredQC = 1;
|
||||
@@ -165,7 +165,7 @@ void startQC(uint16_t divisor) {
|
||||
QCMode = QCState::QC_3; // We have at least QC2, pray for 3
|
||||
return;
|
||||
}
|
||||
osDelay(100); // 100mS
|
||||
vTaskDelay(TICKS_100MS); // 100mS
|
||||
}
|
||||
QCMode = QCState::NOT_STARTED;
|
||||
QCTries++;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include "../../configuration.h"
|
||||
#include "BSP.h"
|
||||
#include "Setup.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include "string.h"
|
||||
volatile systemSettingsType systemSettings;
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "gui.hpp"
|
||||
#include "../../configuration.h"
|
||||
#include "Buttons.hpp"
|
||||
#include "TipThermoModel.h"
|
||||
#include "Translation.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "configuration.h"
|
||||
#include "main.hpp"
|
||||
|
||||
void gui_Menu(const menuitem *menu);
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
* Main.cpp bootstraps the device and then hands over to FreeRTOS and the threads
|
||||
*/
|
||||
|
||||
#include "main.hpp"
|
||||
#include "BSP.h"
|
||||
#include "LIS2DH12.hpp"
|
||||
#include "Settings.h"
|
||||
#include "cmsis_os.h"
|
||||
#include <MMA8652FC.hpp>
|
||||
#include <main.hpp>
|
||||
#include <power.hpp>
|
||||
#include "power.hpp"
|
||||
uint8_t DetectedAccelerometerVersion = 0;
|
||||
bool settingsWereReset = false;
|
||||
// FreeRTOS variables
|
||||
@@ -45,21 +43,23 @@ int main(void) {
|
||||
settingsWereReset = restoreSettings(); // load the settings from flash
|
||||
resetWatchdog();
|
||||
/* Create the thread(s) */
|
||||
/* definition and creation of POWTask - Power management for QC */
|
||||
osThreadStaticDef(POWTask, startPOWTask, osPriorityAboveNormal, 0, POWTaskStackSize, POWTaskBuffer, &POWTaskControlBlock);
|
||||
POWTaskHandle = osThreadCreate(osThread(POWTask), NULL);
|
||||
|
||||
/* definition and creation of GUITask - The OLED control & update*/
|
||||
osThreadStaticDef(GUITask, startGUITask, osPriorityBelowNormal, 0, GUITaskStackSize, GUITaskBuffer, &GUITaskControlBlock);
|
||||
GUITaskHandle = osThreadCreate(osThread(GUITask), NULL);
|
||||
|
||||
/* definition and creation of PIDTask - Heating control*/
|
||||
osThreadStaticDef(PIDTask, startPIDTask, osPriorityRealtime, 0, PIDTaskStackSize, PIDTaskBuffer, &PIDTaskControlBlock);
|
||||
PIDTaskHandle = osThreadCreate(osThread(PIDTask), NULL);
|
||||
|
||||
/* definition and creation of POWTask - Power management for QC */
|
||||
osThreadStaticDef(POWTask, startPOWTask, osPriorityAboveNormal, 0, POWTaskStackSize, POWTaskBuffer, &POWTaskControlBlock);
|
||||
POWTaskHandle = osThreadCreate(osThread(POWTask), NULL);
|
||||
|
||||
/* definition and creation of MOVTask - Accelerometer management */
|
||||
osThreadStaticDef(MOVTask, startMOVTask, osPriorityNormal, 0, MOVTaskStackSize, MOVTaskBuffer, &MOVTaskControlBlock);
|
||||
MOVTaskHandle = osThreadCreate(osThread(MOVTask), NULL);
|
||||
|
||||
/* definition and creation of GUITask - The OLED control & update*/
|
||||
osThreadStaticDef(GUITask, startGUITask, osPriorityBelowNormal, 0, GUITaskStackSize, GUITaskBuffer, &GUITaskControlBlock);
|
||||
GUITaskHandle = osThreadCreate(osThread(GUITask), NULL);
|
||||
|
||||
resetWatchdog();
|
||||
|
||||
/* Start scheduler */
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
extern "C" {
|
||||
#include "FreeRTOSConfig.h"
|
||||
}
|
||||
#include "../../configuration.h"
|
||||
#include "Buttons.hpp"
|
||||
#include "I2CBB.hpp"
|
||||
#include "LIS2DH12.hpp"
|
||||
@@ -15,6 +14,7 @@ extern "C" {
|
||||
#include "TipThermoModel.h"
|
||||
#include "Translation.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "configuration.h"
|
||||
#include "main.hpp"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "fusbpd.h"
|
||||
#include "main.hpp"
|
||||
#include "stdlib.h"
|
||||
#include "task.h"
|
||||
@@ -17,9 +18,20 @@
|
||||
// Small worker thread to handle power (mostly QC) related steps
|
||||
|
||||
void startPOWTask(void const *argument __unused) {
|
||||
// You have to run this once we are willing to answer PD messages
|
||||
// Setting up too early can mean that we miss the ~20ms window to respond on some chargers
|
||||
#ifdef POW_PD
|
||||
if (usb_pd_detect() == true) {
|
||||
// Spawn all of the USB-C processors
|
||||
fusb302_start_processing();
|
||||
}
|
||||
#endif
|
||||
vTaskDelay(TICKS_100MS);
|
||||
// Init any other misc sensors
|
||||
postRToSInit();
|
||||
|
||||
for (;;) {
|
||||
osDelay(TICKS_100MS); // Slow down update rate
|
||||
power_check();
|
||||
osDelay(TICKS_100MS); // Slow down update rate
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user