123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- * 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 <stdlib.h>
-
- #include <pd.h>
- #include "priorities.h"
- #include "policy_engine.h"
- #include "protocol_tx.h"
- #include "fusb302b.h"
-
-
- /*
- * 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
- };
-
- /*
- * PRL_Rx_Wait_for_PHY_Message state
- */
- static enum protocol_rx_state protocol_rx_wait_phy(struct pdb_config *cfg)
- {
- /* Wait for an event */
- eventmask_t evt = chEvtWaitAny(ALL_EVENTS);
-
- /* If we got a reset event, reset */
- if (evt & PDB_EVT_PRLRX_RESET) {
- 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. */
- cfg->prl._rx_message = chPoolAlloc(&pdb_msg_pool);
- /* Read the message */
- fusb_read_message(&cfg->fusb, cfg->prl._rx_message);
- /* If it's a Soft_Reset, go to the soft reset state */
- if (PD_MSGTYPE_GET(cfg->prl._rx_message) == PD_MSGTYPE_SOFT_RESET
- && PD_NUMOBJ_GET(cfg->prl._rx_message) == 0) {
- return PRLRxReset;
- /* Otherwise, check the message ID */
- } else {
- return PRLRxCheckMessageID;
- }
- }
-
- /* We shouldn't ever get here. This just silence the compiler warning. */
- return PRLRxWaitPHY;
- }
-
- /*
- * PRL_Rx_Layer_Reset_for_Receive state
- */
- static enum protocol_rx_state protocol_rx_reset(struct pdb_config *cfg)
- {
- /* Reset MessageIDCounter */
- cfg->prl._tx_messageidcounter = 0;
-
- /* Clear stored MessageID */
- cfg->prl._rx_messageid = -1;
-
- /* TX transitions to its reset state */
- chEvtSignal(cfg->prl.tx_thread, PDB_EVT_PRLTX_RESET);
- chThdYield();
-
- /* If we got a RESET signal, reset the machine */
- if (chEvtGetAndClearEvents(PDB_EVT_PRLRX_RESET) != 0) {
- chPoolFree(&pdb_msg_pool, cfg->prl._rx_message);
- cfg->prl._rx_message = NULL;
- return PRLRxWaitPHY;
- }
-
- /* Go to the Check_MessageID state */
- return PRLRxCheckMessageID;
- }
-
- /*
- * PRL_Rx_Check_MessageID state
- */
- static enum protocol_rx_state protocol_rx_check_messageid(struct pdb_config *cfg)
- {
- /* If we got a RESET signal, reset the machine */
- if (chEvtGetAndClearEvents(PDB_EVT_PRLRX_RESET) != 0) {
- chPoolFree(&pdb_msg_pool, cfg->prl._rx_message);
- cfg->prl._rx_message = NULL;
- return PRLRxWaitPHY;
- }
-
- /* If the message has the stored ID, we've seen this message before. Free
- * it and don't pass it to the policy engine. */
- if (PD_MESSAGEID_GET(cfg->prl._rx_message) == cfg->prl._rx_messageid) {
- chPoolFree(&pdb_msg_pool, cfg->prl._rx_message);
- cfg->prl._rx_message = NULL;
- return PRLRxWaitPHY;
- /* Otherwise, there's either no stored ID or this message has an ID we
- * haven't just seen. Transition to the Store_MessageID state. */
- } else {
- return PRLRxStoreMessageID;
- }
- }
-
- /*
- * PRL_Rx_Store_MessageID state
- */
- static enum protocol_rx_state protocol_rx_store_messageid(struct pdb_config *cfg)
- {
- /* Tell ProtocolTX to discard the message being transmitted */
- chEvtSignal(cfg->prl.tx_thread, PDB_EVT_PRLTX_DISCARD);
- chThdYield();
-
- /* Update the stored MessageID */
- cfg->prl._rx_messageid = PD_MESSAGEID_GET(cfg->prl._rx_message);
-
- /* Pass the message to the policy engine. */
- chMBPost(&cfg->pe.mailbox, (msg_t) cfg->prl._rx_message, TIME_IMMEDIATE);
- chEvtSignal(cfg->pe.thread, PDB_EVT_PE_MSG_RX);
-
- /* Don't check if we got a RESET because we'd do nothing different. */
-
- return PRLRxWaitPHY;
- }
-
- /*
- * Protocol layer RX state machine thread
- */
- static THD_FUNCTION(ProtocolRX, cfg) {
- enum protocol_rx_state state = PRLRxWaitPHY;
-
- while (true) {
- switch (state) {
- case PRLRxWaitPHY:
- state = protocol_rx_wait_phy(cfg);
- break;
- case PRLRxReset:
- state = protocol_rx_reset(cfg);
- break;
- case PRLRxCheckMessageID:
- state = protocol_rx_check_messageid(cfg);
- break;
- case PRLRxStoreMessageID:
- state = protocol_rx_store_messageid(cfg);
- break;
- default:
- /* This is an error. It really shouldn't happen. We might
- * want to handle it anyway, though. */
- break;
- }
- }
- }
-
- void pdb_prlrx_run(struct pdb_config *cfg)
- {
- cfg->prl._rx_messageid = -1;
-
- cfg->prl.rx_thread = chThdCreateStatic(cfg->prl._rx_wa,
- sizeof(cfg->prl._rx_wa), PDB_PRIO_PRL, ProtocolRX, cfg);
- }
|