📄 serialp.nc
字号:
/*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
* downloading, copying, installing or using the software you agree to
* this license. If you do not agree to this license, do not download,
* install, copy or use the software.
*
* Intel Open Source License
*
* Copyright (c) 2002 Intel Corporation
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Revision: $Revision: 1.5 $
*
*/
/*
*
* This modules provides framing for TOS_Msgs using PPP-HDLC-like
* framing (see RFC 1662). When sending, a TOS_Msg is encapsulated in
* an HDLC frame. Receiving is similar EXCEPT that the component
* expects a special token byte be received before the data
* payload. The purpose of the token is to feed back an
* acknowledgement to the sender which serves as a crude form of
* flow-control.
*
* @author Phil Buonadonna
* @author Lewis Girod
* @author Ben Greenstein
* @date August 7 2005
*/
#include "AM.h"
#include "crc.h"
module SerialP {
provides {
interface Init;
interface SplitControl;
interface SendBytePacket;
interface ReceiveBytePacket;
}
uses {
interface SerialFrameComm;
interface Leds;
interface StdControl as SerialControl;
interface SerialFlush;
}
}
implementation {
#define NO_TX_SEQNO
enum {
RX_DATA_BUFFER_SIZE = 2,
TX_DATA_BUFFER_SIZE = 4,
SERIAL_MTU = 255,
SERIAL_VERSION = 1,
ACK_QUEUE_SIZE = 5,
};
enum {
RXSTATE_NOSYNC,
RXSTATE_PROTO,
RXSTATE_TOKEN,
RXSTATE_INFO,
RXSTATE_INACTIVE
};
enum {
TXSTATE_IDLE,
TXSTATE_PROTO,
TXSTATE_SEQNO,
TXSTATE_INFO,
TXSTATE_FCS1,
TXSTATE_FCS2,
TXSTATE_ENDFLAG,
TXSTATE_ENDWAIT,
TXSTATE_FINISH,
TXSTATE_ERROR,
TXSTATE_INACTIVE
};
typedef enum {
BUFFER_AVAILABLE,
BUFFER_FILLING,
BUFFER_COMPLETE,
} tx_data_buffer_states_t;
enum {
TX_ACK_INDEX = 0,
TX_DATA_INDEX = 1,
TX_BUFFER_COUNT = 2,
};
typedef struct {
uint8_t writePtr;
uint8_t readPtr;
uint8_t buf[RX_DATA_BUFFER_SIZE+1]; // one wasted byte: writePtr == readPtr means empty
} rx_buf_t;
typedef struct {
uint8_t state;
uint8_t buf;
} tx_buf_t;
typedef struct {
uint8_t writePtr;
uint8_t readPtr;
uint8_t buf[ACK_QUEUE_SIZE+1]; // one wasted byte: writePtr == readPtr means empty
} ack_queue_t;
/* Buffers */
rx_buf_t rxBuf;
tx_buf_t txBuf[TX_BUFFER_COUNT];
/* Receive State */
uint8_t rxState;
uint8_t rxByteCnt;
uint8_t rxProto;
uint8_t rxSeqno;
uint16_t rxCRC;
/* Transmit State */
norace uint8_t txState;
norace uint8_t txByteCnt;
norace uint8_t txProto;
norace uint8_t txSeqno;
norace uint16_t txCRC;
uint8_t txPending;
norace uint8_t txIndex;
/* Ack Queue */
ack_queue_t ackQ;
bool offPending = FALSE;
// Prototypes
inline void txInit();
inline void rxInit();
inline void ackInit();
inline bool ack_queue_is_full();
inline bool ack_queue_is_empty();
inline void ack_queue_push(uint8_t token);
inline uint8_t ack_queue_top();
uint8_t ack_queue_pop();
inline void rx_buffer_init();
inline bool rx_buffer_is_full();
inline bool rx_buffer_is_empty();
inline void rx_buffer_push(uint8_t data);
inline uint8_t rx_buffer_top();
inline uint8_t rx_buffer_pop();
inline uint16_t rx_current_crc();
void rx_state_machine(bool isDelimeter, uint8_t data);
void MaybeScheduleTx();
task void RunTx();
inline void txInit(){
uint8_t i;
atomic for (i = 0; i < TX_BUFFER_COUNT; i++) txBuf[i].state = BUFFER_AVAILABLE;
txState = TXSTATE_IDLE;
txByteCnt = 0;
txProto = 0;
txSeqno = 0;
txCRC = 0;
txPending = FALSE;
txIndex = 0;
}
inline void rxInit(){
rxBuf.writePtr = rxBuf.readPtr = 0;
rxState = RXSTATE_NOSYNC;
rxByteCnt = 0;
rxProto = 0;
rxSeqno = 0;
rxCRC = 0;
}
inline void ackInit(){
ackQ.writePtr = ackQ.readPtr = 0;
}
command error_t Init.init() {
txInit();
rxInit();
ackInit();
return SUCCESS;
}
/*
* buffer and queue manipulation
*/
inline bool ack_queue_is_full(){
uint8_t tmp, tmp2;
atomic {
tmp = ackQ.writePtr;
tmp2 = ackQ.readPtr;
}
if (++tmp > ACK_QUEUE_SIZE) tmp = 0;
return (tmp == tmp2);
}
inline bool ack_queue_is_empty(){
bool ret;
atomic ret = (ackQ.writePtr == ackQ.readPtr);
return ret;
}
inline void ack_queue_push(uint8_t token) {
if (!ack_queue_is_full()){
atomic {
ackQ.buf[ackQ.writePtr] = token;
if (++ackQ.writePtr > ACK_QUEUE_SIZE) ackQ.writePtr = 0;
}
MaybeScheduleTx();
}
}
inline uint8_t ack_queue_top() {
uint8_t tmp = 0;
atomic {
if (!ack_queue_is_empty()){
tmp = ackQ.buf[ackQ.readPtr];
}
}
return tmp;
}
uint8_t ack_queue_pop() {
uint8_t retval = 0;
atomic {
if (ackQ.writePtr != ackQ.readPtr){
retval = ackQ.buf[ackQ.readPtr];
if (++(ackQ.readPtr) > ACK_QUEUE_SIZE) ackQ.readPtr = 0;
}
}
return retval;
}
/*
* Buffer Manipulation
*/
inline void rx_buffer_init(){
rxBuf.writePtr = rxBuf.readPtr = 0;
}
inline bool rx_buffer_is_full() {
uint8_t tmp = rxBuf.writePtr;
if (++tmp > RX_DATA_BUFFER_SIZE) tmp = 0;
return (tmp == rxBuf.readPtr);
}
inline bool rx_buffer_is_empty(){
return (rxBuf.readPtr == rxBuf.writePtr);
}
inline void rx_buffer_push(uint8_t data){
rxBuf.buf[rxBuf.writePtr] = data;
if (++(rxBuf.writePtr) > RX_DATA_BUFFER_SIZE) rxBuf.writePtr = 0;
}
inline uint8_t rx_buffer_top(){
uint8_t tmp = rxBuf.buf[rxBuf.readPtr];
return tmp;
}
inline uint8_t rx_buffer_pop(){
uint8_t tmp = rxBuf.buf[rxBuf.readPtr];
if (++(rxBuf.readPtr) > RX_DATA_BUFFER_SIZE) rxBuf.readPtr = 0;
return tmp;
}
inline uint16_t rx_current_crc(){
uint16_t crc;
uint8_t tmp = rxBuf.writePtr;
tmp = (tmp == 0 ? RX_DATA_BUFFER_SIZE : tmp - 1);
crc = rxBuf.buf[tmp] & 0x00ff;
crc = (crc << 8) & 0xFF00;
tmp = (tmp == 0 ? RX_DATA_BUFFER_SIZE : tmp - 1);
crc |= (rxBuf.buf[tmp] & 0x00FF);
return crc;
}
task void startDoneTask() {
call SerialControl.start();
signal SplitControl.startDone(SUCCESS);
}
task void stopDoneTask() {
call SerialFlush.flush();
}
event void SerialFlush.flushDone(){
call SerialControl.stop();
signal SplitControl.stopDone(SUCCESS);
}
task void defaultSerialFlushTask(){
signal SerialFlush.flushDone();
}
default command void SerialFlush.flush(){
post defaultSerialFlushTask();
}
command error_t SplitControl.start() {
post startDoneTask();
return SUCCESS;
}
void testOff() {
bool turnOff = FALSE;
atomic {
if (txState == TXSTATE_INACTIVE &&
rxState == RXSTATE_INACTIVE) {
turnOff = TRUE;
}
}
if (turnOff) {
post stopDoneTask();
atomic offPending = FALSE;
}
else {
atomic offPending = TRUE;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -