📄 protocol.c
字号:
/***************************************************************************//*! *\MODULE Wireless UART with Flow Control * *\COMPONENT $RCSfile: Protocol.c,v $ * *\VERSION $Name: $ * *\REVISION $Revision: 1.1 $ * *\DATED $Date: 2008/01/21 10:15:04 $ * *\STATUS $State: Exp $ * *\AUTHOR Martin Looker * *\DESCRIPTION Handles the over the air protocol. * * Manages the protocol to transmit and receive data over the radio. * * The protocol maintains a single packet containing the next packet of data * for transmission: * * - If the packet is empty it is filled with the next packet of * data from the receive queue. * * - If a packet is ready for transmission the protocol is initiated. * * The basic protocol for A transmitting a data packet to B is as follows: * * - A sends an equiry packet to B * * - If B has space in the UART transmit queue B responds with an ack packet. * * - A sends the data packet to B * * - If B has space in the UART transmit queue it adds the data to the queue and * responds with an ack packet. * * - If B does not have space to receive a packet it responds with a nack packet, A then * pauses for a short while before retrying. * * It is possible that both A and B send an enquiry packet at the same time, the following * rules apply in such a situation: * * - The device that last sent a data packet yields to the other device. If B were the last * device to send data to A then B would yield to A by sending an ack packet, A would then get * to send data. * * - If A gets to send data in the previous scenario, A will pause before sending another * enquiry packet in the expectation that B is ready to send data. * * - The enquiry packets indicate if the device is going to yield, in the event that both * devices are going to take the same action the Router will yield to the Coordinator. *//* *\dot * digraph G { * label="Protocol State Machine" * rankdir="LR" * fontname="FreeSans.ttf" * fontsize=10 * labelfontname="FreeSans.ttf" * labelfontsize=10 * edge [fontname="FreeSans.ttf", fontsize=8, labelfontname="FreeSans.ttf", labelfontsize=8]; * node [fontname="FreeSans.ttf", fontsize=10, labelfontname="FreeSans.ttf", labelfontsize=10,shape="box",height=0.2,width=0.4]; * edge [color="Black"]; * IDLE -> ENQ [label="Data?\nTx Enq"]; * RX -> IDLE [label="Rx Data?\nTx N/Ack, Yield=F"]; * edge [color="#0000AA", fontcolor="#0000AA", labelfontcolor="#0000AA"]; * IDLE -> RX [label="Rx Enq & Spc?\nTx Ack"]; * RX -> RX [label="Rx Enq & Spc?\nTx Ack"]; * WAIT -> RX [label="Rx Enq & Spc?\nTx Ack"]; * ENQ -> RX [label="Rx Enq & Spc & Yield?\nTx Ack"]; * IDLE -> IDLE [label="Rx Enq & !Spc?\nTx Nak"]; * RX -> RX [label="Rx Enq & !Spc?\nTx Nak"]; * WAIT -> WAIT [label="Rx Enq & !Spc?\nTx Nak"]; * ENQ -> ENQ [label="Rx Enq & !Spc & Yield?\nTx Nak"]; * ENQ -> ENQ [label="Rx Enq & !Yield?\nWait=T"]; * edge [color="#00AA00", fontcolor="#00AA00", labelfontcolor="#00AA00"]; * ENQ -> TX [label="Rx Ack?\nTx Data"]; * TX -> IDLE [label="Rx Ack?\nYield=T"]; * TX -> WAIT [label="Rx Ack & Wait?\nYield=T"]; * edge [color="#AA0000", fontcolor="#AA0000", labelfontcolor="#AA0000"]; * ENQ -> WAIT [label="Rx Nak?"]; * TX -> WAIT [label="Rx Nak?\nYield=T"]; *} *\enddot *\CHANGE HISTORY * * $Log: Protocol.c,v $ * Revision 1.1 2008/01/21 10:15:04 mlook * Initial checkin * * Revision 1.1 2007/11/02 12:32:52 mlook * Adding new application notes * * * *\LAST MODIFIED BY $Author: mlook $ * $Modtime: $ * **************************************************************************** * * This software is owned by Jennic and/or its supplier and is protected * under applicable copyright laws. All rights are reserved. We grant You, * and any third parties, a license to use this software solely and * exclusively on Jennic products. You, and any third parties must reproduce * the copyright and warranty notice and any other legend of ownership on each * copy or partial copy of the software. * * THIS SOFTWARE IS PROVIDED "AS IS". JENNIC MAKES NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, * ACCURACY OR LACK OF NEGLIGENCE. JENNIC SHALL NOT, IN ANY CIRCUMSTANCES, * BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, SPECIAL, * INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON WHATSOEVER. * * Copyright Jennic Ltd 2005, 2006, 2007. All rights reserved * ****************************************************************************//****************************************************************************//*** Include files ***//****************************************************************************/#include <jendefs.h>#include <string.h>#include <Printf.h>#include "gdb.h"#include "Network.h"#include "Protocol.h"#include "SerialQ.h"#include "Uart.h"/****************************************************************************//*** Macro Definitions ***//****************************************************************************/#define MAX_DATA_PER_FRAME 64 /**< Maximum amount of data per radio frame */#define PR_DEBUG 0 /**< Provides protocol debugging *//* Protocol character codes */#if PR_DEBUG#define CHAR_STX 0x00 /**< Data packet */#define CHAR_ENQ 0x01 /**< Transmit enquiry packet */#define CHAR_ACK 0x02 /**< Acknowledge packet */#define CHAR_NACK 0x03 /**< Negative acknowledge packet */#else#define CHAR_STX 0x02 /**< Data packet */#define CHAR_ENQ 0x05 /**< Transmit enquiry packet */#define CHAR_ACK 0x06 /**< Acknowledge packet */#define CHAR_NACK 0x15 /**< Negative acknowledge packet */#endif/****************************************************************************//*** Type Definitions ***//****************************************************************************//** States for protocol's state machine. */typedef enum{ PR_STATE_IDLE=0, /**< Protocol is idle */ PR_STATE_RX, /**< Waiting to receive data */ PR_STATE_ENQ, /**< Equiry sent to transmit data */ PR_STATE_TX, /**< Data transmitted, waiting for ACK */ PR_STATE_WAIT /**< Waiting before trying to transmit */} tePrState;/** Data packet structure. */typedef struct{ uint16 u16Length; /**< Data length */ uint8 au8Data[MAX_DATA_PER_FRAME+1];/**< Data packet */} tsPrPacket;/****************************************************************************//*** Local Function Prototypes ***//****************************************************************************//****************************************************************************//*** Exported Variables ***//****************************************************************************//****************************************************************************//*** Local Variables ***//****************************************************************************/PRIVATE tePrState eState; /**< Protocol state */PRIVATE uint8 u8Timer; /**< State timer */PRIVATE uint8 u8RxSequence; /**< Receive sequence */PRIVATE uint8 u8TxSequence; /**< Transmit sequence */PRIVATE bool_t bCoord; /**< Coordinator device */PRIVATE bool_t bYield; /**< Yield next time there is a conflict */PRIVATE bool_t bWait; /**< Wait before transmission enquiry */PRIVATE tsPrPacket sPacketData; /**< Data packet */PRIVATE tsPrPacket sPacketCtrl; /**< Protocol control packet */PRIVATE uint16 u16RxCount = 0;PRIVATE uint16 u16TxCount = 0;PRIVATE uint16 u16RxAckCount = 0;PRIVATE uint16 u16TxAckCount = 0;PRIVATE uint16 u16RxStxCount = 0;PRIVATE uint16 u16TxStxCount = 0;PRIVATE uint16 u16RxEnqCount = 0;PRIVATE uint16 u16TxEnqCount = 0;PRIVATE uint16 u16ClEnqCount = 0;#if PR_DEBUGPRIVATE char aszAddr[2][4] = {"Rtr", "Crd"};PRIVATE char aszCtrl[4][4] = {"STX", "ENQ", "ACK", "NAK"};#endif/****************************************************************************//*** Exported Functions ***//****************************************************************************//****************************************************************************//*** Local Functions ***//****************************************************************************/PRIVATE void vProtocol_State(tePrState);PRIVATE void vProtocol_Packet_Reset(tsPrPacket *);PRIVATE void vProtocol_Packet_Tx(tsPrPacket *);PRIVATE void vProtocol_Packet_Data(void);PRIVATE void vProtocol_Packet_Ctrl(char);PRIVATE bool_t bProtocol_RxSequence(uint8);/**************************************************************************** * * NAME vProtocol_Init *//*! *\DESCRIPTION Initialises protocol data. *//* PARAMETERS Name RW Usage * None. * * RETURNS * None. * * NOTES * None. ****************************************************************************/PUBLIC void vProtocol_Init(bool_t bInitCoord) /**< (R) Initialise as coordinator */{ /* Initialise protocol data */ eState = PR_STATE_IDLE; u8Timer = 0; u8TxSequence = 0; u8RxSequence = 0; bCoord = bInitCoord; bYield = ! bCoord; bWait = FALSE; /* Reset packets */ vProtocol_Packet_Reset(&sPacketData); vProtocol_Packet_Reset(&sPacketCtrl); #if PR_DEBUG /* Debug */ vSerialQ_AddString(TX_QUEUE, aszAddr[bCoord]); vSerialQ_AddItem(TX_QUEUE, ' '); vSerialQ_AddString(TX_QUEUE, "Start\n"); #endif}/**************************************************************************** * * NAME: vProtocol_Tx *//*! *\DESCRIPTION Builds and initiates transmission of data packets, handles state timeouts. * * If in idle state and the data packet is empty and there is data in the UART's * receive queue the data packet is populated with the next set of data from the * UART's receive queue. * * If in idle state and the data packet is populated initiate transmission by * sending the enquiry control packet. * * If not in idle state and the timer has expired return to the idle state. *//* PARAMETERS: Name RW Usage * None. * * RETURNS: * None. * * NOTES: * None. ****************************************************************************/PUBLIC void vProtocol_Tx(void){ /* Are we idle ? */ if (eState == PR_STATE_IDLE) { /* Populate the next data packet if required */ vProtocol_Packet_Data(); /* Got a data packet to send ? */ if (sPacketData.u16Length > 0) { /* Go to enquiry state */ vProtocol_State(PR_STATE_ENQ); /* Send enquiry control packet */ vProtocol_Packet_Ctrl(CHAR_ENQ); } } /* Not idle ? */ else { /* Increment timer */ u8Timer++; /* Timer expired ? */ if (u8Timer > 25) { /* Go to idle state */ vProtocol_State(PR_STATE_IDLE); } }}/**************************************************************************** * * NAME: vProtocol_Rx *//*! *\DESCRIPTION Receives and processes incoming packets. * * Handles incoming data and control packets updating the state machine as * required. * * Received data packets are added to the UART's transmit queue for output by * the UART. *//* PARAMETERS: Name RW Usage * None. * * RETURNS: * None. * * NOTES: * None. ****************************************************************************/PUBLIC void vProtocol_Rx(uint16 u16Length, /**< Data length */ uint8 * pu8Data) /**< Data packet */{ uint16 i; bool_t bYieldOther; #if PR_DEBUG /* Debug */ vSerialQ_AddString(TX_QUEUE, aszAddr[!bCoord]); vSerialQ_AddItem(TX_QUEUE, ' '); vSerialQ_AddString(TX_QUEUE, aszCtrl[pu8Data[0]]); #endif /* Enqiry ? */ if (pu8Data[0] == CHAR_ENQ) { #if PR_DEBUG vSerialQ_AddItem(TX_QUEUE, ' '); vSerialQ_AddHex(TX_QUEUE, pu8Data[1], 2); vSerialQ_AddItem(TX_QUEUE, '\r'); vUart_StartTx(); #endif /* Update Rx counts */ u16RxEnqCount++; /* Update clashing ENQ count if required */ if (eState == PR_STATE_ENQ) u16ClEnqCount++; /* Get other device's yield state */ bYieldOther = (bool_t) pu8Data[1]; /* Are yield states the same (devices are out of sync) ? */ if (bYieldOther == bYield) { /* If endpoint yield, if coord don't */ bYield = ! bCoord; } /* Are we in a state where we might receive data ? */ if (eState == PR_STATE_IDLE || eState == PR_STATE_RX || eState == PR_STATE_WAIT || (eState == PR_STATE_ENQ && bYield == TRUE)) { /* Have we got space in the UART transmit buffer for a full packet ? */ if (u16SerialQ_Free(TX_QUEUE) >= MAX_DATA_PER_FRAME) { /* Go to receive state */ vProtocol_State(PR_STATE_RX); /* Transmit acknowledgement */ vProtocol_Packet_Ctrl(CHAR_ACK); } /* No room ? */ else { /* Transmit nack */ vProtocol_Packet_Ctrl(CHAR_NACK); } } /* Are we expecting the other end to yield ? */ else if (eState == PR_STATE_ENQ && bYield == FALSE) { /* Wait after sending our data to let the other end take its turn */ bWait = TRUE; } } /* Ack ? */ else if (pu8Data[0] == CHAR_ACK) { #if PR_DEBUG vSerialQ_AddItem(TX_QUEUE, '\r');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -