Library set up as dummy module on mbed to mimic Nordic.

Dependencies:   mbed-rtos mbed

rs485.cpp

Committer:
Stephen_NewVistas
Date:
2016-12-13
Revision:
2:9ab591cf81b8
Parent:
1:d6b18299a715

File content as of revision 2:9ab591cf81b8:

#include <string.h>
#include <stdio.h>

#include "rs485.h"

#define DEBUG

static list_t functionList = { .index = 0 };

Packet buildPacket;
static unsigned int buffPtr;
static unsigned char buffer[128+1];
int checksum;
int pState = START;
int returnState;
unsigned int plength;
unsigned char command;
int message;
static unsigned char packetBuffer[128];
static unsigned int packetBufferSize;

/************************** External Functions********************************
*   These functions need to be externall defined to be able to process packets
*    and to send out chars over the bus.
/************************** External Functions********************************/
extern int Bluetooth_ReceivePacket( Packet *_packet );
extern int Bluetooth_SendChar( unsigned char );
extern const unsigned char DEVADDRESS;

/******************************************************************************
 * Function void RegisterCommand( command , function )
 *
 * When a command is registered with this function it will be added to the function
 *  list. Once on the list, when a packet is received on the bus containing that
 *  command the associated function will get called and it will be passed the data
 *  within the packet as a parameter.
 *
 * PreCondition:    None
 *
 * Input:           'command'  - command byte
 *                  'function' - pointer to function to be called
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/
unsigned char RegisterCommand( unsigned char _command , void (*_function)( unsigned char *) ){
    functionList.list[ functionList.index ].function = _function;
    functionList.list[ functionList.index ].command = _command;
    functionList.index++;      
    return 0;
}

/******************************************************************************
 * Function void CheckFunction( Packet * )
 *
 * This passes in a packet and compares the command byte with a list of registered
 *  commands. If it finds a match it will call that function along with the data
 *  in the packet.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - packet containing command byte and data
 *                  
 * Output:          '1' - command matched and function called
 *                  '2' - no command found
 *
 * Side Effects:    None
 *
 *****************************************************************************/
int CheckFunction( Packet *_packet ){
    int i = 0;
    void (*Caller)(unsigned char *);
    for( i = 0 ; i < functionList.index ; i++ ){
        if( _packet->command == functionList.list[i].command ){
            Caller = (void (*)(unsigned char *))functionList.list[i].function;
            Caller( (unsigned char *)_packet->packetData );
            return 1;
        }
    }
    return 0;
}

void RS495_Init( void ){
       
}

/******************************************************************************
 * Function void SendAck( void )
 *
 * Sends an acknowledge byte over the bus. It calls an external function to
 *  handle the actual hardware communication.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - prebuilt packet to send
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/ 
static void SendAck( void ){
    #ifdef DEBUG
        pc.printf( "\n\rAck Sent.\n\r" );
    #endif // DEBUG
    unsigned char ack = ACKCHAR;
    Bluetooth_SendChar( ack );
}

/******************************************************************************
 * Function void SendNack( void )
 *
 * Sends a non acknowledge byte over the bus. It calls an external function to
 *  handle the actual hardware communication.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - prebuilt packet to send
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/ 
static void SendNack( void ){
    #ifdef DEBUG
        pc.printf( "\n\rNack Sent.\n\r" );
    #endif // DEBUG
    unsigned char nack = NAKCHAR;
    Bluetooth_SendChar( nack );
}

/******************************************************************************
 * Function void ProcessPacket( Packet *)
 *
 * Gets automatically called once an entire packet is successfully received.
 *  May modify what is done, but it should just pass the packet over to 
 *  an external function where it can be correctly handled.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - packet received on bus
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/ 
static int ProcessPacket( Packet *_packet ){
    return Bluetooth_ReceivePacket( _packet );
}

/******************************************************************************
 * Function void setResponse(int, int, int)
 *
 * This function sets the feedback information to be send in the master device.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - prebuilt packet to send
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/  
void SendMessage( void ){    
    int j = 0;
    Bluetooth_SendChar( packetBuffer[ j++ ] );
    while( j < packetBufferSize ){
        if( packetBuffer[ j ] ==  STARTPACK ){
            Bluetooth_SendChar( ESCAPE );     //  #SCD Added this line, I think it should be here
            Bluetooth_SendChar( 0x01 );
            j++;
        }
        else if( packetBuffer[ j ] == ESCAPE ){
            Bluetooth_SendChar( ESCAPE );
            Bluetooth_SendChar( ESCAPE );
            j++;
        }
        else if( packetBuffer[ j ] ==  STARTPOLL ){
            Bluetooth_SendChar( ESCAPE );
            Bluetooth_SendChar( 0x02 );
            j++;
        }
        else{
            Bluetooth_SendChar( packetBuffer[ j++ ] );
        }
    }    
}

/******************************************************************************
 * Function void SetResponse( Packet *_packet )
 *
 * This function sets the feedback information to be send in the master device.
 *
 * PreCondition:    None
 *
 * Input:           '_packet' - prebuilt packet to send
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/ 
 void SetResponsePacket( Packet *_packet ){
    packetBufferSize = getFormattedPacket(_packet, packetBuffer);    
    message = 1;
}

/******************************************************************************
 * Function void SetResponseWithData( unsigned char deviceID, unsigned char 
    command, unsigned char * data, unsigned short dataLength)
 *
 * This function sets the feedback information to be send in the master device.
 *
 * PreCondition:    None
 *
 * Input:           'deviceID'   - address where the packet is going
                    'command'    - command to be sent
                    '*data'      - point to unsiged char array packet with data
                    'dataLength' - length of 'data'
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 *****************************************************************************/ 
void SetResponseWithData( unsigned char deviceID, unsigned char command, unsigned char * data, unsigned short dataLength){
        
    //  build packet to be sent    
    Packet packet;    
    packet.deviceID = deviceID;
    packet.sourceID = DEVADDRESS;
    packet.command = command;
    packet.packetLength = dataLength;
    memcpy( packet.packetData , data , dataLength );
    packetBufferSize = getFormattedPacket(&packet, packetBuffer);
    
    //  print message to be sent
    #ifdef DEBUG
        pc.printf( "Message to send: ");    
        unsigned short length = 0;
        for( length = 1 ; length < ( dataLength + sizeof( packet.deviceID ) + sizeof( packet.sourceID ) + sizeof( packet.command ) + sizeof( packet.packetLength ) + 1 ) ; length++ ){
            pc.printf( "%x " , packetBuffer[ length ] );   
        }
        pc.printf( "\n\r" );
    #endif
    
    message = 1;
}

/******************************************************************************
 * Function void SerialHandler(unsigned char )
 *
 * This function handles the received data from the Serial Communication.
 *
 * PreCondition:    None
 *
 * Input:           'RXByte' - the received data from Serial Communication
 *
 *
 * Output:          None
 *
 * Side Effects:    Will call functions to send ACK, NACK and process a packet
 *                   once an entire packet is received.
 *
 *****************************************************************************/
void SerialHandler(unsigned char RXByte){
    
    #ifdef DEBUG
        pc.printf( "RXByte: %x" , RXByte );
    #endif


    //  check the incoming byte for special characters
    if( RXByte ==  STARTPACK ){                     //  start of packet byte
        #ifdef DEBUG
            pc.printf( " - STARTBYTE\n\r" );
        #endif
        pState = DEVICEADDRESS;                     //  move on to check the destination address
        buffPtr = 0;                                //  reset buffer pointer
        buffer[buffPtr++] = STARTPACK;              //  load RXByte into buffer
        checksum = STARTPACK;                       //  add to checksum
        return;                                     //  exit function, will be called again in next state
    }
    else if( RXByte == STARTPOLL ){                 //  poll byte
        #ifdef DEBUG
            pc.printf( " - STARTPOLL\n\r" );
        #endif
        pState = POLL;                              //  move on to check the distination address
        return;                                     //  exit function, will be called again in next state
    }
    else if( RXByte == ESCAPE ){                    //  escape byte
        if( pState == HANDLEESCAPE ){               //  if this is the second escape byte in a row
        }
        else{
            #ifdef DEBUG
                pc.printf( " - ESCAPE TO " );
            #endif
            returnState = pState;                   //  if this is the first escape byte, record the current state
            pState = HANDLEESCAPE;                  //  change state
            return;                                 //  exit function, will be called again in next state
        }
    }

    if( pState == HANDLEESCAPE ){                   //  if entering here RXByte needs to be unescaped
        switch( RXByte ){
            case 1:                                 //  unescape a 0x7F/Start of packet byte
                RXByte = 0x7F;
                #ifdef DEBUG
                    pc.printf( " -> %x" , RXByte );
                #endif
                break;

            case 2:                                 //  unescape a 0x8F/Poll byte
                RXByte = 0x8F;
                #ifdef DEBUG
                    pc.printf( " -> %x" , RXByte );
                #endif
                break;

            case ESCAPE:                            //  unescape a 0x8E/Escape byte
                RXByte = 0x8E;
                #ifdef DEBUG
                    pc.printf( " -> %x" , RXByte );
                #endif
                break;
        }
        pState = returnState;                       //  change back to state before escape byte received
    }

    switch( pState ){

        case POLL: //  of switch( pState )          //  poll state checks RXByte to see if there is an address match


            if( RXByte == DEVADDRESS ){             //  if the device is being polled...
                #ifdef DEBUG
                   pc.printf( " - Address Match: %x" , DEVADDRESS );
                #endif

                if( message ){                      //  if a message is available send it
                    #ifdef DEBUG
                        pc.printf( " - Message to Send\n\r" );
                    #endif
                    SendMessage();                //  #SCD haven't tested this
                    pState = RESPONSE;              //  change state to wait for ACK or NACK
                }
                else{                               //  device is pulled but no message to be sent
                    #ifdef DEBUG
                        pc.printf( " - No message to Send\n\r" );
                    #endif
                  SendAck();                        //  just send an ACK
                  pState = START;
                }
            }
            else{
                 pState = START;                    //  device not addressed, do nothing
            }
            break;

        case START: //  of switch( pState )         //  this state really does nothing and just waits for
            pState = START;                         //   if the device is not addressed in a packet
            break;

        case RESPONSE: //  of switch( pState )      //  a message was sent it last state and now this state is

            switch( RXByte ){

                case ACKCHAR:                       //  ACK is received - message successful, clear message to be sent
                        #ifdef DEBUG
                            pc.printf( " - ACK RECEIVED\n\r" );
                        #endif
                    message = 0;
                    pState = START;
                    break;

                case NAKCHAR:                       //  NACK is received - message not successful
                        #ifdef DEBUG
                            pc.printf( " - NACK RECEIVED\n\r" );
                        #endif
                    if( message ){                  //  if a message still needs to be sent, send again
                        SendMessage();
                        message = 0;                //  clear message after this seconda attempt to prevent too many tries
                        pState = RESPONSE;          //  set state to come by here next time around
                    }
                    else{                           //  if a NACK is received for the second time in a row
                        //#error #SCD               //  throw an error and do not resend
                        pc.printf( "Received two NACKs from master. Message failed.\n\r" );
                    }
                    break;

                default:
                        #ifdef DEBUG
                            pc.printf( " - EXPECTED ACK or NACK\n\r" );
                        #endif
                    pState = START;                 //  if neither an ACK nor NACK is received, reset state
                    break;

            }
            break;

        case DEVICEADDRESS: //  of switch( pState ) //  checks to see if device is addressed in current packet
                #ifdef DEBUG
                    pc.printf( " - DEVICEADDRESS\n\r" );
                #endif

            if( RXByte == DEVADDRESS ){
                #ifdef PRINT_ADDRESS_MATCH
                   pc.printf( "Address Match: %d\n\r" , DEVADDRESS );
                #endif

                pState = SOURCEADD;                 //  next state is grabbing the source device ID
                buffer[buffPtr++] = RXByte;         //  add RXByte to buffer
                buildPacket.deviceID = RXByte;      //  build packet
                checksum += RXByte;                 //  add RXByte to checksum
            }
            else{
                pState = START;                     //  if device is not addressed reset state
            }

            break;

        case SOURCEADD: //  of switch( pState )     //  records the source address of the packet
            #ifdef DEBUG
                pc.printf( " - SOURCEADD\n\r" );
            #endif

            pState = COLLECTCOMMAND;                //  state advances to get the command byte
            buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
            buildPacket.sourceID = RXByte;           //  build packet
            checksum += RXByte;                     //  add RXByte to checksum
            break;

        case COLLECTCOMMAND: //  of switch( pState )//  records the command byte of the packet
            #ifdef DEBUG
                pc.printf( " - COMMAND\n\r" );
            #endif

            command = RXByte;                       //  record command byte
            buildPacket.command = RXByte;           //  build packet
            pState = COLLECTCOUNT1;                 //  advance to get packetLength
            buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
            checksum += RXByte;                     //  add RXByte to checksum
            break;

        case COLLECTCOUNT1: //  of switch( pState ) //  records first byte of packetLength
            #ifdef DEBUG
                pc.printf( " - COUNT MSB \n\r" );
            #endif

            pState = COLLECTCOUNT2;                 //  advance state to get next byte of packetLength
            plength = RXByte;
            plength <<= 8;                  //  store byte in packetLength #SCD is this storing correctly?
            buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
            checksum += RXByte;                     //  add RXByte to checksum
            break;

        case COLLECTCOUNT2: //  of switch( pState ) //  records second byte of packetLength
            #ifdef DEBUG
                pc.printf( " - COUNT LSB\n\r" );
            #endif

            plength += RXByte;                      //  add RXByte to packetLength total
            buildPacket.packetLength = plength;     //  build packet
            buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
            checksum += RXByte;                     //  add RXByte to checksum
            if( plength == 0 )                      //  if packetLength is 0, advance to checksum state
                pState = COLLECTCHECKSUM;
            else                                    //  otherwise move on to collect packet payload
                pState = COLLECTPACKET;
            break;

        case COLLECTPACKET: //  of switch( pState ) //  collects packetData, enters this state multiple times
            #ifdef DEBUG
                pc.printf( " - PACKETDATA \n\r" );
            #endif

            plength--;                              //  decrement length
            buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
            checksum += RXByte;                     //  add RXByte to checksum

            if( plength == 0 ){                     //  if collected all packetData advance state
                pState = COLLECTCHECKSUM;
            }
            break;

        case COLLECTCHECKSUM://  of switch( pState )        // collects checksum of packet and checks for validity
            #ifdef DEBUG
                pc.printf( " - CHECKSUM\n\r" );
            #endif
            memcpy( &buildPacket.packetData , &buffer[6] , buildPacket.packetLength );

            if( RXByte == ( ( checksum* - 1 ) & 0xFF ) ){   //  compares RXByte with LSB of checksum
                message = 0;                                //  if checksum is correct clear message #SCD could a message be waiting?
                memset(packetBuffer, '\0', 128);            //  clear packetBuffer
               
                buffer[buffPtr++] = RXByte;             //  add RXByte to buffer
                
                #ifdef DEBUG
                   pc.printf( "Receive Buffer: " );       //  debug print received packet
                    unsigned int i = 0;
                    for( i = 0 ; i < buffPtr ; i++ ){
                       pc.printf( "%x " , buffer[ i ] );
                    }
                   pc.printf( "\n\r" );
                #endif

                int errorResult = ProcessPacket( &buildPacket );

                if( errorResult == -1 ){                                    //  check to make sure function performed properly
                    //#SCD setResponse(RPIADDRESS, command, ERRORCOMMAND);
                }
                SendAck();                                          //  send an ACK
            }
            else{
                SendNack();                              //  if checksum is not corret, send a NACK
            }

            pState = START;
            break;

    }   //  end switch( pState )

}   //  end serial2Handler function