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_
|
#ifndef USER_BSP_PD_H_
|
||||||
#define USER_BSP_PD_H_
|
#define USER_BSP_PD_H_
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
/*
|
bool getFUS302IRQLow(); // Return true if the IRQ line is still held low
|
||||||
* 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;
|
|
||||||
#endif /* USER_BSP_PD_H_ */
|
#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_SECOND configTICK_RATE_HZ
|
||||||
#define TICKS_MIN (60 * TICKS_SECOND)
|
#define TICKS_MIN (60 * TICKS_SECOND)
|
||||||
#define TICKS_100MS (TICKS_SECOND / 10)
|
#define TICKS_100MS (TICKS_SECOND / 10)
|
||||||
|
#define TICKS_10MS (TICKS_100MS / 10)
|
||||||
#endif /* BSP_DEFINES_H_ */
|
#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 "IRQ.h"
|
||||||
|
#include "Pins.h"
|
||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Catch the IRQ that says that the conversion is done on the temperature
|
* 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
|
* 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;
|
(void)GPIO_Pin;
|
||||||
InterruptHandler::irqCallback();
|
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 "int_n.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
bool FUSB302_present = false;
|
bool FUSB302_present = false;
|
||||||
|
bool FUSB302_probed = false;
|
||||||
|
|
||||||
void power_check() {
|
void power_check() {
|
||||||
#ifdef POW_PD
|
#ifdef POW_PD
|
||||||
if (FUSB302_present) {
|
if (FUSB302_present) {
|
||||||
|
PolicyEngine::PPSTimerCallback();
|
||||||
// Cant start QC until either PD works or fails
|
// Cant start QC until either PD works or fails
|
||||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||||
return;
|
return;
|
||||||
@@ -27,7 +29,12 @@ void power_check() {
|
|||||||
}
|
}
|
||||||
uint8_t usb_pd_detect() {
|
uint8_t usb_pd_detect() {
|
||||||
#ifdef POW_PD
|
#ifdef POW_PD
|
||||||
|
if (FUSB302_probed) {
|
||||||
|
return FUSB302_present;
|
||||||
|
} else {
|
||||||
FUSB302_present = fusb302_detect();
|
FUSB302_present = fusb302_detect();
|
||||||
|
FUSB302_probed = true;
|
||||||
|
}
|
||||||
return FUSB302_present;
|
return FUSB302_present;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
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"
|
#include "task.h"
|
||||||
|
|
||||||
// Initialisation to be performed with scheduler active
|
// Initialisation to be performed with scheduler active
|
||||||
void postRToSInit() {
|
void postRToSInit() {}
|
||||||
#ifdef POW_PD
|
|
||||||
if (usb_pd_detect() == true) {
|
|
||||||
// Spawn all of the USB-C processors
|
|
||||||
fusb302_start_processing();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
#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
|
// These are unused for now
|
||||||
void I2C0_EV_IRQHandler(void) {}
|
void I2C0_EV_IRQHandler(void) {}
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
bool FUSB302_present = false;
|
bool FUSB302_present = false;
|
||||||
|
bool FUSB302_probed = false;
|
||||||
|
|
||||||
void power_check() {
|
void power_check() {
|
||||||
#ifdef POW_PD
|
#ifdef POW_PD
|
||||||
if (FUSB302_present) {
|
if (FUSB302_present) {
|
||||||
|
PolicyEngine::PPSTimerCallback();
|
||||||
// Cant start QC until either PD works or fails
|
// Cant start QC until either PD works or fails
|
||||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||||
return;
|
return;
|
||||||
@@ -27,8 +29,12 @@ void power_check() {
|
|||||||
}
|
}
|
||||||
uint8_t usb_pd_detect() {
|
uint8_t usb_pd_detect() {
|
||||||
#ifdef POW_PD
|
#ifdef POW_PD
|
||||||
|
if (FUSB302_probed) {
|
||||||
|
return FUSB302_present;
|
||||||
|
} else {
|
||||||
FUSB302_present = fusb302_detect();
|
FUSB302_present = fusb302_detect();
|
||||||
|
FUSB302_probed = true;
|
||||||
|
}
|
||||||
return FUSB302_present;
|
return FUSB302_present;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
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();
|
hall_effect_present = Si7210::init();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef POW_PD
|
|
||||||
// Spawn all of the USB-C processors
|
|
||||||
fusb302_start_processing();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
int16_t getRawHallEffect() {
|
int16_t getRawHallEffect() {
|
||||||
if (hall_effect_present) {
|
if (hall_effect_present) {
|
||||||
|
|||||||
@@ -14,65 +14,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "Model_Config.h"
|
#include "fusb302b.h"
|
||||||
#ifdef POW_PD
|
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
#include "I2C_Wrapper.hpp"
|
#include "I2C_Wrapper.hpp"
|
||||||
#include "Setup.h"
|
#include "Setup.h"
|
||||||
#include "fusb302b.h"
|
#include "fusb_user.h"
|
||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
#include <pd.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) {
|
void fusb_send_message(const union pd_msg *msg) {
|
||||||
|
|
||||||
/* Token sequences for the FUSB302B */
|
/* Token sequences for the FUSB302B */
|
||||||
@@ -122,15 +70,12 @@ void fusb_send_hardrst() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool fusb_setup() {
|
bool fusb_setup() {
|
||||||
if (!FRToSI2C::probe(FUSB302B_ADDR)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* Fully reset the FUSB302B */
|
/* Fully reset the FUSB302B */
|
||||||
fusb_write_byte(FUSB_RESET, FUSB_RESET_SW_RES);
|
fusb_write_byte(FUSB_RESET, FUSB_RESET_SW_RES);
|
||||||
osDelay(2);
|
vTaskDelay(TICKS_10MS);
|
||||||
uint8_t tries = 0;
|
uint8_t tries = 0;
|
||||||
while (!fusb_read_id()) {
|
while (!fusb_read_id()) {
|
||||||
osDelay(10);
|
vTaskDelay(TICKS_10MS);
|
||||||
tries++;
|
tries++;
|
||||||
if (tries > 5) {
|
if (tries > 5) {
|
||||||
return false; // Welp :(
|
return false; // Welp :(
|
||||||
@@ -156,12 +101,12 @@ bool fusb_setup() {
|
|||||||
|
|
||||||
/* Measure CC1 */
|
/* Measure CC1 */
|
||||||
fusb_write_byte(FUSB_SWITCHES0, 0x07);
|
fusb_write_byte(FUSB_SWITCHES0, 0x07);
|
||||||
osDelay(10);
|
vTaskDelay(TICKS_10MS);
|
||||||
uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||||
|
|
||||||
/* Measure CC2 */
|
/* Measure CC2 */
|
||||||
fusb_write_byte(FUSB_SWITCHES0, 0x0B);
|
fusb_write_byte(FUSB_SWITCHES0, 0x0B);
|
||||||
osDelay(10);
|
vTaskDelay(TICKS_10MS);
|
||||||
uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL;
|
||||||
|
|
||||||
/* Select the correct CC line for BMC signaling; also enable AUTO_CRC */
|
/* Select the correct CC line for BMC signaling; also enable AUTO_CRC */
|
||||||
@@ -210,9 +155,3 @@ bool fusb_read_id() {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
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 "fusb302b.h"
|
||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
#include "protocol_rx.h"
|
|
||||||
#include "protocol_tx.h"
|
#include "protocol_tx.h"
|
||||||
#include <fusbpd.h>
|
#include <fusbpd.h>
|
||||||
#include <pd.h>
|
#include <pd.h>
|
||||||
@@ -21,7 +21,6 @@ void fusb302_start_processing() {
|
|||||||
if (fusb_setup()) {
|
if (fusb_setup()) {
|
||||||
PolicyEngine::init();
|
PolicyEngine::init();
|
||||||
ProtocolTransmit::init();
|
ProtocolTransmit::init();
|
||||||
ProtocolReceive::init();
|
|
||||||
InterruptHandler::init();
|
InterruptHandler::init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,34 +17,63 @@
|
|||||||
|
|
||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
|
#include "BSP_PD.h"
|
||||||
#include "fusb302b.h"
|
#include "fusb302b.h"
|
||||||
#include "fusbpd.h"
|
#include "fusbpd.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
#include "protocol_rx.h"
|
|
||||||
#include "protocol_tx.h"
|
#include "protocol_tx.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include <pd.h>
|
#include <pd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
osThreadId InterruptHandler::TaskHandle = NULL;
|
volatile osThreadId InterruptHandler::TaskHandle = NULL;
|
||||||
uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize];
|
uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize];
|
||||||
osStaticThreadDef_t InterruptHandler::TaskControlBlock;
|
osStaticThreadDef_t InterruptHandler::TaskControlBlock;
|
||||||
|
union pd_msg InterruptHandler::tempMessage;
|
||||||
|
|
||||||
void InterruptHandler::init() {
|
void InterruptHandler::init() {
|
||||||
|
TaskHandle = NULL;
|
||||||
osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
|
||||||
TaskHandle = osThreadCreate(osThread(intTask), NULL);
|
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 InterruptHandler::Thread(const void *arg) {
|
||||||
(void)arg;
|
(void)arg;
|
||||||
union fusb_status status;
|
union fusb_status status;
|
||||||
while (true) {
|
for (;;) {
|
||||||
/* If the INT_N line is low */
|
// If the irq is low continue, otherwise wait for irq or timeout
|
||||||
if (xTaskNotifyWait(0x00, 0x0F, NULL, PolicyEngine::setupCompleteOrTimedOut() ? 1000 : 10) == pdPASS) {
|
if (!getFUS302IRQLow()) {
|
||||||
// delay slightly so we catch the crc with better timing
|
xTaskNotifyWait(0x00, 0x0F, NULL, TICKS_SECOND * 30);
|
||||||
osDelay(1);
|
|
||||||
}
|
}
|
||||||
/* Read the FUSB302B status and interrupt registers */
|
/* Read the FUSB302B status and interrupt registers */
|
||||||
fusb_get_status(&status);
|
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
|
/* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX
|
||||||
* thread */
|
* thread */
|
||||||
if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) {
|
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);
|
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
|
/* If the I_OCP_TEMP and OVRTEMP flags are set, tell the Policy
|
||||||
* Engine thread */
|
* Engine thread */
|
||||||
if ((status.interrupta & FUSB_INTERRUPTA_I_OCP_TEMP) && (status.status1 & FUSB_STATUS1_OVRTEMP)) {
|
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() {
|
void InterruptHandler::irqCallback() {
|
||||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
|
||||||
if (TaskHandle != NULL) {
|
if (TaskHandle != NULL) {
|
||||||
BaseType_t taskWoke = pdFALSE;
|
BaseType_t taskWoke = pdFALSE;
|
||||||
xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke);
|
xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke);
|
||||||
portYIELD_FROM_ISR(taskWoke);
|
portYIELD_FROM_ISR(taskWoke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void Thread(const void *arg);
|
static void Thread(const void *arg);
|
||||||
static osThreadId TaskHandle;
|
static volatile osThreadId TaskHandle;
|
||||||
static const size_t TaskStackSize = 1536 / 3;
|
static const size_t TaskStackSize = 1536 / 3;
|
||||||
static uint32_t TaskBuffer[TaskStackSize];
|
static uint32_t TaskBuffer[TaskStackSize];
|
||||||
static osStaticThreadDef_t TaskControlBlock;
|
static osStaticThreadDef_t TaskControlBlock;
|
||||||
@@ -44,6 +44,9 @@ private:
|
|||||||
static enum hardrst_state hardrst_hard_reset_requested();
|
static enum hardrst_state hardrst_hard_reset_requested();
|
||||||
static enum hardrst_state hardrst_wait_pe();
|
static enum hardrst_state hardrst_wait_pe();
|
||||||
static enum hardrst_state hardrst_complete();
|
static enum hardrst_state hardrst_complete();
|
||||||
|
// Mesage rx
|
||||||
|
static void readPendingMessage();
|
||||||
|
static union pd_msg tempMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PDB_INT_N_OLD_H */
|
#endif /* PDB_INT_N_OLD_H */
|
||||||
|
|||||||
@@ -271,13 +271,13 @@
|
|||||||
* Where a range is specified, the middle of the range (rounded down to the
|
* Where a range is specified, the middle of the range (rounded down to the
|
||||||
* nearest millisecond) is used.
|
* nearest millisecond) is used.
|
||||||
*/
|
*/
|
||||||
#define PD_T_CHUNKING_NOT_SUPPORTED (450)
|
#define PD_T_CHUNKING_NOT_SUPPORTED (TICKS_SECOND / 2)
|
||||||
#define PD_T_HARD_RESET_COMPLETE (1000)
|
#define PD_T_HARD_RESET_COMPLETE (1 * TICKS_SECOND)
|
||||||
#define PD_T_PS_TRANSITION (5000)
|
#define PD_T_PS_TRANSITION (5 * TICKS_SECOND)
|
||||||
#define PD_T_SENDER_RESPONSE (2700)
|
#define PD_T_SENDER_RESPONSE (27 * TICKS_100MS)
|
||||||
#define PD_T_SINK_REQUEST (1000)
|
#define PD_T_SINK_REQUEST (1 * TICKS_SECOND)
|
||||||
#define PD_T_TYPEC_SINK_WAIT_CAP (1000)
|
#define PD_T_TYPEC_SINK_WAIT_CAP (1 * TICKS_SECOND)
|
||||||
#define PD_T_PD_DEBOUNCE (2000)
|
#define PD_T_PD_DEBOUNCE (2 * TICKS_SECOND)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Counter maximums
|
* Counter maximums
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
#define PDB_CONF_H
|
#define PDB_CONF_H
|
||||||
|
|
||||||
/* Number of messages in the message pool */
|
/* 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 EVENT_MASK(x) (1 << x)
|
||||||
#define eventmask_t uint32_t
|
|
||||||
/* PD Buddy thread priorities */
|
/* PD Buddy thread priorities */
|
||||||
#define PDB_PRIO_PE (osPriorityNormal)
|
#define PDB_PRIO_PE (osPriorityAboveNormal)
|
||||||
#define PDB_PRIO_PRL (osPriorityBelowNormal)
|
#define PDB_PRIO_PRL (osPriorityAboveNormal)
|
||||||
#define PDB_PRIO_PRL_INT_N (osPriorityLow)
|
#define PDB_PRIO_PRL_INT_N (osPriorityAboveNormal)
|
||||||
|
|
||||||
#endif /* PDB_CONF_H */
|
#endif /* PDB_CONF_H */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
|
#include "Defines.h"
|
||||||
#include "fusb302b.h"
|
#include "fusb302b.h"
|
||||||
#include "int_n.h"
|
#include "int_n.h"
|
||||||
#include "protocol_tx.h"
|
#include "protocol_tx.h"
|
||||||
@@ -31,7 +32,6 @@ bool PolicyEngine::_explicit_contract;
|
|||||||
int8_t PolicyEngine::_hard_reset_counter;
|
int8_t PolicyEngine::_hard_reset_counter;
|
||||||
int8_t PolicyEngine::_old_tcc_match;
|
int8_t PolicyEngine::_old_tcc_match;
|
||||||
uint8_t PolicyEngine::_pps_index;
|
uint8_t PolicyEngine::_pps_index;
|
||||||
uint8_t PolicyEngine::_last_pps;
|
|
||||||
osThreadId PolicyEngine::TaskHandle = NULL;
|
osThreadId PolicyEngine::TaskHandle = NULL;
|
||||||
uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize];
|
uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize];
|
||||||
osStaticThreadDef_t PolicyEngine::TaskControlBlock;
|
osStaticThreadDef_t PolicyEngine::TaskControlBlock;
|
||||||
@@ -43,6 +43,8 @@ uint8_t PolicyEngine::ucQueueStorageArea[PDB_MSG_POOL_
|
|||||||
QueueHandle_t PolicyEngine::messagesWaiting = NULL;
|
QueueHandle_t PolicyEngine::messagesWaiting = NULL;
|
||||||
EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL;
|
EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL;
|
||||||
StaticEventGroup_t PolicyEngine::xCreatedEventGroup;
|
StaticEventGroup_t PolicyEngine::xCreatedEventGroup;
|
||||||
|
bool PolicyEngine::PPSTimerEnabled = false;
|
||||||
|
TickType_t PolicyEngine::PPSTimeLastEvent = 0;
|
||||||
void PolicyEngine::init() {
|
void PolicyEngine::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);
|
||||||
// Create static thread at PDB_PRIO_PE priority
|
// Create static thread at PDB_PRIO_PE priority
|
||||||
@@ -51,9 +53,10 @@ void PolicyEngine::init() {
|
|||||||
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::notify(uint32_t notification) {
|
void PolicyEngine::notify(PolicyEngine::Notifications notification) {
|
||||||
|
EventBits_t val = (EventBits_t)notification;
|
||||||
if (xEventGroupHandle != NULL) {
|
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 */
|
/* Initialize the old_tcc_match */
|
||||||
_old_tcc_match = -1;
|
_old_tcc_match = -1;
|
||||||
/* Initialize the pps_index */
|
/* Initialize the pps_index */
|
||||||
_pps_index = 8;
|
_pps_index = 0xFF;
|
||||||
/* Initialize the last_pps */
|
|
||||||
_last_pps = 8;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Loop based on state
|
// Loop based on state
|
||||||
@@ -133,7 +134,7 @@ void PolicyEngine::pe_task(const void *arg) {
|
|||||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() {
|
||||||
/* We don't have an explicit contract currently */
|
/* We don't have an explicit contract currently */
|
||||||
_explicit_contract = false;
|
_explicit_contract = false;
|
||||||
|
PPSTimerEnabled = false;
|
||||||
// If desired could send an alert that PD is starting
|
// If desired could send an alert that PD is starting
|
||||||
|
|
||||||
/* No need to reset the protocol layer here. There are two ways into this
|
/* 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() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() {
|
||||||
/* Fetch a message from the protocol layer */
|
/* Fetch a message from the protocol layer */
|
||||||
eventmask_t evt = 0;
|
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,
|
||||||
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,
|
|
||||||
// Wait for cap timeout
|
// Wait for cap timeout
|
||||||
PD_T_TYPEC_SINK_WAIT_CAP);
|
PD_T_TYPEC_SINK_WAIT_CAP);
|
||||||
}
|
|
||||||
/* If we timed out waiting for Source_Capabilities, send a hard reset */
|
/* If we timed out waiting for Source_Capabilities, send a hard reset */
|
||||||
if (evt == 0) {
|
if (evt == 0) {
|
||||||
return PESinkHardReset;
|
return PESinkHardReset;
|
||||||
}
|
}
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkWaitCap;
|
||||||
}
|
}
|
||||||
/* If we're too hot, we shouldn't negotiate power yet */
|
/* 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;
|
return PESinkWaitCap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we got a message */
|
/* 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 */
|
/* 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 we got a Source_Capabilities message, read it. */
|
||||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||||
/* First, determine what PD revision we're using */
|
/* First, determine what PD revision we're using */
|
||||||
@@ -194,15 +191,13 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PESinkEvalCap;
|
return PESinkEvalCap;
|
||||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
|
||||||
}
|
}
|
||||||
evt = 0;
|
|
||||||
}
|
}
|
||||||
return PESinkWaitCap; // wait for more messages?
|
return PESinkWaitCap; // wait for more messages?
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we failed to get a message, send a hard reset */
|
/* If we failed to get a message, wait longer */
|
||||||
return PESinkHardReset;
|
return PESinkWaitCap;
|
||||||
}
|
}
|
||||||
|
|
||||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
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. */
|
* PE_SNK_Select_Cap. */
|
||||||
/* Start by assuming we won't find a PPS APDO (set the index greater
|
/* Start by assuming we won't find a PPS APDO (set the index greater
|
||||||
* than the maximum possible) */
|
* 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 */
|
/* Search for the first PPS APDO */
|
||||||
for (int i = 0; i < PD_NUMOBJ_GET(&tempMessage); i++) {
|
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) {
|
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;
|
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 */
|
/* Ask the DPM what to request */
|
||||||
if (pdbs_dpm_evaluate_capability(&tempMessage, &_last_dpm_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;
|
return PESinkSelectCap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,29 +237,28 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
|||||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||||
|
|
||||||
/* Transmit the request */
|
/* Transmit the request */
|
||||||
waitForEvent(0xFFFF, 0); // clear pending
|
waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL, 0); // clear pending
|
||||||
ProtocolTransmit::pushMessage(&_last_dpm_request);
|
ProtocolTransmit::pushMessage(&_last_dpm_request);
|
||||||
// Send indication that there is a message pending
|
// Send indication that there is a message pending
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a hard reset */
|
/* 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;
|
return PESinkHardReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for a response */
|
/* 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 we got reset signaling, transition to default */
|
||||||
if (evt & PDB_EVT_PE_RESET) {
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||||
return PESinkTransitionDefault;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If we didn't get a response before the timeout, send a hard reset */
|
/* If we didn't get a response before the timeout, send a hard reset */
|
||||||
if (evt == 0) {
|
if (evt == 0) {
|
||||||
return PESinkHardReset;
|
return PESinkSoftReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the response message */
|
/* Get the response message */
|
||||||
@@ -265,7 +266,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
|||||||
readMessage();
|
readMessage();
|
||||||
/* If the source accepted our request, wait for the new power */
|
/* If the source accepted our request, wait for the new power */
|
||||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkTransitionSink;
|
return PESinkTransitionSink;
|
||||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
/* 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) {
|
} 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;
|
return PESinkReady;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return PESinkSendSoftReset;
|
return PESinkSoftReset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PESinkHardReset;
|
return PESinkHardReset;
|
||||||
@@ -288,111 +288,97 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
|||||||
|
|
||||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() {
|
||||||
/* Wait for the PS_RDY message */
|
/* 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 we got reset signaling, transition to default */
|
||||||
if (evt & PDB_EVT_PE_RESET) {
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||||
return PESinkTransitionDefault;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If no message was received, send a hard reset */
|
|
||||||
if (evt == 0) {
|
|
||||||
return PESinkHardReset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we received a message, read it */
|
/* If we received a message, read it */
|
||||||
if (messageWaiting()) {
|
while (messageWaiting()) {
|
||||||
readMessage();
|
readMessage();
|
||||||
/* If we got a PS_RDY, handle it */
|
/* If we got a PS_RDY, handle it */
|
||||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PS_RDY && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PS_RDY && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
/* We just finished negotiating an explicit contract */
|
/* We just finished negotiating an explicit contract */
|
||||||
_explicit_contract = true;
|
_explicit_contract = true;
|
||||||
|
|
||||||
/* Set the output appropriately */
|
/* Negotiation finished */
|
||||||
pdbs_dpm_transition_requested();
|
pdbs_dpm_transition_requested();
|
||||||
|
|
||||||
return PESinkReady;
|
return PESinkReady;
|
||||||
/* If there was a protocol error, send a hard reset */
|
/* 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 PESinkSoftReset;
|
||||||
return PESinkHardReset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
||||||
eventmask_t evt;
|
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL);
|
||||||
|
/* If SinkPPSPeriodicTimer ran out, send a new request */
|
||||||
/* Wait for an event */
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_PPS_REQUEST) {
|
||||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP);
|
return PESinkSelectCap;
|
||||||
|
}
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we overheated, send a hard reset */
|
/* 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;
|
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 we received a message */
|
||||||
if (evt & PDB_EVT_PE_MSG_RX) {
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_MSG_RX) {
|
||||||
if (messageWaiting()) {
|
if (messageWaiting()) {
|
||||||
readMessage();
|
readMessage();
|
||||||
/* Ignore vendor-defined messages */
|
/* Ignore vendor-defined messages */
|
||||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VENDOR_DEFINED && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VENDOR_DEFINED && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||||
|
|
||||||
return PESinkReady;
|
return PESinkReady;
|
||||||
/* Ignore Ping messages */
|
/* Ignore Ping messages */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PING && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PING && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkReady;
|
return PESinkReady;
|
||||||
/* DR_Swap messages are not supported */
|
/* DR_Swap messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_DR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_DR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* Get_Source_Cap messages are not supported */
|
/* Get_Source_Cap messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SOURCE_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SOURCE_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* PR_Swap messages are not supported */
|
/* PR_Swap messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* VCONN_Swap messages are not supported */
|
/* VCONN_Swap messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VCONN_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VCONN_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* Request messages are not supported */
|
/* Request messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REQUEST && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REQUEST && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* Sink_Capabilities messages are not supported */
|
/* Sink_Capabilities messages are not supported */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SINK_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SINK_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
||||||
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
/* Handle GotoMin messages */
|
/* Handle GotoMin messages */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GOTOMIN && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GOTOMIN && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
/* GiveBack is not supported */
|
|
||||||
return PESinkSendNotSupported;
|
return PESinkSendNotSupported;
|
||||||
|
|
||||||
/* Evaluate new Source_Capabilities */
|
/* Evaluate new Source_Capabilities */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) {
|
} 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;
|
return PESinkEvalCap;
|
||||||
/* Give sink capabilities when asked */
|
/* Give sink capabilities when asked */
|
||||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SINK_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SINK_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkGiveSinkCap;
|
return PESinkGiveSinkCap;
|
||||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
/* 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) {
|
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||||
|
|
||||||
return PESinkSoftReset;
|
return PESinkSoftReset;
|
||||||
/* PD 3.0 messges */
|
/* PD 3.0 messges */
|
||||||
} else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
} 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;
|
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);
|
get_source_cap->hdr = hdr_template | PD_MSGTYPE_GET_SOURCE_CAP | PD_NUMOBJ(0);
|
||||||
/* Transmit the Get_Source_Cap */
|
/* Transmit the Get_Source_Cap */
|
||||||
ProtocolTransmit::pushMessage(get_source_cap);
|
ProtocolTransmit::pushMessage(get_source_cap);
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
/* Free the sent message */
|
/* Free the sent message */
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a hard reset */
|
/* 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;
|
return PESinkHardReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,17 +433,16 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_give_sink_cap() {
|
|||||||
|
|
||||||
/* Transmit our capabilities */
|
/* Transmit our capabilities */
|
||||||
ProtocolTransmit::pushMessage(snk_cap);
|
ProtocolTransmit::pushMessage(snk_cap);
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
|
|
||||||
/* Free the Sink_Capabilities message */
|
/* Free the Sink_Capabilities message */
|
||||||
|
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a hard reset */
|
/* 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;
|
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);
|
accept.hdr = hdr_template | PD_MSGTYPE_ACCEPT | PD_NUMOBJ(0);
|
||||||
/* Transmit the Accept */
|
/* Transmit the Accept */
|
||||||
ProtocolTransmit::pushMessage(&accept);
|
ProtocolTransmit::pushMessage(&accept);
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
/* Free the sent message */
|
/* Free the sent message */
|
||||||
|
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a hard reset */
|
/* 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;
|
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);
|
softrst->hdr = hdr_template | PD_MSGTYPE_SOFT_RESET | PD_NUMOBJ(0);
|
||||||
/* Transmit the soft reset */
|
/* Transmit the soft reset */
|
||||||
ProtocolTransmit::pushMessage(softrst);
|
ProtocolTransmit::pushMessage(softrst);
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a hard reset */
|
/* 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;
|
return PESinkHardReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for a response */
|
/* 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 we got reset signaling, transition to default */
|
||||||
if (evt & PDB_EVT_PE_RESET) {
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||||
return PESinkTransitionDefault;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If we didn't get a response before the timeout, send a hard reset */
|
/* 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() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() {
|
||||||
/* Get a message object */
|
/* Get a message object */
|
||||||
union pd_msg *not_supported = &tempMessage;
|
|
||||||
|
|
||||||
if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_2_0) {
|
if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_2_0) {
|
||||||
/* Make a Reject message */
|
/* 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) {
|
} else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
||||||
/* Make a Not_Supported message */
|
/* 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 */
|
/* Transmit the message */
|
||||||
ProtocolTransmit::pushMessage(not_supported);
|
ProtocolTransmit::pushMessage(&tempMessage);
|
||||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
|
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);
|
||||||
eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET);
|
|
||||||
|
|
||||||
/* If we got reset signaling, transition to default */
|
/* 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;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
/* If the message transmission failed, send a soft reset */
|
/* 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;
|
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() {
|
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_chunk_received() {
|
||||||
|
|
||||||
/* Wait for tChunkingNotSupported */
|
/* 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 we got reset signaling, transition to default */
|
||||||
if (evt & PDB_EVT_PE_RESET) {
|
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
|
||||||
return PESinkTransitionDefault;
|
return PESinkTransitionDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +605,23 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_source_unresponsive() {
|
|||||||
return PESinkSourceUnresponsive;
|
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; }
|
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 {
|
class PolicyEngine {
|
||||||
public:
|
public:
|
||||||
// Sets up internal state and registers the thread
|
// Sets up internal state and registers the thread
|
||||||
static void init();
|
static void init();
|
||||||
// Push an incoming message to the Policy Engine
|
// Push an incoming message to the Policy Engine
|
||||||
static void handleMessage(union pd_msg *msg);
|
static void handleMessage(union pd_msg *msg);
|
||||||
// Send a notification
|
|
||||||
static void notify(uint32_t notification);
|
|
||||||
// Returns true if headers indicate PD3.0 compliant
|
// Returns true if headers indicate PD3.0 compliant
|
||||||
static bool isPD3_0();
|
static bool isPD3_0();
|
||||||
static bool setupCompleteOrTimedOut() {
|
static bool setupCompleteOrTimedOut() {
|
||||||
@@ -53,7 +43,30 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Has pd negotiation completed
|
// 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:
|
private:
|
||||||
static bool pdNegotiationComplete;
|
static bool pdNegotiationComplete;
|
||||||
@@ -72,17 +85,16 @@ private:
|
|||||||
static int8_t _old_tcc_match;
|
static int8_t _old_tcc_match;
|
||||||
/* The index of the first PPS APDO */
|
/* The index of the first PPS APDO */
|
||||||
static uint8_t _pps_index;
|
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);
|
static void pe_task(const void *arg);
|
||||||
enum policy_engine_state {
|
enum policy_engine_state {
|
||||||
PESinkStartup,
|
PESinkStartup,
|
||||||
PESinkDiscovery,
|
PESinkDiscovery,
|
||||||
PESinkWaitCap,
|
PESinkWaitCap,
|
||||||
PESinkEvalCap,
|
PESinkEvalCap,
|
||||||
PESinkSelectCap,
|
PESinkSelectCap, // 4
|
||||||
PESinkTransitionSink,
|
PESinkTransitionSink, // 5
|
||||||
PESinkReady,
|
PESinkReady, // 6
|
||||||
PESinkGetSourceCap,
|
PESinkGetSourceCap,
|
||||||
PESinkGiveSinkCap,
|
PESinkGiveSinkCap,
|
||||||
PESinkHardReset,
|
PESinkHardReset,
|
||||||
@@ -113,7 +125,7 @@ private:
|
|||||||
static enum policy_engine_state pe_sink_source_unresponsive();
|
static enum policy_engine_state pe_sink_source_unresponsive();
|
||||||
static EventGroupHandle_t xEventGroupHandle;
|
static EventGroupHandle_t xEventGroupHandle;
|
||||||
static StaticEventGroup_t xCreatedEventGroup;
|
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
|
// Task resources
|
||||||
static osThreadId TaskHandle;
|
static osThreadId TaskHandle;
|
||||||
static const size_t TaskStackSize = 2048 / 4;
|
static const size_t TaskStackSize = 2048 / 4;
|
||||||
@@ -131,6 +143,8 @@ private:
|
|||||||
static bool messageWaiting();
|
static bool messageWaiting();
|
||||||
// Read a pending message into the temp message
|
// Read a pending message into the temp message
|
||||||
static bool readMessage();
|
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
|
// These callbacks are called to implement the logic for the iron to select the desired voltage
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
* Author: Ralim
|
* Author: Ralim
|
||||||
*/
|
*/
|
||||||
#include "BSP_PD.h"
|
#include "BSP_PD.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "pd.h"
|
#include "pd.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
|
|
||||||
/* The current draw when the output is disabled */
|
/* 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,
|
* Find the index of the first PDO from capabilities in the voltage range,
|
||||||
* using the desired order.
|
* using the desired order.
|
||||||
@@ -54,52 +56,88 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
|
|||||||
/* Make sure we have configuration */
|
/* Make sure we have configuration */
|
||||||
/* Look at the PDOs to see if one matches our desires */
|
/* Look at the PDOs to see if one matches our desires */
|
||||||
// Look against USB_PD_Desired_Levels to select in order of preference
|
// 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++) {
|
for (uint8_t i = 0; i < numobj; i++) {
|
||||||
/* If we have a fixed PDO, its V equals our desired V, and its I is
|
/* If we have a fixed PDO, its V equals our desired V, and its I is
|
||||||
* at least our desired I */
|
* at least our desired I */
|
||||||
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||||
// This is a fixed PDO entry
|
// This is a fixed PDO entry
|
||||||
int voltage = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i]));
|
// Evaluate if it can produve sufficient current based on the tipResistance (ohms*10)
|
||||||
int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]);
|
// V=I*R -> V/I => minimum resistance, if our tip resistance is >= this then we can use this supply
|
||||||
uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel * 2) + 0];
|
|
||||||
uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel * 2) + 1];
|
int voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); // voltage in mV units
|
||||||
// As pd stores current in 10mA increments, divide by 10
|
int current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // current in 10mA units
|
||||||
desiredminCurrent /= 10;
|
int min_resistance_ohmsx10 = voltage_mv / current_a_x100;
|
||||||
if (voltage == desiredVoltage) {
|
if (voltage_mv <= (USB_PD_VMAX * 1000)) {
|
||||||
if (current >= desiredminCurrent) {
|
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 */
|
/* We got what we wanted, so build a request for that */
|
||||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||||
|
if (bestIsPPS) {
|
||||||
/* GiveBack disabled */
|
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);
|
||||||
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);
|
} else {
|
||||||
// We support usb comms (ish)
|
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);
|
||||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
}
|
||||||
|
// We dont do usb
|
||||||
|
// request->obj[0] |= PD_RDO_USB_COMMS;
|
||||||
|
|
||||||
/* Update requested voltage */
|
/* Update requested voltage */
|
||||||
_requested_voltage = voltage;
|
_requested_voltage = bestIndexVoltage;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
/* Nothing matched (or no configuration), so get 5 V at low current */
|
/* Nothing matched (or no configuration), so get 5 V at low current */
|
||||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
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);
|
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
|
/* If the output is enabled and we got here, it must be a capability mismatch. */
|
||||||
* mismatch. */
|
|
||||||
if (pdNegotiationComplete) {
|
if (pdNegotiationComplete) {
|
||||||
request->obj[0] |= PD_RDO_CAP_MISMATCH;
|
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 */
|
/* Update requested voltage */
|
||||||
_requested_voltage = 5000;
|
_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) {
|
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);
|
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 */
|
/* Get the current we want */
|
||||||
uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps
|
uint16_t voltage = USB_PD_VMAX * 1000; // in mv
|
||||||
uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv
|
if (_requested_voltage != 5000) {
|
||||||
|
voltage = _requested_voltage;
|
||||||
|
}
|
||||||
|
uint16_t current = (voltage) / tipResistance; // In centi-amps
|
||||||
|
|
||||||
/* Add a PDO for the desired power. */
|
/* 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);
|
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[2] ^= cap->obj[1];
|
||||||
cap->obj[1] ^= cap->obj[2];
|
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. */
|
/* 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() {
|
void PolicyEngine::pdbs_dpm_transition_default() {
|
||||||
/* Cast the dpm_data to the right type */
|
|
||||||
|
|
||||||
/* Pretend we requested 5 V */
|
/* Pretend we requested 5 V */
|
||||||
current_voltage_mv = 5000;
|
current_voltage_mv = 5000;
|
||||||
@@ -175,12 +221,7 @@ void PolicyEngine::pdbs_dpm_transition_default() {
|
|||||||
pdNegotiationComplete = false;
|
pdNegotiationComplete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::pdbs_dpm_transition_requested() {
|
void PolicyEngine::pdbs_dpm_transition_requested() { pdNegotiationComplete = true; }
|
||||||
/* Cast the dpm_data to the right type */
|
|
||||||
pdNegotiationComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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 "protocol_tx.h"
|
||||||
|
#include "Defines.h"
|
||||||
#include "fusb302b.h"
|
#include "fusb302b.h"
|
||||||
#include "fusbpd.h"
|
#include "fusbpd.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
#include "protocol_rx.h"
|
|
||||||
#include <pd.h>
|
#include <pd.h>
|
||||||
|
|
||||||
osThreadId ProtocolTransmit::TaskHandle = NULL;
|
osThreadId ProtocolTransmit::TaskHandle = NULL;
|
||||||
@@ -44,7 +44,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() {
|
|||||||
* we failed to send it */
|
* we failed to send it */
|
||||||
if (messagePending()) {
|
if (messagePending()) {
|
||||||
/* Tell the policy engine that we failed */
|
/* 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 */
|
/* Finish failing to send the message */
|
||||||
while (messagePending()) {
|
while (messagePending()) {
|
||||||
getMessage(); // Discard
|
getMessage(); // Discard
|
||||||
@@ -88,10 +88,6 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() {
|
|||||||
/* Clear MessageIDCounter */
|
/* Clear MessageIDCounter */
|
||||||
_tx_messageidcounter = 0;
|
_tx_messageidcounter = 0;
|
||||||
|
|
||||||
/* Tell the Protocol RX thread to reset */
|
|
||||||
ProtocolReceive::notify(PDB_EVT_PRLRX_RESET);
|
|
||||||
taskYIELD();
|
|
||||||
|
|
||||||
return PRLTxConstructMessage;
|
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;
|
temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
|
||||||
|
|
||||||
/* PD 3.0 collision avoidance */
|
/* PD 3.0 collision avoidance */
|
||||||
// if (PolicyEngine::isPD3_0()) {
|
if (PolicyEngine::isPD3_0()) {
|
||||||
// /* If we're starting an AMS, wait for permission to transmit */
|
/* If we're starting an AMS, wait for permission to transmit */
|
||||||
// evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS,
|
while (fusb_get_typec_current() != fusb_sink_tx_ok) {
|
||||||
// 0);
|
vTaskDelay(TICKS_10MS);
|
||||||
// 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;
|
messageSending = true;
|
||||||
/* Send the message to the PHY */
|
/* Send the message to the PHY */
|
||||||
fusb_send_message(&temp_msg);
|
fusb_send_message(&temp_msg);
|
||||||
@@ -173,7 +164,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_e
|
|||||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||||
|
|
||||||
/* Tell the policy engine that we failed */
|
/* 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;
|
return PRLTxWaitMessage;
|
||||||
}
|
}
|
||||||
@@ -184,7 +175,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent()
|
|||||||
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
|
||||||
|
|
||||||
/* Tell the policy engine that we succeeded */
|
/* 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;
|
return PRLTxWaitMessage;
|
||||||
}
|
}
|
||||||
@@ -257,7 +248,9 @@ void ProtocolTransmit::init() {
|
|||||||
|
|
||||||
void ProtocolTransmit::pushMessage(union pd_msg *msg) {
|
void ProtocolTransmit::pushMessage(union pd_msg *msg) {
|
||||||
if (messagesWaiting) {
|
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
|
#define PDB_PROTOCOL_TX_H
|
||||||
|
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
#include "protocol_rx.h"
|
|
||||||
#include <pd.h>
|
#include <pd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -38,7 +38,6 @@ public:
|
|||||||
PDB_EVT_PRLTX_I_RETRYFAIL = EVENT_MASK(2), //
|
PDB_EVT_PRLTX_I_RETRYFAIL = EVENT_MASK(2), //
|
||||||
PDB_EVT_PRLTX_DISCARD = EVENT_MASK(3), //
|
PDB_EVT_PRLTX_DISCARD = EVENT_MASK(3), //
|
||||||
PDB_EVT_PRLTX_MSG_TX = EVENT_MASK(4), //
|
PDB_EVT_PRLTX_MSG_TX = EVENT_MASK(4), //
|
||||||
PDB_EVT_PRLTX_START_AMS = EVENT_MASK(5), //
|
|
||||||
};
|
};
|
||||||
static void notify(Notifications notification);
|
static void notify(Notifications notification);
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
#include <I2CBB.hpp>
|
#include <I2CBB.hpp>
|
||||||
SemaphoreHandle_t I2CBB::I2CSemaphore = NULL;
|
SemaphoreHandle_t I2CBB::I2CSemaphore = NULL;
|
||||||
StaticSemaphore_t I2CBB::xSemaphoreBuffer;
|
StaticSemaphore_t I2CBB::xSemaphoreBuffer;
|
||||||
SemaphoreHandle_t I2CBB::I2CSemaphore2 = NULL;
|
|
||||||
StaticSemaphore_t I2CBB::xSemaphoreBuffer2;
|
|
||||||
void I2CBB::init() {
|
void I2CBB::init() {
|
||||||
// Set GPIO's to output open drain
|
// Set GPIO's to output open drain
|
||||||
GPIO_InitTypeDef GPIO_InitStruct;
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||||||
@@ -29,9 +27,7 @@ void I2CBB::init() {
|
|||||||
SOFT_SDA_HIGH();
|
SOFT_SDA_HIGH();
|
||||||
SOFT_SCL_HIGH();
|
SOFT_SCL_HIGH();
|
||||||
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
|
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
|
||||||
I2CSemaphore2 = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer2);
|
|
||||||
unlock();
|
unlock();
|
||||||
unlock2();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2CBB::probe(uint8_t address) {
|
bool I2CBB::probe(uint8_t address) {
|
||||||
@@ -291,14 +287,4 @@ void I2CBB::write_bit(uint8_t val) {
|
|||||||
SOFT_SCL_LOW();
|
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
|
#endif
|
||||||
|
|||||||
@@ -28,14 +28,10 @@ public:
|
|||||||
static void Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
|
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 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 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:
|
private:
|
||||||
static SemaphoreHandle_t I2CSemaphore;
|
static SemaphoreHandle_t I2CSemaphore;
|
||||||
static StaticSemaphore_t xSemaphoreBuffer;
|
static StaticSemaphore_t xSemaphoreBuffer;
|
||||||
static SemaphoreHandle_t I2CSemaphore2;
|
|
||||||
static StaticSemaphore_t xSemaphoreBuffer2;
|
|
||||||
static void unlock();
|
static void unlock();
|
||||||
static bool lock();
|
static bool lock();
|
||||||
static void start();
|
static void start();
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
* Author: Ben V. Brown
|
* Author: Ben V. Brown
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include <OLED.hpp>
|
#include <OLED.hpp>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TipThermoModel.h"
|
#include "TipThermoModel.h"
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
#include "power.hpp"
|
#include "power.hpp"
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -122,8 +122,9 @@
|
|||||||
#define POWER_LIMIT 0 // 0 watts default limit
|
#define POWER_LIMIT 0 // 0 watts default limit
|
||||||
#define MAX_POWER_LIMIT 65 //
|
#define MAX_POWER_LIMIT 65 //
|
||||||
#define POWER_LIMIT_STEPS 5 //
|
#define POWER_LIMIT_STEPS 5 //
|
||||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100
|
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 //
|
||||||
#define TEMP_uV_LOOKUP_HAKKO
|
#define TEMP_uV_LOOKUP_HAKKO //
|
||||||
|
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODEL_Pinecil
|
#ifdef MODEL_Pinecil
|
||||||
@@ -133,8 +134,9 @@
|
|||||||
#define POWER_LIMIT 0 // 0 watts default limit
|
#define POWER_LIMIT 0 // 0 watts default limit
|
||||||
#define MAX_POWER_LIMIT 65 //
|
#define MAX_POWER_LIMIT 65 //
|
||||||
#define POWER_LIMIT_STEPS 5 //
|
#define POWER_LIMIT_STEPS 5 //
|
||||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100
|
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 // Uses TS100 resistors
|
||||||
#define TEMP_uV_LOOKUP_HAKKO
|
#define TEMP_uV_LOOKUP_HAKKO // Use Hakko lookup table
|
||||||
|
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODEL_TS80
|
#ifdef MODEL_TS80
|
||||||
@@ -143,9 +145,10 @@
|
|||||||
#define CALIBRATION_OFFSET 900 // the adc offset in uV
|
#define CALIBRATION_OFFSET 900 // the adc offset in uV
|
||||||
#define POWER_LIMIT 24 // 24 watts default power limit
|
#define POWER_LIMIT 24 // 24 watts default power limit
|
||||||
#define MAX_POWER_LIMIT 30 //
|
#define MAX_POWER_LIMIT 30 //
|
||||||
#define POWER_LIMIT_STEPS 2
|
#define POWER_LIMIT_STEPS 2 //
|
||||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80
|
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 //
|
||||||
#define TEMP_uV_LOOKUP_TS80
|
#define TEMP_uV_LOOKUP_TS80 //
|
||||||
|
#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODEL_TS80P
|
#ifdef MODEL_TS80P
|
||||||
@@ -154,9 +157,10 @@
|
|||||||
#define CALIBRATION_OFFSET 1500 // the adc offset in uV
|
#define CALIBRATION_OFFSET 1500 // the adc offset in uV
|
||||||
#define POWER_LIMIT 30 // 30 watts default power limit
|
#define POWER_LIMIT 30 // 30 watts default power limit
|
||||||
#define MAX_POWER_LIMIT 35 //
|
#define MAX_POWER_LIMIT 35 //
|
||||||
#define POWER_LIMIT_STEPS 2
|
#define POWER_LIMIT_STEPS 2 //
|
||||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80
|
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 //
|
||||||
#define TEMP_uV_LOOKUP_TS80
|
#define TEMP_uV_LOOKUP_TS80 //
|
||||||
|
#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODEL_TS100
|
#ifdef MODEL_TS100
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
* Authors: Ben V. Brown, David Hilton (David's Idea)
|
* Authors: Ben V. Brown, David Hilton (David's Idea)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "expMovingAverage.h"
|
#include "expMovingAverage.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
#include <history.hpp>
|
#include <history.hpp>
|
||||||
|
|||||||
@@ -81,12 +81,12 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
|
|||||||
return; // dont bother with small steps
|
return; // dont bother with small steps
|
||||||
while (steps < 0) {
|
while (steps < 0) {
|
||||||
QC_SeekContNeg();
|
QC_SeekContNeg();
|
||||||
osDelay(30);
|
vTaskDelay(3 * TICKS_10MS);
|
||||||
steps++;
|
steps++;
|
||||||
}
|
}
|
||||||
while (steps > 0) {
|
while (steps > 0) {
|
||||||
QC_SeekContPlus();
|
QC_SeekContPlus();
|
||||||
osDelay(30);
|
vTaskDelay(3 * TICKS_10MS);
|
||||||
steps--;
|
steps--;
|
||||||
}
|
}
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
@@ -140,7 +140,7 @@ void startQC(uint16_t divisor) {
|
|||||||
// Delay 1.25 seconds
|
// Delay 1.25 seconds
|
||||||
uint8_t enteredQC = 0;
|
uint8_t enteredQC = 0;
|
||||||
for (uint16_t i = 0; i < 200 && enteredQC == 0; i++) {
|
for (uint16_t i = 0; i < 200 && enteredQC == 0; i++) {
|
||||||
osDelay(10); // 10mS pause
|
vTaskDelay(TICKS_10MS); // 10mS pause
|
||||||
if (i > 130) {
|
if (i > 130) {
|
||||||
if (QC_DM_PulledDown()) {
|
if (QC_DM_PulledDown()) {
|
||||||
enteredQC = 1;
|
enteredQC = 1;
|
||||||
@@ -165,7 +165,7 @@ void startQC(uint16_t divisor) {
|
|||||||
QCMode = QCState::QC_3; // We have at least QC2, pray for 3
|
QCMode = QCState::QC_3; // We have at least QC2, pray for 3
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
osDelay(100); // 100mS
|
vTaskDelay(TICKS_100MS); // 100mS
|
||||||
}
|
}
|
||||||
QCMode = QCState::NOT_STARTED;
|
QCMode = QCState::NOT_STARTED;
|
||||||
QCTries++;
|
QCTries++;
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
#include "Setup.h"
|
#include "Setup.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
volatile systemSettingsType systemSettings;
|
volatile systemSettingsType systemSettings;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "Buttons.hpp"
|
#include "Buttons.hpp"
|
||||||
#include "TipThermoModel.h"
|
#include "TipThermoModel.h"
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
|
|
||||||
void gui_Menu(const menuitem *menu);
|
void gui_Menu(const menuitem *menu);
|
||||||
|
|||||||
@@ -4,13 +4,11 @@
|
|||||||
* Main.cpp bootstraps the device and then hands over to FreeRTOS and the threads
|
* Main.cpp bootstraps the device and then hands over to FreeRTOS and the threads
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "main.hpp"
|
||||||
#include "BSP.h"
|
#include "BSP.h"
|
||||||
#include "LIS2DH12.hpp"
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
#include <MMA8652FC.hpp>
|
#include "power.hpp"
|
||||||
#include <main.hpp>
|
|
||||||
#include <power.hpp>
|
|
||||||
uint8_t DetectedAccelerometerVersion = 0;
|
uint8_t DetectedAccelerometerVersion = 0;
|
||||||
bool settingsWereReset = false;
|
bool settingsWereReset = false;
|
||||||
// FreeRTOS variables
|
// FreeRTOS variables
|
||||||
@@ -45,21 +43,23 @@ int main(void) {
|
|||||||
settingsWereReset = restoreSettings(); // load the settings from flash
|
settingsWereReset = restoreSettings(); // load the settings from flash
|
||||||
resetWatchdog();
|
resetWatchdog();
|
||||||
/* Create the thread(s) */
|
/* 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*/
|
/* definition and creation of PIDTask - Heating control*/
|
||||||
osThreadStaticDef(PIDTask, startPIDTask, osPriorityRealtime, 0, PIDTaskStackSize, PIDTaskBuffer, &PIDTaskControlBlock);
|
osThreadStaticDef(PIDTask, startPIDTask, osPriorityRealtime, 0, PIDTaskStackSize, PIDTaskBuffer, &PIDTaskControlBlock);
|
||||||
PIDTaskHandle = osThreadCreate(osThread(PIDTask), NULL);
|
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 */
|
/* definition and creation of MOVTask - Accelerometer management */
|
||||||
osThreadStaticDef(MOVTask, startMOVTask, osPriorityNormal, 0, MOVTaskStackSize, MOVTaskBuffer, &MOVTaskControlBlock);
|
osThreadStaticDef(MOVTask, startMOVTask, osPriorityNormal, 0, MOVTaskStackSize, MOVTaskBuffer, &MOVTaskControlBlock);
|
||||||
MOVTaskHandle = osThreadCreate(osThread(MOVTask), NULL);
|
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();
|
resetWatchdog();
|
||||||
|
|
||||||
/* Start scheduler */
|
/* Start scheduler */
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include "FreeRTOSConfig.h"
|
#include "FreeRTOSConfig.h"
|
||||||
}
|
}
|
||||||
#include "../../configuration.h"
|
|
||||||
#include "Buttons.hpp"
|
#include "Buttons.hpp"
|
||||||
#include "I2CBB.hpp"
|
#include "I2CBB.hpp"
|
||||||
#include "LIS2DH12.hpp"
|
#include "LIS2DH12.hpp"
|
||||||
@@ -15,6 +14,7 @@ extern "C" {
|
|||||||
#include "TipThermoModel.h"
|
#include "TipThermoModel.h"
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "QC3.h"
|
#include "QC3.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
|
#include "fusbpd.h"
|
||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
@@ -17,9 +18,20 @@
|
|||||||
// Small worker thread to handle power (mostly QC) related steps
|
// Small worker thread to handle power (mostly QC) related steps
|
||||||
|
|
||||||
void startPOWTask(void const *argument __unused) {
|
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();
|
postRToSInit();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
osDelay(TICKS_100MS); // Slow down update rate
|
|
||||||
power_check();
|
power_check();
|
||||||
|
osDelay(TICKS_100MS); // Slow down update rate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user