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 + -
显示快捷键?