radioserver.c
来自「simulink real-time workshop for dragon12」· C语言 代码 · 共 1,395 行 · 第 1/3 页
C
1,395 行
/**
* Code to manage the server's radio transceiver.
* See main.c for a simple example of a server application.
*
* Use at own risk, etc. Feel free to modify and distribute.
*
* @author Stephen Craig, 07/08/2006
*/
/* System macros (EXT_MODE, etc.) -- generated by 'gen_cpp_req_defines_h.tlc' */
#include "cpp_req_defines.h"
/* HAS_RFCOMMS: '0' : no RF communications, '1' : server, '2' : client, '3' : 'both' */
#if ((HAS_RFCOMMS == 1) | (HAS_RFCOMMS == 3))
/* ensure that SPI support is enabled */
#ifndef HAS_SPI
#define HAS_SPI 1
#endif
#include "radioServer.h" /* various macros etc */
#include <mc9s12dp256.h> /* derivative information */
//#include "sci0.h" /* support for SCI0 */
#include "spi.h" /* support for SPI */
#include "mc_signal.h" /* low-level support for SCI0 */
#include "rb_.h" /* ring buffer implementation */
/* define a macro to set the current module state */
#define setState(s) tickCounter = 0, moduleState = s
/* RF baud rate macro.
Include the macro for 1 MBits (may be necessary for large ranges)
Remove macro for 2 MBits */
// #define SLOW_RF_BAUD_RATE
#define CE PTM_PTM7 /* chip enable */
#define CE_DDR DDRM_DDRM7 /* chip enable data direction */
/* macro used to print out some debug info */
// #define TO_DEBUG
// #define TO_DEBUG_ERROR_CONDITIONS
#ifdef TO_DEBUG
#define TO_DEBUG_ERROR_CONDITIONS
#endif
#ifdef TO_DEBUG
/* when debugging, make the whole thing run as slow as possible */
#define TICK_PRESCALAR 0xffff
#define WAIT_FOR_ACK_TICK_COUNT 17
#else
#ifdef SLOW_RF_BAUD_RATE
/* For 1MBits, nominal time between T~ and ACK is given by
128 + 5 + 128 + 5 + 2*(33 + 33 + 4*(5 + 2 + PAYLOAD_LEN)) = 710us */
#define TICK_PRESCALAR (24*712/TIMER_PRESCALER)
/* If every packet fails, then MAX_RT will occur in
(250*1 + 8*(5+2+PAYLOAD_LEN) + 138.5)*16 = 12712us = 16 ticks
Make it 17 to be conservative */
#define WAIT_FOR_ACK_TICK_COUNT (17)
#else
/* For 2MBits, nominal time between T~ and ACK is given by
128 + 5 + 128 + 5 + 1*(33 + 33 + 4*(5 + 2 + PAYLOAD_LEN)) = 488us */
#define TICK_PRESCALAR (24*490/TIMER_PRESCALER)
/* If every packet fails, then MAX_RT will occur in
(250*1 + 4*(5+2+PAYLOAD_LEN) + 138.5)*16 = 8712us = 18 ticks
Make it 19 to be conservative */
#define WAIT_FOR_ACK_TICK_COUNT (19)
#endif
#endif
/* To ensure the server has timed out, need to wait an extra two ticks.
this is because the server's ticks could potentially be aligned to
just miss the interrupt, and then just miss again on the other end. */
#define TIME_OUT_TICK_COUNT (WAIT_FOR_ACK_TICK_COUNT + 2)
#define TICK_REGISTER TC0
#define TICK_ENABLE TIE_C0I /* changed to timer channel 0, interrupt enable - fw-09-06 */
#define TICK_INTERRUPT TFLG1_C0F
// RadioServer_OnTick
/* a delay is required for the client to enter receive mode */
#define WAIT_FOR_CLIENT_TICK_COUNT 1
#define ADDRESS_LENGTH 5 /* Address length (should be 5) */
/* define useful mnemonics */
/* these are all reads */
#define R_CONFIG 0x00 // Configuration Register
#define R_EN_AA 0x01 // Enable Auto Acknowledge
#define R_EN_RXADDR 0x02 // Enable RX Addresses
#define R_SETUP_AW 0x03 // Setup of Address Widths
#define R_SETUP_RETR 0x04 // Setup of Automatic Retransmission
#define R_RF_CH 0x05 // RF Channel
#define R_RF_SETUP 0x06 // RF Setup
#define R_STATUS 0x07 // Status
#define R_OBSERVE_TX 0x08 // Transmit Observe register
#define R_CD 0x09 // Carrier Detect
#define R_RX_ADDR_P0 0x0a // Receive address data pipe 0
#define R_RX_ADDR_P1 0x0b // Receive address data pipe 1
#define R_RX_ADDR_P2 0x0c // Receive address data pipe 2
#define R_RX_ADDR_P3 0x0d // Receive address data pipe 3
#define R_RX_ADDR_P4 0x0e // Receive address data pipe 4
#define R_RX_ADDR_P5 0x0f // Receive address data pipe 5
#define R_TX_ADDR 0x10 // Transmit address
#define R_RX_PW_0 0x11 // Number of bytes in RX payload for pipe 0
#define R_RX_PW_1 0x12 // Number of bytes in RX payload for pipe 1
#define R_RX_PW_2 0x13 // Number of bytes in RX payload for pipe 2
#define R_RX_PW_3 0x14 // Number of bytes in RX payload for pipe 3
#define R_RW_PW_4 0x15 // Number of bytes in RX payload for pipe 4
#define R_RW_PW_5 0x16 // Number of bytes in RX payload for pipe 5
#define R_FIFO_STATUS 0x17 // FIFO Status register
/* these are all writes */
#define W_CONFIG 0x20 // Configuration Register
#define W_EN_AA 0x21 // Enable Auto Acknowledge
#define W_EN_RXADDR 0x22 // Enable RX Addresses
#define W_SETUP_AW 0x23 // Setup of Address Widths
#define W_SETUP_RETR 0x24 // Setup of Automatic Retransmission
#define W_RF_CH 0x25 // RF Channel
#define W_RF_SETUP 0x26 // RF Setup
#define W_STATUS 0x27 // Status
#define W_OBSERVE_TX 0x28 // Transmit Observe register
#define W_RX_ADDR_P0 0x2a // Receive address data pipe 0
#define W_RX_ADDR_P1 0x2b // Receive address data pipe 1
#define W_RX_ADDR_P2 0x2c // Receive address data pipe 2
#define W_RX_ADDR_P3 0x2d // Receive address data pipe 3
#define W_RX_ADDR_P4 0x2e // Receive address data pipe 4
#define W_RX_ADDR_P5 0x2f // Receive address data pipe 5
#define W_TX_ADDR 0x30 // Transmit address
#define W_RX_PW_0 0x31 // Number of bytes in RX payload for pipe 0
#define W_RX_PW_1 0x32 // Number of bytes in RX payload for pipe 1
#define W_RX_PW_2 0x33 // Number of bytes in RX payload for pipe 2
#define W_RX_PW_3 0x34 // Number of bytes in RX payload for pipe 3
#define W_RX_PW_4 0x35 // Number of bytes in RX payload for pipe 4
#define W_RX_PW_5 0x36 // Number of bytes in RX payload for pipe 5
#define R_RX_PAYLOAD 0x61 // Read RX-payload
#define W_TX_PAYLOAD 0xa0 // Write TX-payload
#define FLUSH_TX 0xe1 // Flush transmit buffer
#define FLUSH_RX 0xe2 // Flush receive buffer
#define REUSE_TX_PL 0xe3 // Reuse last transmission
#define NOP 0xff // No operation
/* Flags in STATUS */
#define RX_DR_MASK 0x40 /* Data Ready RX FIFO interrupt */
#define TX_DS_MASK 0x20 /* Data Sent TX FIFO interrupt */
#define MAX_RT_MASK 0x10 /* Max number of TX retries interrupt */
#define RX_P_NO_MASK 0x0e /* Mask to retrieve the data pipe number */
#define RX_EMPTY_MASK 0x01 /* Flag in FIFO_STATUS register */
#define RF_CH_MASK 0x7f /* To ensure 0 < rf_ch < 127 */
/* used to escape the characters matching the EOT token and ESCAPE */
#define RADIO_ESCAPE_CHAR 0xfe
/* end of transmission token */
#define RADIO_EOT_CHAR 0xfd
/* define states */
#define STATE_WAIT_FOR_EOT 0
#define STATE_WAIT_FOR_RECEIVE 1
#define STATE_WAIT_FOR_CLIENT 2
/* First byte of every message is a header byte */
/* This flag is set if the client (or server) has been reset. */
#define HEADER_RESET_MASK 0x80
/* This flag is set if the client (or server) acknowledges reset. */
#define HEADER_ACK_RESET_MASK 0x40
/* This bit is set in the header byte if the header is to be
interpretted as EOT */
#define HEADER_EOT_MASK 0x10
/* some macros to make some function calls a little more readable */
#define UPDATE_PRIM_RX 1
#define MAINTAIN_PRIM_RX 0
#define UPDATE_ADDRESS 1
#define MAINTAIN_ADDRESS 0
#define CLIENT_MODIFIED 1
#define CLIENT_UNMODIFIED 0
/* Last byte of client 0's address, etc
Must match the address specified in radioClient.c */
#define CLIENT_TAIL_0 0xc2
#define CLIENT_TAIL_1 0xc3
#define CLIENT_TAIL_2 0xc4
#define CLIENT_TAIL_3 0xc5
#define CLIENT_TAIL_4 0xc6
const unsigned char clientAddrTail[CLIENT_COUNT_MAX] = {
CLIENT_TAIL_0, CLIENT_TAIL_1, CLIENT_TAIL_2,
CLIENT_TAIL_3, CLIENT_TAIL_4
};
/* declare space for rx and tx addresses */
unsigned char rx1_address_array[ADDRESS_LENGTH];
unsigned char tx_address_array[ADDRESS_LENGTH];
#define RB_TX_FULL(b) \
( ((unsigned char)((b)->out - (b)->in) <= PAYLOAD_LEN - 3) \
&& ((b)->in != (b)->out) \
)
#define RB_TX_PUSH(b, v) \
(RB_TX_FULL(b) ? 1 : \
((b)->start[(b)->in++] = (v), (b)->nElements++, 0) \
)
typedef struct {
/* the index of the state in the commStates array */
unsigned char id;
/* memory for outgoing data, has to be 256 bytes */
unsigned char outBuf[256];
/* memory for incoming data, has to be 256 bytes */
unsigned char inBuf[256];
/* declare pointers to rb data structures */
rbType outRB;
rbType inRB;
/* store the last tID sent here */
unsigned char lastTID;
/* flags to store reset status */
unsigned char reset;
unsigned short failureCount;
} commStateType;
commStateType commStates[CLIENT_COUNT];
commStateType *cc = NULL;
/* store the current state */
unsigned char moduleState;
/* used by the server to determine which clients are active */
unsigned char clientFlags;
/* incremented every time there is a tick */
unsigned char tickCounter;
/* Determines the next client to poll.
Returns true if the cc was modified. */
unsigned char RadioServer_NextClient() {
// determine the next client flag set after the cc
switch(cc->id) {
case 0:
if(clientFlags & CLIENT_FLAG_1) {
cc = &commStates[1];
} else if(clientFlags & CLIENT_FLAG_2) {
cc = &commStates[2];
} else if(clientFlags & CLIENT_FLAG_3) {
cc = &commStates[3];
} else if(clientFlags & CLIENT_FLAG_4) {
cc = &commStates[4];
} else {
return CLIENT_UNMODIFIED;
}
return CLIENT_MODIFIED;
case 1:
if(clientFlags & CLIENT_FLAG_2) {
cc = &commStates[2];
} else if(clientFlags & CLIENT_FLAG_3) {
cc = &commStates[3];
} else if(clientFlags & CLIENT_FLAG_4) {
cc = &commStates[4];
} else if(clientFlags & CLIENT_FLAG_0) {
cc = &commStates[0];
} else {
return CLIENT_UNMODIFIED;
}
return CLIENT_MODIFIED;
case 2:
if(clientFlags & CLIENT_FLAG_3) {
cc = &commStates[3];
} else if(clientFlags & CLIENT_FLAG_4) {
cc = &commStates[4];
} else if(clientFlags & CLIENT_FLAG_0) {
cc = &commStates[0];
} else if(clientFlags & CLIENT_FLAG_1) {
cc = &commStates[1];
} else {
return CLIENT_UNMODIFIED;
}
return CLIENT_MODIFIED;
case 3:
if(clientFlags & CLIENT_FLAG_4) {
cc = &commStates[4];
} else if(clientFlags & CLIENT_FLAG_0) {
cc = &commStates[0];
} else if(clientFlags & CLIENT_FLAG_1) {
cc = &commStates[1];
} else if(clientFlags & CLIENT_FLAG_2) {
cc = &commStates[2];
} else {
return CLIENT_UNMODIFIED;
}
return CLIENT_MODIFIED;
case 4:
if(clientFlags & CLIENT_FLAG_0) {
cc = &commStates[0];
} else if(clientFlags & CLIENT_FLAG_1) {
cc = &commStates[1];
} else if(clientFlags & CLIENT_FLAG_2) {
cc = &commStates[2];
} else if(clientFlags & CLIENT_FLAG_3) {
cc = &commStates[3];
} else {
cc = &commStates[4];
return CLIENT_UNMODIFIED;
}
return CLIENT_MODIFIED;
}
return CLIENT_UNMODIFIED;
}
/*
Transmit() is a private procedure that is only called when the
server is in possession of the EOT token, or the EOT needs to
be regenerated.
*/
void RadioServer_Transmit(unsigned char updateAddresses) {
unsigned char i, haveSentEOT, header, data;
#ifdef TO_DEBUG
SCI0_OutString("T\r\n"); /* enter Transmit */
#endif
/* can only re-configure if in stand-by mode */
CE = 0;
/* a good idea to clear all interrupts and flush buffers first */
SPI_OutChar(FLUSH_TX);
SPI_OutChar(FLUSH_RX);
/* clears all interrupts */
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 0 PRIM_RX : PTX
Enter transmit mode
*/
SPI_OutChar2(W_CONFIG, 0x7e);
if(updateAddresses) {
/* Append the tail of the current client address to
clientAddressHeader */
tx_address_array[0] = clientAddrTail[cc->id];
/*
RX_ADDR_P0 Register
Receive address for current client (for ACK).
*/
SPI_OutChar3(W_RX_ADDR_P0, tx_address_array, ADDRESS_LENGTH);
/*
TX_ADDR Register
Transmit address for current client.
*/
SPI_OutChar3(W_TX_ADDR, tx_address_array, ADDRESS_LENGTH);
}
/* download the next segment */
while(SPI0SR_SPTEF == 0) {}
/* begin SPI segment */
CSN = 0;
/* output the write transmit buffer command */
SPI0DR = W_TX_PAYLOAD;
SPI_Pause();
/* Determine what the header byte should be */
header = cc->reset;
if(header & HEADER_RESET_MASK) {
/* if we've reset recently, make sure we start transmitting
from the start of the transmit buffer */
RB_SET_OUT(&cc->outRB, 0);
header |= HEADER_EOT_MASK;
}
/* determine whether we should send EOT in header byte */
if(RB_EMPTY(&cc->outRB)) {
header |= HEADER_EOT_MASK;
}
/* output the header byte */
while(SPI0SR_SPTEF == 0) {}
SPI0DR = header;
SPI_Pause();
/* work out if EOT was set in header */
haveSentEOT = (header & HEADER_EOT_MASK) != 0;
/* output the rID */
while(SPI0SR_SPTEF == 0) {}
SPI0DR = cc->inRB.in;
SPI_Pause();
/* output the tID */
while(SPI0SR_SPTEF == 0) {}
SPI0DR = cc->outRB.out;
SPI_Pause();
/* store what the last tID sent was */
cc->lastTID = cc->outRB.out;
/* fill the remaining bytes */
for(i=3; i<PAYLOAD_LEN; i++) {
while(SPI0SR_SPTEF == 0) {}
if(haveSentEOT == 0) {
if(RB_EMPTY(&cc->outRB)) {
/* if there's no more data to be sent, then EOT */
SPI0DR = RADIO_EOT_CHAR;
haveSentEOT = 1;
} else {
/* check what the next byte is to send */
RB_PEEK(&cc->outRB, &data);
if(data != RADIO_ESCAPE_CHAR
&& data != RADIO_EOT_CHAR) {
/* the byte is not a special token, transmit it */
RB_POP(&cc->outRB, &SPI0DR);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?