Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91728228
sbcp_slave.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Nov 13, 22:01
Size
11 KB
Mime Type
text/x-c
Expires
Fri, Nov 15, 22:01 (1 d, 20 h)
Engine
blob
Format
Raw Data
Handle
22315394
Attached To
R6619 Oncilla Motordriver Firmware
sbcp_slave.c
View Options
/*
sbcp.c
Copyright (C) 2010 Rico Moeckel <rico.moeckel at epfl dot ch>,
EPFL Biorobotics Laboratory (http://biorob.epfl.ch)
EPFL Ecole Polytechnique Federale de Lausanne (http://www.epfl.ch)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
\defgroup sbcp SBCP
\brief Simple Binary Communication Protocol.
This file contains the implements the Simple Binary Communication
Protocol (Slave device) - a communication protocol for a single
master - multiple slave, half-duplex communication bus.
\author Rico Moeckel
\version 1.1
\date 2011-04-28
*/
/*@{*/
/** \file sbcp.c
\brief Simple Binary Communication Protocol.
*/
#include "sbcp.h"
#include <p33Fxxxx.h>
#include "sbcp.h"
#include "timer.h"
#include "command.h"
#include "config.h"
#include "dma_sbcp.h"
#include "port.h"
#include <string.h>
/*************************************************************************
*
* VARIABLES
*
*************************************************************************/
extern
const
tSBCP_CmdTbl
sbcp_cmd_tbl
[];
extern
const
int
SBCP_COMMAND_TABLE_LENGTH
;
//static tSBCP_AppVar SbcpVar;
volatile
tSBCP_AppVar
sbcp
;
///< Container struct storing the local SBCP variables.
/*******************************************************************************
*
* INLINE FUNCTION !!!!
*
******************************************************************************/
/**
* COmputes the checksum of a given packet
* @param packet the pointer to the packet buffer
* @return the checksum of the packet
*/
inline
unsigned
char
sbcp_compute_checksum_of_packet
(
const
unsigned
int
*
packet
){
unsigned
char
res
=
SBCP_MY_CLASS
+
SBCP_MY_ID
;
unsigned
int
i
;
res
+=
packet
[
SBCP_POS_PAYLOAD_LENGTH
];
res
+=
packet
[
SBCP_POS_INSTRUCTION
];
unsigned
int
size
=
(
packet
[
SBCP_POS_PAYLOAD_LENGTH
]
+
5
)
&
DMA_SBCP_MAX_PACKET_SIZE_MASK
;
for
(
i
=
SBCP_POS_PAYLOAD_START
;
i
<
size
;
++
i
){
res
+=
packet
[
i
];
}
return
res
;
}
/*************************************************************************
*
* FUNCTIONS
*
*************************************************************************/
/** \brief Function for initializing SBCP module.
This function initializes the SBCP module. It should be
called once in the main initialization function before executing
the sbcp_main() outine.
\param no parameters
\return no returns
*/
void
sbcp_init
()
{
DMA_PACKET_QUEUE_SET_EMPTY
(
sbcp
.
bus_ready_packet_queue
);
sbcp
.
bus_tx_flags
=
SBCP_TX_BUFFER_FREE
;
sbcp
.
bus_low_latency_flags
=
SBCP_LL_NOTHING
;
sbcp
.
bus_low_latency_payload
[
0
]
=
0x00
;
sbcp
.
bus_low_latency_payload
[
1
]
=
0x00
;
sbcp
.
bus_low_latency_payload
[
2
]
=
0x00
;
sbcp
.
bus_low_latency_payload
[
3
]
=
0x00
;
sbcp
.
bus_low_latency_previous_error_code
=
SBCP_STANDARD_ACKNOWLEDGEMENT
;
PORT_RS485_DRIVER_DISABLE
;
PORT_RS485_RECEIVER_ENABLE
;
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
[
SBCP_POS_HEADER
]
=
SBCP_HEADER
;
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
[
SBCP_POS_CLASS
]
=
SBCP_MY_CLASS
;
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
[
SBCP_POS_ID
]
=
SBCP_MY_ID
;
DMA_PACKET_QUEUE_BUS_LL_TX_BUFFER_CPU
[
SBCP_POS_HEADER
]
=
SBCP_HEADER
;
DMA_PACKET_QUEUE_BUS_LL_TX_BUFFER_CPU
[
SBCP_POS_CLASS
]
=
SBCP_MY_CLASS
;
DMA_PACKET_QUEUE_BUS_LL_TX_BUFFER_CPU
[
SBCP_POS_ID
]
=
SBCP_MY_ID
;
DMA_PACKET_QUEUE_BUS_LL_TX_BUFFER_CPU
[
SBCP_POS_PAYLOAD_LENGTH
]
=
SBCP_LOW_LATENCY_INSTRUCTION_FEEDBACK_PAYLOAD_SIZE
;
DMA_PACKET_QUEUE_BUS_LL_TX_BUFFER_CPU
[
SBCP_POS_INSTRUCTION
]
=
SBCP_STANDARD_ACKNOWLEDGEMENT
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_HEADER
]
=
SBCP_HEADER
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_CLASS
]
=
SBCP_MY_CLASS
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_ID
]
=
SBCP_MY_ID
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_PAYLOAD_LENGTH
]
=
0x01
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_INSTRUCTION
]
=
SBCP_ERROR_FLAG_COM_ERROR
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_PAYLOAD_START
]
=
SBCP_COM_ERROR_CODE_CHECKSUM_INCORRECT
;
DMA_PACKET_QUEUE_BUS_LL_ERROR_TX_BUFFER_CPU
[
SBCP_POS_PAYLOAD_START
+
1
]
=
SBCP_MY_CLASS
+
SBCP_MY_ID
+
0x01
+
SBCP_ERROR_FLAG_COM_ERROR
+
SBCP_COM_ERROR_CODE_CHECKSUM_INCORRECT
;
}
/** \brief SBCP command search
Function calls function corresponding to the SBCP instruction (as being registered in table sbcp_cmd_tbl[]
in file command.c) found in the SBCP packet. This function assumes that the entire
packet is already received and the the check sum is correct.
\param buffer:
pointer to the ring buffer that contains the SBCP packet
\param packet_start:
start position of SBCP packet in ring buffer. This is not a pointer but just
an index.
\return no returns
*/
#define SBCP_SEARCH_AND_EXECUTE_INSTRUCTION(buffer) do{\
unsigned char instruction = buffer[SBCP_POS_INSTRUCTION];\
/* check if instruction is valid number - meaning if entry in command table can exist*/
\
if (instruction >= SBCP_COMMAND_TABLE_LENGTH) {\
sbcp_bus_send_com_error_code(SBCP_COM_ERROR_CODE_UNKNOWN_INSTRUCTION);\
} else { \
/* sbcp_bus_send_standard_acknowlegement();*/
\
sbcp_cmd_tbl[instruction].cmd_function( buffer );\
}\
}while(0)
/** \brief SBCP main function.
This function implements all SBCP state machines for packet analysation. It should
be peridically called in the main() function.
\param no parameters
\return no returns
*/
void
sbcp_main
()
{
//first clear overrun errors that may occurs, even if it is really, really bad
if
(
U1STAbits
.
OERR
==
1
){
U1STAbits
.
OERR
=
0
;
//we lose all buffer data, but it means that DMA was
// activated while data was inside ! this is bad. To avoid this really
// bad situation, DMA0Channel should always be on, most of the time
// (could be disabled while Tx over the bus however).
// if we fail to do so, the UART will fill up, and we may loose some
// bytes. This is really, really bad since :
// - If master send a new packet very quickly we may miss our packet if
// we don't listen quickly enough.
// - If we start the recption inside a packet. We may, with bad luck
// start to see the sequence 0xff xx xx XX with XX being a relatively
// large number. Then we are screwed and may loose even more packet,
// for a long long time.
}
// Handle timeout
//right now if their is any error, we don't read the packet at all. Thus the
//master will issue a timeout. It would be nice, in case of an Frame error
//to send back an error packet
if
(
dma_sbcp
.
bus_rx_error
){
//disable UART and DMA
U1MODEbits
.
UARTEN
=
0
;
U1STAbits
.
UTXEN
=
0
;
DMA0CONbits
.
CHEN
=
0
;
DMA0STA
=
DMA_PACKET_QUEUE_BUS_GET_DMA
(
dma_sbcp
.
bus_rx_queue
.
tail
);
DMA0CNT
=
0
;
dma_sbcp
.
bus_rx_state
=
DMA_WAIT_FOR_HEADER_BYTE
;
DMA0CONbits
.
CHEN
=
1
;
U1MODEbits
.
UARTEN
=
1
;
U1STAbits
.
UTXEN
=
1
;
dma_sbcp
.
bus_rx_error
=
0
;
}
if
(
!
DMA_PACKET_QUEUE_EMPTY
(
sbcp
.
bus_ready_packet_queue
))
{
unsigned
int
*
packet
=
DMA_PACKET_QUEUE_BUS_GET_CPU
(
sbcp
.
bus_ready_packet_queue
.
head
);
if
(
packet
[
SBCP_POS_ID
]
==
SBCP_MY_ID
&&
packet
[
SBCP_POS_CLASS
]
==
SBCP_MY_CLASS
)
{
unsigned
char
csPos
=
(
packet
[
SBCP_POS_PAYLOAD_LENGTH
]
+
SBCP_POS_PAYLOAD_START
)
&
DMA_SBCP_MAX_PACKET_SIZE_MASK
;
unsigned
char
correctCS
=
SBCP_MY_ID
+
SBCP_MY_CLASS
;
correctCS
+=
packet
[
SBCP_POS_PAYLOAD_LENGTH
];
correctCS
+=
packet
[
SBCP_POS_INSTRUCTION
];
unsigned
int
size
=
(
packet
[
SBCP_POS_PAYLOAD_LENGTH
]
+
5
)
&
DMA_SBCP_MAX_PACKET_SIZE_MASK
;
unsigned
int
i
=
SBCP_POS_PAYLOAD_START
;
for
(;
i
<
size
;
++
i
){
correctCS
+=
packet
[
i
];
}
if
(
packet
[
csPos
]
==
correctCS
){
SBCP_SEARCH_AND_EXECUTE_INSTRUCTION
(
packet
);
}
else
{
sbcp_bus_send_com_error_code
(
SBCP_COM_ERROR_CODE_CHECKSUM_INCORRECT
);
}
}
else
if
(
DMA0CONbits
.
CHEN
==
0
){
DMA_INIT_BUS_RX
;
}
DMA_PACKET_QUEUE_INCREMENT_HEAD
(
sbcp
.
bus_ready_packet_queue
);
DMA_PACKET_QUEUE_INCREMENT_HEAD
(
dma_sbcp
.
bus_rx_queue
);
}
if
(
sbcp
.
bus_tx_flags
==
SBCP_TX_BUFFER_OCCUPIED
)
{
//FLAGS IN_TX not set !
DMA1STA
=
DMA_PACKET_QUEUE_BUS_TX_BUFFER_DMA
;
DMA1CNT
=
((
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
[
SBCP_POS_PAYLOAD_LENGTH
]
+
5
)
&
DMA_SBCP_MAX_PACKET_SIZE_MASK
);
PORT_RS485_RECEIVER_DISABLE
;
PORT_RS485_DRIVER_ENABLE
;
DMA1CONbits
.
CHEN
=
1
;
DMA1REQbits
.
FORCE
=
1
;
sbcp
.
bus_tx_flags
|=
SBCP_TX_BUFFER_IN_TX
;
//mark it to not send it lot of time !!!!
}
if
(
dma_sbcp
.
bus_rx_state
==
DMA_OVERFLOW_PENDING
){
if
(
!
DMA_PACKET_QUEUE_FULL
(
dma_sbcp
.
bus_rx_queue
)){
DMA_INIT_BUS_RX
;
}
}
// Transfering packets from BUS TX ring buffer to BUS UART output
// Only transmit data to UART buffer if UART buffer is empty
// and ring buffer is not empty. Do not waste time with busy waiting.
// for UART that is connected to RS485
// check if we wait for a new packet
}
/** \brief Function for transmitting a messages via the communication bus.
This function sends a message via the communication bus by copying it into
the correct output ring buffer and taking control over the communication bus.
\param message:
pointer to the linear message buffer that contains the SBCP packet that
should be transmitted
\param message_length:
length of the message that should be transmitted.
\return success/error flag
*/
/** \brief Function for generation of standard acknowledgement messages.
This function generates a standard acknowledgement message
and sends it via the communication bus.
\param no parameters
\return no returns
*/
void
sbcp_bus_send_standard_acknowlegement
()
{
unsigned
int
*
message
=
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
;
sbcp
.
bus_tx_flags
=
SBCP_TX_BUFFER_OCCUPIED
;
message
[
SBCP_POS_PAYLOAD_LENGTH
]
=
0x00
;
message
[
SBCP_POS_INSTRUCTION
]
=
SBCP_STANDARD_ACKNOWLEDGEMENT
;
message
[
SBCP_POS_PAYLOAD_START
]
=
SBCP_MY_CLASS
+
SBCP_MY_ID
+
SBCP_STANDARD_ACKNOWLEDGEMENT
;
}
/** \brief Function for generation of error messages.
This function generates a standard error message according to the
given error code and sends it via the communication bus.
\param error_code:
Error code to be transmitted.
\return no returns
*/
void
sbcp_bus_send_com_error_code
(
unsigned
char
error_code
)
{
unsigned
int
*
message
=
DMA_PACKET_QUEUE_BUS_TX_BUFFER_CPU
;
sbcp
.
bus_tx_flags
=
SBCP_TX_BUFFER_OCCUPIED
;
message
[
SBCP_POS_PAYLOAD_LENGTH
]
=
0x01
;
message
[
SBCP_POS_INSTRUCTION
]
=
SBCP_ERROR_FLAG_COM_ERROR
;
message
[
SBCP_POS_PAYLOAD_START
]
=
error_code
;
message
[
SBCP_POS_PAYLOAD_START
+
1
]
=
SBCP_MY_CLASS
+
SBCP_MY_ID
+
1
+
SBCP_ERROR_FLAG_COM_ERROR
+
error_code
;
}
Event Timeline
Log In to Comment