1
0
forked from me/IronOS

Reworking USB-PD stack to remove a thread

This commit is contained in:
Ben V. Brown
2021-05-01 12:21:37 +10:00
parent 27aecd2436
commit 0bfe052127
9 changed files with 265 additions and 549 deletions

View File

@@ -24,8 +24,10 @@
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 */
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 uint8_t sop_seq[5] = { FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP1,
static const uint8_t eop_seq[4] = {FUSB_FIFO_TX_JAM_CRC, FUSB_FIFO_TX_EOP, FUSB_FIFO_TX_TXOFF, FUSB_FIFO_TX_TXON}; 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 */ /* 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 /* Get the length of the message: a two-octet header plus NUMOBJ four-octet
@@ -41,6 +43,11 @@ void fusb_send_message(const union pd_msg *msg) {
fusb_write_buf(FUSB_FIFOS, 4, eop_seq); fusb_write_buf(FUSB_FIFOS, 4, eop_seq);
} }
bool fusb_rx_pending() {
return (fusb_read_byte( FUSB_STATUS1) & FUSB_STATUS1_RX_EMPTY)
!= FUSB_STATUS1_RX_EMPTY;
}
uint8_t fusb_read_message(union pd_msg *msg) { uint8_t fusb_read_message(union pd_msg *msg) {
static uint8_t garbage[4]; static uint8_t garbage[4];
@@ -48,7 +55,12 @@ uint8_t fusb_read_message(union pd_msg *msg) {
// Read the header. If its not a SOP we dont actually want it at all // 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 // 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); if ((fusb_read_byte( FUSB_FIFOS) & FUSB_FIFO_RX_TOKEN_BITS)
!= FUSB_FIFO_RX_SOP) {
return 1;
}
// fusb_read_byte(FUSB_FIFOS);
/* Read the message header into msg */ /* Read the message header into msg */
fusb_read_buf(FUSB_FIFOS, 2, msg->bytes); fusb_read_buf(FUSB_FIFOS, 2, msg->bytes);
/* Get the number of data objects */ /* Get the number of data objects */
@@ -132,7 +144,8 @@ bool fusb_get_status(union fusb_status *status) {
enum fusb_typec_current fusb_get_typec_current() { enum fusb_typec_current fusb_get_typec_current() {
/* Read the BC_LVL into a variable */ /* 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); enum fusb_typec_current bc_lvl = (enum fusb_typec_current) (fusb_read_byte(
FUSB_STATUS0) & FUSB_STATUS0_BC_LVL);
return bc_lvl; return bc_lvl;
} }
@@ -144,7 +157,7 @@ void fusb_reset() {
/* Flush the RX buffer */ /* Flush the RX buffer */
fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH); fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH);
/* Reset the PD logic */ /* Reset the PD logic */
// fusb_write_byte( FUSB_RESET, FUSB_RESET_PD_RESET); fusb_write_byte( FUSB_RESET, FUSB_RESET_PD_RESET);
} }
bool fusb_read_id() { bool fusb_read_id() {

View File

@@ -269,7 +269,7 @@ union fusb_status {
* Send a USB Power Delivery message to the FUSB302B * Send a USB Power Delivery message to the FUSB302B
*/ */
void fusb_send_message(const union pd_msg *msg); void fusb_send_message(const union pd_msg *msg);
bool fusb_rx_pending();
/* /*
* Read a USB Power Delivery message from the FUSB302B * Read a USB Power Delivery message from the FUSB302B
*/ */

View File

@@ -12,7 +12,6 @@
#include "int_n.h" #include "int_n.h"
#include "policy_engine.h" #include "policy_engine.h"
#include "protocol_tx.h"
#include <fusbpd.h> #include <fusbpd.h>
#include <pd.h> #include <pd.h>
@@ -20,7 +19,6 @@ void fusb302_start_processing() {
/* Initialize the FUSB302B */ /* Initialize the FUSB302B */
if (fusb_setup()) { if (fusb_setup()) {
PolicyEngine::init(); PolicyEngine::init();
ProtocolTransmit::init();
InterruptHandler::init(); InterruptHandler::init();
} }
} }

View File

@@ -22,7 +22,6 @@
#include "fusbpd.h" #include "fusbpd.h"
#include "policy_engine.h" #include "policy_engine.h"
#include "protocol_tx.h"
#include "task.h" #include "task.h"
#include <pd.h> #include <pd.h>
#include <string.h> #include <string.h>
@@ -34,27 +33,36 @@ union pd_msg InterruptHandler::tempMessage;
void InterruptHandler::init() { void InterruptHandler::init() {
TaskHandle = NULL; 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);
} }
volatile uint32_t msgCounter = 0;
volatile uint32_t msgCounter1 = 0;
void InterruptHandler::readPendingMessage() { 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)); memset(&tempMessage, 0, sizeof(tempMessage));
while (fusb_rx_pending()) {
msgCounter++;
/* Read the message */ /* Read the message */
fusb_read_message(&tempMessage); if (fusb_read_message(&tempMessage) == 0) {
/* If it's a Soft_Reset, go to the soft reset state */ /* 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) { if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET
&& PD_NUMOBJ_GET(&tempMessage) == 0) {
/* TX transitions to its reset state */ /* TX transitions to its reset state */
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET); PolicyEngine::notify(
PolicyEngine::Notifications::PDB_EVT_PE_RESET);
} else { } else {
/* Tell ProtocolTX to discard the message being transmitted */ /* Tell PolicyEngine to discard the message being transmitted */
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD); PolicyEngine::notify(
PolicyEngine::Notifications::PDB_EVT_TX_DISCARD);
/* Pass the message to the policy engine. */ /* Pass the message to the policy engine. */
PolicyEngine::handleMessage(&tempMessage); PolicyEngine::handleMessage(&tempMessage);
} }
} else {
msgCounter1++;
}
}
} }
void InterruptHandler::Thread(const void *arg) { void InterruptHandler::Thread(const void *arg) {
@@ -77,16 +85,20 @@ void InterruptHandler::Thread(const void *arg) {
/* 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) {
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_TXSENT); PolicyEngine::notify(
PolicyEngine::Notifications::PDB_EVT_TX_I_TXSENT);
} }
if (status.interrupta & FUSB_INTERRUPTA_I_RETRYFAIL) { if (status.interrupta & FUSB_INTERRUPTA_I_RETRYFAIL) {
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_RETRYFAIL); PolicyEngine::notify(
PolicyEngine::Notifications::PDB_EVT_TX_I_RETRYFAIL);
} }
/* 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)
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_I_OVRTEMP); && (status.status1 & FUSB_STATUS1_OVRTEMP)) {
PolicyEngine::notify(
PolicyEngine::Notifications::PDB_EVT_PE_I_OVRTEMP);
} }
} }
} }
@@ -94,7 +106,8 @@ void InterruptHandler::Thread(const void *arg) {
void InterruptHandler::irqCallback() { void InterruptHandler::irqCallback() {
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);
} }
} }

View File

@@ -19,7 +19,6 @@
#include "Defines.h" #include "Defines.h"
#include "fusb302b.h" #include "fusb302b.h"
#include "int_n.h" #include "int_n.h"
#include "protocol_tx.h"
#include <pd.h> #include <pd.h>
#include <stdbool.h> #include <stdbool.h>
bool PolicyEngine::pdNegotiationComplete; bool PolicyEngine::pdNegotiationComplete;
@@ -45,6 +44,7 @@ EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL;
StaticEventGroup_t PolicyEngine::xCreatedEventGroup; StaticEventGroup_t PolicyEngine::xCreatedEventGroup;
bool PolicyEngine::PPSTimerEnabled = false; bool PolicyEngine::PPSTimerEnabled = false;
TickType_t PolicyEngine::PPSTimeLastEvent = 0; TickType_t PolicyEngine::PPSTimeLastEvent = 0;
uint8_t PolicyEngine::_tx_messageidcounter = 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
@@ -238,9 +238,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
/* Transmit the request */ /* Transmit the request */
waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL, 0); // clear pending waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL, 0); // clear pending
ProtocolTransmit::pushMessage(&_last_dpm_request); EventBits_t evt = pushMessage(&_last_dpm_request);
// Send indication that there is a message pending
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* If we got reset signaling, transition to default */ /* If we got reset signaling, transition to default */
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET || evt == 0) { if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET || evt == 0) {
return PESinkTransitionDefault; return PESinkTransitionDefault;
@@ -410,8 +408,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_get_source_cap() {
/* Make a Get_Source_Cap message */ /* Make a Get_Source_Cap message */
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); EventBits_t evt = pushMessage(get_source_cap);
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* Free the sent message */ /* Free the sent message */
/* If we got reset signaling, transition to default */ /* If we got reset signaling, transition to default */
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
@@ -432,8 +429,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_give_sink_cap() {
pdbs_dpm_get_sink_capability(snk_cap); pdbs_dpm_get_sink_capability(snk_cap);
/* Transmit our capabilities */ /* Transmit our capabilities */
ProtocolTransmit::pushMessage(snk_cap); EventBits_t evt = pushMessage(snk_cap);
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* Free the Sink_Capabilities message */ /* Free the Sink_Capabilities message */
@@ -485,8 +481,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_soft_reset() {
/* Make an Accept message */ /* Make an Accept message */
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); EventBits_t evt = pushMessage(&accept);
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* Free the sent message */ /* Free the sent message */
/* If we got reset signaling, transition to default */ /* If we got reset signaling, transition to default */
@@ -510,8 +505,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() {
/* Make a Soft_Reset message */ /* Make a Soft_Reset message */
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); EventBits_t evt = pushMessage(softrst);
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* If we got reset signaling, transition to default */ /* If we got reset signaling, transition to default */
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
return PESinkTransitionDefault; return PESinkTransitionDefault;
@@ -564,8 +558,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() {
} }
/* Transmit the message */ /* Transmit the message */
ProtocolTransmit::pushMessage(&tempMessage); EventBits_t evt = pushMessage(&tempMessage);
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET);
/* If we got reset signaling, transition to default */ /* If we got reset signaling, transition to default */
if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) {
@@ -625,3 +618,57 @@ void PolicyEngine::PPSTimerCallback() {
} }
} }
} }
EventBits_t PolicyEngine::pushMessage(union pd_msg *msg) {
if (PD_MSGTYPE_GET(msg) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(msg) == 0) {
/* Clear MessageIDCounter */
_tx_messageidcounter = 0;
return (EventBits_t)Notifications::PDB_EVT_PE_TX_DONE;
}
msg->hdr &= ~PD_HDR_MESSAGEID;
msg->hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
/* PD 3.0 collision avoidance */
if (PolicyEngine::isPD3_0()) {
/* If we're starting an AMS, wait for permission to transmit */
// while (fusb_get_typec_current() != fusb_sink_tx_ok) {
// vTaskDelay(TICKS_10MS);
// }
}
/* Send the message to the PHY */
fusb_send_message(msg);
/* Waiting for response*/
EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_RESET | (uint32_t)Notifications::PDB_EVT_TX_DISCARD | (uint32_t)Notifications::PDB_EVT_TX_I_TXSENT
| (uint32_t)Notifications::PDB_EVT_TX_I_RETRYFAIL);
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_TX_DISCARD) {
// increment the counter
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
return (EventBits_t)Notifications::PDB_EVT_PE_TX_ERR; //
}
/* If the message was sent successfully */
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_TX_I_TXSENT) {
union pd_msg goodcrc;
/* Read the GoodCRC */
fusb_read_message(&goodcrc);
/* Check that the message is correct */
if (PD_MSGTYPE_GET(&goodcrc) == PD_MSGTYPE_GOODCRC && PD_NUMOBJ_GET(&goodcrc) == 0 && PD_MESSAGEID_GET(&goodcrc) == _tx_messageidcounter) {
/* Increment MessageIDCounter */
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
return (EventBits_t)Notifications::PDB_EVT_PE_TX_DONE;
} else {
return (EventBits_t)Notifications::PDB_EVT_PE_TX_ERR;
}
}
/* If the message failed to be sent */
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_TX_I_RETRYFAIL) {
return (EventBits_t)Notifications::PDB_EVT_PE_TX_ERR;
}
/* Silence the compiler warning */
return (EventBits_t)Notifications::PDB_EVT_PE_TX_ERR;
}

View File

@@ -61,7 +61,10 @@ public:
PDB_EVT_PE_PPS_REQUEST = EVENT_MASK(6), PDB_EVT_PE_PPS_REQUEST = EVENT_MASK(6),
PDB_EVT_PE_GET_SOURCE_CAP = EVENT_MASK(7), PDB_EVT_PE_GET_SOURCE_CAP = EVENT_MASK(7),
PDB_EVT_PE_NEW_POWER = EVENT_MASK(8), PDB_EVT_PE_NEW_POWER = EVENT_MASK(8),
PDB_EVT_PE_ALL = (EVENT_MASK(9) - 1), PDB_EVT_TX_I_TXSENT = EVENT_MASK(9),
PDB_EVT_TX_I_RETRYFAIL = EVENT_MASK(10),
PDB_EVT_TX_DISCARD = EVENT_MASK(11),
PDB_EVT_PE_ALL = (EVENT_MASK(12) - 1),
}; };
// Send a notification // Send a notification
static void notify(Notifications notification); static void notify(Notifications notification);
@@ -87,24 +90,27 @@ private:
static uint8_t _pps_index; static uint8_t _pps_index;
static void pe_task(const void *arg); static void pe_task(const void *arg);
static EventBits_t pushMessage(union pd_msg *msg);
static uint8_t _tx_messageidcounter;
enum policy_engine_state { enum policy_engine_state {
PESinkStartup, PESinkStartup, // 0
PESinkDiscovery, PESinkDiscovery, // 1
PESinkWaitCap, PESinkWaitCap, // 2
PESinkEvalCap, PESinkEvalCap, // 3
PESinkSelectCap, // 4 PESinkSelectCap, // 4
PESinkTransitionSink, // 5 PESinkTransitionSink, // 5
PESinkReady, // 6 PESinkReady, // 6
PESinkGetSourceCap, PESinkGetSourceCap, // 7
PESinkGiveSinkCap, PESinkGiveSinkCap, // 8
PESinkHardReset, PESinkHardReset, // 9
PESinkTransitionDefault, PESinkTransitionDefault, // 10
PESinkSoftReset, PESinkSoftReset, // 11
PESinkSendSoftReset, PESinkSendSoftReset, // 12
PESinkSendNotSupported, PESinkSendNotSupported, // 13
PESinkChunkReceived, PESinkChunkReceived, // 14
PESinkNotSupportedReceived, PESinkNotSupportedReceived, // 15
PESinkSourceUnresponsive PESinkSourceUnresponsive // 16
}; };
static enum policy_engine_state pe_sink_startup(); static enum policy_engine_state pe_sink_startup();
static enum policy_engine_state pe_sink_discovery(); static enum policy_engine_state pe_sink_discovery();

View File

@@ -1,276 +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_tx.h"
#include "Defines.h"
#include "fusb302b.h"
#include "fusbpd.h"
#include "policy_engine.h"
#include <pd.h>
osThreadId ProtocolTransmit::TaskHandle = NULL;
uint32_t ProtocolTransmit::TaskBuffer[ProtocolTransmit::TaskStackSize];
osStaticThreadDef_t ProtocolTransmit::TaskControlBlock;
StaticQueue_t ProtocolTransmit::xStaticQueue;
bool ProtocolTransmit::messageSending = false;
uint8_t ProtocolTransmit::ucQueueStorageArea[PDB_MSG_POOL_SIZE * sizeof(union pd_msg)];
QueueHandle_t ProtocolTransmit::messagesWaiting = NULL;
uint8_t ProtocolTransmit::_tx_messageidcounter;
union pd_msg ProtocolTransmit::temp_msg;
EventGroupHandle_t ProtocolTransmit::xEventGroupHandle = NULL;
StaticEventGroup_t ProtocolTransmit::xCreatedEventGroup;
/*
* PRL_Tx_PHY_Layer_Reset state
*/
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() {
/* Reset the PHY */
fusb_reset();
/* If a message was pending when we got here, tell the policy engine that
* we failed to send it */
if (messagePending()) {
/* Tell the policy engine that we failed */
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR);
/* Finish failing to send the message */
while (messagePending()) {
getMessage(); // Discard
}
}
/* Wait for a message request */
return PRLTxWaitMessage;
}
/*
* PRL_Tx_Wait_for_Message_Request state
*/
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_message() {
/* Wait for an event */
ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_RESET | (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD | (uint32_t)Notifications::PDB_EVT_PRLTX_MSG_TX);
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_RESET) {
return PRLTxPHYReset;
}
/* If the policy engine is trying to send a message */
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_MSG_TX) {
/* Get the message */
getMessage();
/* If it's a Soft_Reset, reset the TX layer first */
if (PD_MSGTYPE_GET(&temp_msg) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&(temp_msg)) == 0) {
return PRLTxReset;
/* Otherwise, just send the message */
} else {
return PRLTxConstructMessage;
}
}
/* Silence the compiler warning */
return PRLTxWaitMessage;
}
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() {
/* Clear MessageIDCounter */
_tx_messageidcounter = 0;
return PRLTxConstructMessage;
}
/*
* PRL_Tx_Construct_Message state
*/
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_message() {
/* Set the correct MessageID in the message */
temp_msg.hdr &= ~PD_HDR_MESSAGEID;
temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
/* PD 3.0 collision avoidance */
if (PolicyEngine::isPD3_0()) {
/* If we're starting an AMS, wait for permission to transmit */
while (fusb_get_typec_current() != fusb_sink_tx_ok) {
vTaskDelay(TICKS_10MS);
}
}
messageSending = true;
/* Send the message to the PHY */
fusb_send_message(&temp_msg);
return PRLTxWaitResponse;
}
/*
* PRL_Tx_Wait_for_PHY_Response state
*/
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_response() {
/* Wait for an event. There is no need to run CRCReceiveTimer, since the
* FUSB302B handles that as part of its retry mechanism. */
ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_RESET | (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD | (uint32_t)Notifications::PDB_EVT_PRLTX_I_TXSENT
| (uint32_t)Notifications::PDB_EVT_PRLTX_I_RETRYFAIL);
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_RESET) {
return PRLTxPHYReset;
}
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_DISCARD) {
return PRLTxDiscardMessage;
}
/* If the message was sent successfully */
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_I_TXSENT) {
return PRLTxMatchMessageID;
}
/* If the message failed to be sent */
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_I_RETRYFAIL) {
return PRLTxTransmissionError;
}
/* Silence the compiler warning */
return PRLTxDiscardMessage;
}
/*
* PRL_Tx_Match_MessageID state
*/
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_match_messageid() {
union pd_msg goodcrc;
/* Read the GoodCRC */
fusb_read_message(&goodcrc);
/* Check that the message is correct */
if (PD_MSGTYPE_GET(&goodcrc) == PD_MSGTYPE_GOODCRC && PD_NUMOBJ_GET(&goodcrc) == 0 && PD_MESSAGEID_GET(&goodcrc) == _tx_messageidcounter) {
return PRLTxMessageSent;
} else {
return PRLTxTransmissionError;
}
}
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_error() {
/* Increment MessageIDCounter */
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
/* Tell the policy engine that we failed */
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR);
return PRLTxWaitMessage;
}
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent() {
messageSending = false;
/* Increment MessageIDCounter */
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
/* Tell the policy engine that we succeeded */
PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_DONE);
return PRLTxWaitMessage;
}
ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_discard_message() {
/* If we were working on sending a message, increment MessageIDCounter */
if (messageSending) {
_tx_messageidcounter = (_tx_messageidcounter + 1) % 8;
return PRLTxPHYReset;
} else {
return PRLTxWaitMessage;
}
}
void ProtocolTransmit::thread(const void *args) {
(void)args;
ProtocolTransmit::protocol_tx_state state = PRLTxPHYReset;
// Init the incoming message queue
while (true) {
switch (state) {
case PRLTxPHYReset:
state = protocol_tx_phy_reset();
break;
case PRLTxWaitMessage:
state = protocol_tx_wait_message();
break;
case PRLTxReset:
state = protocol_tx_reset();
break;
case PRLTxConstructMessage:
state = protocol_tx_construct_message();
break;
case PRLTxWaitResponse:
state = protocol_tx_wait_response();
break;
case PRLTxMatchMessageID:
state = protocol_tx_match_messageid();
break;
case PRLTxTransmissionError:
state = protocol_tx_transmission_error();
break;
case PRLTxMessageSent:
state = protocol_tx_message_sent();
break;
case PRLTxDiscardMessage:
state = protocol_tx_discard_message();
break;
default:
state = PRLTxPHYReset;
break;
}
}
}
void ProtocolTransmit::notify(ProtocolTransmit::Notifications notification) {
if (xEventGroupHandle != NULL) {
xEventGroupSetBits(xEventGroupHandle, (uint32_t)notification);
}
}
void ProtocolTransmit::init() {
messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue);
osThreadStaticDef(pd_txTask, thread, PDB_PRIO_PRL, 0, TaskStackSize, TaskBuffer, &TaskControlBlock);
TaskHandle = osThreadCreate(osThread(pd_txTask), NULL);
xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup);
}
void ProtocolTransmit::pushMessage(union pd_msg *msg) {
if (messagesWaiting) {
if (xQueueSend(messagesWaiting, msg, 100) == pdTRUE) {
notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX);
}
}
}
bool ProtocolTransmit::messagePending() {
if (messagesWaiting) {
return uxQueueMessagesWaiting(messagesWaiting) > 0;
}
return false;
}
void ProtocolTransmit::getMessage() {
// Loads the pending message into the buffer
if (messagesWaiting) {
xQueueReceive(messagesWaiting, &temp_msg, 1);
}
}
ProtocolTransmit::Notifications ProtocolTransmit::waitForEvent(uint32_t mask, TickType_t ticksToWait) {
if (xEventGroupHandle) {
return (Notifications)xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait);
}
return (Notifications)0;
}

View File

@@ -1,85 +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_TX_H
#define PDB_PROTOCOL_TX_H
#include "policy_engine.h"
#include <pd.h>
#include <stdint.h>
/* Events for the Protocol TX thread */
class ProtocolTransmit {
public:
static void init();
// Push a message to the queue to be sent out the pd comms bus
static void pushMessage(union pd_msg *msg);
enum class Notifications {
PDB_EVT_PRLTX_RESET = EVENT_MASK(0), //
PDB_EVT_PRLTX_I_TXSENT = EVENT_MASK(1), //
PDB_EVT_PRLTX_I_RETRYFAIL = EVENT_MASK(2), //
PDB_EVT_PRLTX_DISCARD = EVENT_MASK(3), //
PDB_EVT_PRLTX_MSG_TX = EVENT_MASK(4), //
};
static void notify(Notifications 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;
static bool messageSending;
/*
* Protocol TX machine states
*
* Because the PHY can automatically send retries, the Check_RetryCounter state
* has been removed, transitions relating to it are modified appropriately, and
* we don't even keep a RetryCounter.
*/
enum protocol_tx_state { PRLTxPHYReset, PRLTxWaitMessage, PRLTxReset, PRLTxConstructMessage, PRLTxWaitResponse, PRLTxMatchMessageID, PRLTxTransmissionError, PRLTxMessageSent, PRLTxDiscardMessage };
// Internal states
static protocol_tx_state protocol_tx_discard_message();
static protocol_tx_state protocol_tx_message_sent();
static protocol_tx_state protocol_tx_transmission_error();
static protocol_tx_state protocol_tx_match_messageid();
static protocol_tx_state protocol_tx_wait_response();
static protocol_tx_state protocol_tx_construct_message();
static protocol_tx_state protocol_tx_reset();
static protocol_tx_state protocol_tx_wait_message();
static protocol_tx_state protocol_tx_phy_reset();
// queue of up to PDB_MSG_POOL_SIZE messages to send
static StaticQueue_t xStaticQueue;
/* The array to use as the queue's storage area. This must be at least
uxQueueLength * uxItemSize bytes. */
static uint8_t ucQueueStorageArea[PDB_MSG_POOL_SIZE * sizeof(union pd_msg)];
static QueueHandle_t messagesWaiting;
static uint8_t _tx_messageidcounter;
static bool messagePending();
// Reads a message off the queue into the temp message
static void getMessage();
static union pd_msg temp_msg;
static Notifications waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY);
};
#endif /* PDB_PROTOCOL_TX_H */

View File

@@ -164,9 +164,9 @@
#endif #endif
#ifdef MODEL_MHP30 #ifdef MODEL_MHP30
#define VOLTAGE_DIV 350 // Default for MHP30 #define VOLTAGE_DIV 352 // Default for MHP30
#define PID_POWER_LIMIT 65 // Sets the max pwm power limit #define PID_POWER_LIMIT 65 // Sets the max pwm power limit
#define CALIBRATION_OFFSET 0 // the adc offset in uV #define CALIBRATION_OFFSET 700 // the adc offset in uV
#define POWER_LIMIT 65 // 65 watts default power limit #define POWER_LIMIT 65 // 65 watts default power limit
#define MAX_POWER_LIMIT 65 // #define MAX_POWER_LIMIT 65 //
#define POWER_LIMIT_STEPS 2 // #define POWER_LIMIT_STEPS 2 //