📄 serialp.nc
字号:
command error_t SplitControl.stop() {
atomic {
if (rxState == RXSTATE_NOSYNC) {
rxState = RXSTATE_INACTIVE;
}
}
atomic {
if (txState == TXSTATE_IDLE) {
txState = TXSTATE_INACTIVE;
}
}
testOff();
return SUCCESS;
}
/*
* Receive Path
*/
async event void SerialFrameComm.delimiterReceived(){
rx_state_machine(TRUE,0);
}
async event void SerialFrameComm.dataReceived(uint8_t data){
rx_state_machine(FALSE,data);
}
bool valid_rx_proto(uint8_t proto){
switch (proto){
case SERIAL_PROTO_PACKET_ACK:
return TRUE;
case SERIAL_PROTO_ACK:
case SERIAL_PROTO_PACKET_NOACK:
default:
return FALSE;
}
}
void rx_state_machine(bool isDelimeter, uint8_t data){
switch (rxState) {
case RXSTATE_NOSYNC:
if (isDelimeter) {
rxInit();
rxState = RXSTATE_PROTO;
}
break;
case RXSTATE_PROTO:
if (!isDelimeter){
rxCRC = crcByte(rxCRC,data);
rxState = RXSTATE_TOKEN;
rxProto = data;
if (!valid_rx_proto(rxProto))
goto nosync;
// only supports serial proto packet ack
if (rxProto != SERIAL_PROTO_PACKET_ACK){
goto nosync;
}
if (signal ReceiveBytePacket.startPacket() != SUCCESS){
goto nosync;
}
}
break;
case RXSTATE_TOKEN:
if (isDelimeter) {
goto nosync;
}
else {
rxSeqno = data;
rxCRC = crcByte(rxCRC,rxSeqno);
rxState = RXSTATE_INFO;
}
break;
case RXSTATE_INFO:
if (rxByteCnt < SERIAL_MTU){
if (isDelimeter) { /* handle end of frame */
if (rxByteCnt >= 2) {
if (rx_current_crc() == rxCRC) {
signal ReceiveBytePacket.endPacket(SUCCESS);
ack_queue_push(rxSeqno);
goto nosync;
}
else {
goto nosync;
}
}
else {
goto nosync;
}
}
else { /* handle new bytes to save */
if (rxByteCnt >= 2){
signal ReceiveBytePacket.byteReceived(rx_buffer_top());
rxCRC = crcByte(rxCRC,rx_buffer_pop());
}
rx_buffer_push(data);
rxByteCnt++;
}
}
/* no valid message.. */
else {
goto nosync;
}
break;
default:
goto nosync;
}
goto done;
nosync:
/* reset all counters, etc */
rxInit();
call SerialFrameComm.resetReceive();
signal ReceiveBytePacket.endPacket(FAIL);
if (offPending) {
rxState = RXSTATE_INACTIVE;
testOff();
}
/* if this was a flag, start in proto state.. */
else if (isDelimeter) {
rxState = RXSTATE_PROTO;
}
done:
}
/*
* Send Path
*/
void MaybeScheduleTx() {
atomic {
if (txPending == 0) {
if (post RunTx() == SUCCESS) {
txPending = 1;
}
}
}
}
async command error_t SendBytePacket.completeSend(){
bool ret = FAIL;
atomic {
txBuf[TX_DATA_INDEX].state = BUFFER_COMPLETE;
ret = SUCCESS;
}
return ret;
}
async command error_t SendBytePacket.startSend(uint8_t b){
bool not_busy = FALSE;
atomic {
if (txBuf[TX_DATA_INDEX].state == BUFFER_AVAILABLE){
txBuf[TX_DATA_INDEX].state = BUFFER_FILLING;
txBuf[TX_DATA_INDEX].buf = b;
not_busy = TRUE;
}
}
if (not_busy) {
MaybeScheduleTx();
return SUCCESS;
}
return EBUSY;
}
task void RunTx() {
uint8_t idle;
uint8_t done;
uint8_t fail;
/*
the following trigger MaybeScheduleTx, which starts at most one RunTx:
1) adding an ack to the ack queue (ack_queue_push())
2) starting to send a packet (SendBytePacket.startSend())
3) failure to send start delimiter in RunTx
4) putDone:
*/
error_t result = SUCCESS;
bool send_completed = FALSE;
bool start_it = FALSE;
atomic {
txPending = 0;
idle = (txState == TXSTATE_IDLE);
done = (txState == TXSTATE_FINISH);
fail = (txState == TXSTATE_ERROR);
if (done || fail){
txState = TXSTATE_IDLE;
txBuf[txIndex].state = BUFFER_AVAILABLE;
}
}
/* if done, call the send done */
if (done || fail) {
txSeqno++;
if (txProto == SERIAL_PROTO_ACK){
ack_queue_pop();
}
else {
result = done ? SUCCESS : FAIL;
send_completed = TRUE;
}
idle = TRUE;
}
/* if idle, set up next packet to TX */
if (idle) {
bool goInactive;
atomic goInactive = offPending;
if (goInactive) {
atomic txState = TXSTATE_INACTIVE;
}
else {
/* acks are top priority */
uint8_t myAckState;
uint8_t myDataState;
atomic {
myAckState = txBuf[TX_ACK_INDEX].state;
myDataState = txBuf[TX_DATA_INDEX].state;
}
if (!ack_queue_is_empty() && myAckState == BUFFER_AVAILABLE) {
atomic {
txBuf[TX_ACK_INDEX].state = BUFFER_COMPLETE;
txBuf[TX_ACK_INDEX].buf = ack_queue_top();
}
txProto = SERIAL_PROTO_ACK;
txIndex = TX_ACK_INDEX;
start_it = TRUE;
}
else if (myDataState == BUFFER_FILLING || myDataState == BUFFER_COMPLETE){
txProto = SERIAL_PROTO_PACKET_NOACK;
txIndex = TX_DATA_INDEX;
start_it = TRUE;
}
else {
/* nothing to send now.. */
}
}
}
else {
/* we're in the middle of transmitting */
}
if (send_completed){
signal SendBytePacket.sendCompleted(result);
}
if (txState == TXSTATE_INACTIVE) {
testOff();
return;
}
if (start_it){
/* OK, start transmitting ! */
atomic {
txCRC = 0;
txByteCnt = 0;
txState = TXSTATE_PROTO;
}
if (call SerialFrameComm.putDelimiter() != SUCCESS) {
atomic txState = TXSTATE_ERROR;
MaybeScheduleTx();
}
}
}
async event void SerialFrameComm.putDone() {
{
error_t txResult = SUCCESS;
switch (txState) {
case TXSTATE_PROTO:
txResult = call SerialFrameComm.putData(txProto);
#ifdef NO_TX_SEQNO
txState = TXSTATE_INFO;
#else
txState = TXSTATE_SEQNO;
#endif
txCRC = crcByte(txCRC,txProto);
break;
case TXSTATE_SEQNO:
txResult = call SerialFrameComm.putData(txSeqno);
txState = TXSTATE_INFO;
txCRC = crcByte(txCRC,txSeqno);
break;
case TXSTATE_INFO:
atomic {
txResult = call SerialFrameComm.putData(txBuf[txIndex].buf);
txCRC = crcByte(txCRC,txBuf[txIndex].buf);
++txByteCnt;
if (txIndex == TX_DATA_INDEX){
uint8_t nextByte;
nextByte = signal SendBytePacket.nextByte();
if (txBuf[txIndex].state == BUFFER_COMPLETE || txByteCnt >= SERIAL_MTU){
txState = TXSTATE_FCS1;
}
else { /* never called on ack b/c ack is BUFFER_COMPLETE initially */
txBuf[txIndex].buf = nextByte;
}
}
else { // TX_ACK_INDEX
txState = TXSTATE_FCS1;
}
}
break;
case TXSTATE_FCS1:
txResult = call SerialFrameComm.putData(txCRC & 0xff);
txState = TXSTATE_FCS2;
break;
case TXSTATE_FCS2:
txResult = call SerialFrameComm.putData((txCRC >> 8) & 0xff);
txState = TXSTATE_ENDFLAG;
break;
case TXSTATE_ENDFLAG:
txResult = call SerialFrameComm.putDelimiter();
txState = TXSTATE_ENDWAIT;
break;
case TXSTATE_ENDWAIT:
txState = TXSTATE_FINISH;
case TXSTATE_FINISH:
MaybeScheduleTx();
break;
case TXSTATE_ERROR:
default:
txResult = FAIL;
break;
}
if (txResult != SUCCESS) {
txState = TXSTATE_ERROR;
MaybeScheduleTx();
}
}
}
default event void SplitControl.startDone(error_t err) {}
default event void SplitControl.stopDone(error_t err) {}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -