📄 radioclient.c
字号:
CSN = 1;
#ifdef TO_DEBUG
SCI0_OutString("T~\r\n"); /* exit Transmit() */
#endif
// Pulse CE to start transmission (must be > 10us)
CE = 1;
}
/*
EnterReceive is a private procedure to configure the module for
receive mode.
Must be in a standby-mode to call this method.
*/
void RadioClient_EnterReceive() {
/* a good idea to clear all interrupts and flush buffers first */
SPI_OutChar(FLUSH_TX);
SPI_OutChar(FLUSH_RX);
SPI_OutChar2(W_STATUS, RX_DR_MASK | TX_DS_MASK | MAX_RT_MASK);
/*
bit CONFIG Register
7 0 Reserved
6 1 MASK_RX_DR : Don't reflect RX_DR on IRQ pin
5 1 MASK_TX_DS : Don't reflect TX_DS on IRQ pin
4 1 MASK_MAX_RT : Don't reflect MAX_RT on IRQ pin
3 1 EN_CRC : Enable CRC
2 1 CRCO : 2 byte CRC
1 1 PWR_UP : Power Up
0 1 PRIM_RX : PRX
Enter receive mode
*/
SPI_OutChar2(W_CONFIG, 0x7f);
CE = 1;
}
/*
OnReceive() is a private procedure which is called when the
RX_DR flag is set in the STATUS register.
Returns 1 if have received EOT, otherwise returns 0
*/
void RadioClient_OnReceive() {
unsigned char header, rID, tID, in, i, toEscape, haveReceivedEOT, trustData;
#ifdef TO_DEBUG
SCI0_OutString("R\r\n"); /* enter onReceive() */
#endif
/* use in as a dummy */
in = SPI0SR;
in = SPI0DR; // clear SPIF
toEscape = haveReceivedEOT = 0;
while(SPI0SR_SPTEF == 0) {}
CSN = 0;
/* send the read command */
SPI0DR = R_RX_PAYLOAD;
SPI_Pause();
in = SPI_InChar(); // discard the status byte
while(SPI0SR_SPTEF == 0) {}
SPI0DR = NOP; // output a dummy value to generate SCK
SPI_Pause();
/* read in header byte */
header = SPI_InChar();
while(SPI0SR_SPTEF == 0) {}
SPI0DR = NOP; // output a dummy value to generate SCK
SPI_Pause();
/* read in rID */
rID = SPI_InChar();
while(SPI0SR_SPTEF == 0) {}
SPI0DR = NOP; // output a dummy value to generate SCK
SPI_Pause();
/* read in tID */
tID = SPI_InChar();
if(tID == cc->inRB.in) {
/* server's tID matches expected rID, i.e. the server's sending
requested byte next, so can probably trust */
trustData = 1;
} else {
/* the server is sending a byte out of order, probably cannot
trust */
trustData = 0;
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Invalid tID: ");
SCI0_OutUDec(tID);
SCI0_OutString(", expected ");
SCI0_OutUDec(cc->inRB.in);
SCI0_OutString("\r\n");
#endif
}
/* may be able to trust the data if the client has been reset
recently */
if(cc->reset & HEADER_RESET_MASK) {
/* client has been reset recently */
if(header & HEADER_ACK_RESET_MASK) {
/* server has acknowledged client reset */
cc->reset &= ~HEADER_RESET_MASK;
/* what follows must be valid, since the server has ack'd
reset */
trustData = 1;
#ifdef TO_DEBUG
SCI0_OutString("ACK'd reset\r\n");
#endif
} else {
/* server has not acknowledged reset, cannot trust data,
even if had a "valid" tID */
trustData = 0;
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Not ACK'd reset\r\n");
#endif
}
}
/* if the server itself has been reset, we can trust the data */
if(header & HEADER_RESET_MASK) {
/* Server has been reset!
This can be bad if there's still data in the buffer,
may get data queued from another session => clean them */
RadioClient_CleanOut();
RadioClient_CleanIn();
/* acknowledge to server that the reset has been a success */
cc->reset |= HEADER_ACK_RESET_MASK;
cc->failureCount = 0;
/* what follows is a new byte (it's byte 0) */
trustData = 1;
#ifdef TO_DEBUG
SCI0_OutString("Server reset\r\n");
#endif
} else {
/* if server hasn't reset, clear ACK_RESET flag */
cc->reset &= ~HEADER_ACK_RESET_MASK;
}
#ifdef TO_DEBUG_ERROR_CONDITIONS
if(!trustData) {
SCI0_OutString("Discard data\r\n");
}
#endif
haveReceivedEOT = (header & HEADER_EOT_MASK) != 0;
for(i=3; i<PAYLOAD_LEN; i++) {
while(SPI0SR_SPTEF == 0) {}
SPI0DR = NOP; // output a dummy value to generate SCK
SPI_Pause();
in = SPI_InChar(); // read in potentially valid byte
if(trustData && (haveReceivedEOT == 0)) {
if(toEscape == 0) { // last character in wasn't the ESCAPE char
switch(in) {
case RADIO_ESCAPE_CHAR:
toEscape = 1;
break;
case RADIO_EOT_CHAR:
/* have received EOT */
haveReceivedEOT = 1;
break;
default:
if(RB_PUSH(&cc->inRB, in)) {
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Dropped char: ");
SCI0_OutUHex(in);
SCI0_OutString("\r\n");
#endif
}
break;
}
} else {
if(RB_PUSH(&cc->inRB, in)) {
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Dropped char: ");
SCI0_OutUHex(in);
SCI0_OutString("\r\n");
#endif
}
toEscape = 0;
}
}
}
CSN = 1;
#ifdef TO_DEBUG_ERROR_CONDITIONS
if(cc->outRB.out != rID) {
SCI0_OutString("Invalid rID: ");
SCI0_OutUDec(rID);
SCI0_OutString(", expected ");
SCI0_OutUDec(cc->outRB.out);
SCI0_OutString("\r\n");
}
#endif
RB_SET_OUT(&cc->outRB, rID);
/* no more data in RX buffer */
#ifdef TO_DEBUG
SCI0_OutString("R~"); /* exit onReceive() */
#endif
}
/*
Setup timer.
*/
void RadioClient_RestartTick() {
TICK_ENABLE = 1;
TICK_REGISTER = TICK_PRESCALAR + TCNT;
TICK_INTERRUPT = 1;
}
/* beginning of the interrupt service routine ================================= */
#pragma CODE_SEG __NEAR_SEG NON_BANKED /* Interrupt section for this module. Placement will be in NON_BANKED area. */
/**
* Called regularly.
*/
__interrupt void RadioClient_OnTick(void) {
unsigned char status;
/* first deal with the timer flags */
TICK_ENABLE = 0;
TICK_INTERRUPT = 1;
/* re-enable all interrupts (to allow servicing of RxD interrupt) */
asm cli // re-enable interrupts to allow this one to be interrupted
/* always increment the tick counter */
tickCounter++;
#ifdef TO_DEBUG
SCI0_OutChar('`'); /* tick */
#endif
switch(moduleState) {
case STATE_WAIT_FOR_EOT:
#ifdef TO_DEBUG
SCI0_OutChar('@');
#endif
/* read status (one byte long) */
SPI_Read(R_STATUS, &status, 1);
if(status & TX_DS_MASK) {
/* successfully transmitted PAYLOAD_LEN bytes */
#ifdef TO_DEBUG
SCI0_OutString("T'd\r\n"); /* successful transmit */
#endif
/* clear interrupt */
SPI_OutChar2(W_STATUS, TX_DS_MASK);
/* Since EOT was transmitted, client is about to send,
=> enter RX */
RadioClient_EnterReceive();
setState(STATE_WAIT_FOR_RECEIVE);
} else if(status & MAX_RT_MASK) {
/* module has informed us there's been a timeout */
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("F'd\r\n"); /* explicit timeout */
#endif
/* clear interrupt */
SPI_OutChar2(W_STATUS, MAX_RT_MASK);
RB_SET_OUT(&cc->outRB, cc->lastTID);
cc->failureCount++;
RadioClient_EnterReceive();
setState(STATE_WAIT_FOR_RECEIVE);
} else if(tickCounter >= WAIT_FOR_ACK_TICK_COUNT) {
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Q'd\r\n"); /* implicit timeout */
#endif
/* this is a very bizarre state to get into, treat it similarly
to as though we had explicitly received a timeout */
RB_SET_OUT(&cc->outRB, cc->lastTID);
cc->failureCount++;
RadioClient_EnterReceive();
setState(STATE_WAIT_FOR_RECEIVE);
}
break;
case STATE_WAIT_FOR_RECEIVE:
#ifdef TO_DEBUG
SCI0_OutChar('r'); /* wait in receive */
#endif
/* read status (one byte long) */
SPI_Read(R_STATUS, &status, 1);
if(status & RX_DR_MASK) {
#ifdef TO_DEBUG
SCI0_OutString("R'd"); /* successful receive */
#endif
/* to be pedantic, should ensure that the RX_P_NO matches
the receive address pipe (1) */
if((((status & RX_P_NO_MASK) >> 1) - 1) == cc->id) {
RadioClient_OnReceive();
setState(STATE_WAIT_FOR_SERVER);
} else {
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Wrong pipe number!");
SCI0_OutUHex((status & RX_P_NO_MASK) >> 1);
#endif
RadioClient_EnterReceive();
setState(STATE_WAIT_FOR_RECEIVE);
}
} else if(tickCounter >= TIME_OUT_TICK_COUNT) {
/* client has timed out */
#ifdef TO_DEBUG_ERROR_CONDITIONS
SCI0_OutString("Timeout");
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -