Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86495362
sbcp.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
Sun, Oct 6, 20:26
Size
18 KB
Mime Type
text/x-c
Expires
Tue, Oct 8, 20:26 (1 d, 22 h)
Engine
blob
Format
Raw Data
Handle
21430920
Attached To
R6616 sbcp-uc
sbcp.c
View Options
#include <sbcp-uc/sbcp.h>
#include <sbcp-uc/buffers.h>
#include <sbcp-uc/register.h>
#include <sbcp-uc/packet.h>
#ifdef SBCP_PROVIDE_MAIN
typedef enum sbcp_tx_state_t {
SBCP_TX_BUFFER_FREE = 0,
SBCP_TX_BUFFER_OCCUPIED ,
SBCP_TX_BUFFER_IN_TX
} sbcp_tx_state_t;
typedef enum sbcp_ll_flags_t {
SBCP_LL_NOTHING = 0,
SBCP_LL_RX_IS_AVAILABLE = 1 << 0,
SBCP_LL_TX_IS_AVAILABLE = 1 << 1,
SBCP_LL_IS_DISABLED = 1 << 2
} sbcp_ll_flags_t;
typedef enum sbcp_rx_state_t {
SBCP_NO_RX = 0,
SBCP_RX_WAIT_FOR_HEADER_BYTE,
SBCP_RX_WAIT_FOR_FULL_HEADER,
SBCP_RX_WAIT_FOR_FULL_PACKET,
SBCP_RX_OVERFLOW_PENDING
} sbcp_rx_state_t;
typedef enum sbcp_uart_err_flags_t {
SBCP_UART_ALL_ERRORS_DISABLED = 0x00,
SBCP_UART_FERR_ENABLED = 0x01,
SBCP_UART_PERR_ENABLED = 0x02,
SBCP_UART_OERR_ENABLED = 0x04
} sbcp_uart_err_flags_t;
struct sbcp_t {
gpio receive_disable;
gpio send_enable;
buffer_fifo rx_fifo;
buffer_fifo rx_ready_fifo;
sbcp_rx_state_t rx_state;
unsigned int rx_error;
volatile unsigned int * current_rx_packet;
sbcp_uart_err_flags_t bus_uart_error_flags;
sbcp_tx_state_t tx_state;
unsigned char is_for_us;
sbcp_ll_flags_t ll_flags;
unsigned char ll_payload[SBCP_LOW_LATENCY_IN_SIZE * 2];
unsigned char ll_previous_error_code;
sbcp_reg_address ll_in_registers[SBCP_LOW_LATENCY_IN_SIZE];
sbcp_reg_address ll_out_registers[SBCP_LOW_LATENCY_OUT_SIZE];
uint8_t ll_in_size;
uint8_t ll_out_size;
};
typedef struct sbcp_t sbcp_t;
#define uart_line_in_tx() do{ \
gpio_set(sbcp.receive_disable); \
gpio_set(sbcp.send_enable); \
}while(0)
#define uart_line_in_rx() do{ \
gpio_clear(sbcp.send_enable); \
gpio_clear(sbcp.receive_disable); \
}while(0)
#define dma_init_bus_rx() do { \
buffer_fifo_increment_tail(sbcp.rx_fifo); \
DMA0STA = buffer_fifo_get_dma_addr(sbcp.rx_fifo.tail); \
sbcp.current_rx_packet = buffer_fifo_get_cpu_addr(sbcp.rx_fifo.tail); \
DMA0CNT = 0; \
sbcp.rx_state = SBCP_RX_WAIT_FOR_HEADER_BYTE; \
DMA0CONbits.CHEN = 1;}while(0)
#define dma_bus_rx_end_header() do{ \
DMA0CONbits.CHEN = 0; \
DMA0STA += 2; \
DMA0CNT = 2; \
DMA0CONbits.CHEN = 1; \
sbcp.rx_state = SBCP_RX_WAIT_FOR_FULL_HEADER; \
}while(0)
#define SBCP_PACKET_SIZE_MASK (SBCP_PACKET_SIZE - 1)
#define dma_bus_rx_full_packet() do{ \
DMA0CONbits.CHEN = 0; \
DMA0STA +=6 ; \
sbcp_payload_size length = sbcp.current_rx_packet[SBCP_PAYLOAD_SIZE_POS]; \
DMA0CNT = (length & SBCP_PACKET_SIZE_MASK ) + 1; \
DMA0CONbits.CHEN = 1; \
sbcp.rx_state = SBCP_RX_WAIT_FOR_FULL_PACKET; \
}while(0)
//! Force GCC to not reorder the instruction before and after this macro
#define barrier() __asm__ __volatile__("": : :"memory")
#define dma_init_bus_tx(buffer) do{ \
DMA1STA = __builtin_dmaoffset( buffer ); \
DMA1CNT = (((volatile unsigned int) buffer[SBCP_PAYLOAD_SIZE_POS]) + 5 ) & SBCP_PACKET_SIZE_MASK; \
uart_line_in_tx(); \
DMA1CONbits.CHEN = 1; \
barrier(); \
DMA1REQbits.FORCE = 1; \
}while(0)
#define timer_4_start() do { \
T4CONbits.TON = 1; \
}while(0)
#define timer_4_stop() do{ \
T4CONbits.TON = 0; \
}while(0)
#define timer_4_stop_and_clear() do{ \
T4CONbits.TON = 0; \
TMR4 = 0x00; \
}while(0)
void init_timer_4(unsigned int frequency, unsigned long clock_frequency) {
timer_4_stop();
T4CONbits.T32 = 0;
T4CONbits.TCS = 0;
T4CONbits.TGATE = 0;
unsigned long increments = clock_frequency / frequency;
if(increments < 65535){
PR4 = increments;
T4CONbits.TCKPS = 0b00;
} else if (increments < 8 * 65535) {
PR4 = increments / 8;
T4CONbits.TCKPS = 0b01;
}
}
//Mark it as volatile as it will heavily be modified by interrupt !!!
volatile sbcp_t sbcp;
void init_dma_for_uart(){
DMA0CONbits.SIZE = 0; // use word
DMA0CONbits.DIR = 0; // from peripherical to RAM
DMA0CONbits.HALF = 0; // inetrrupt after all receive
DMA0CONbits.NULLW = 0; // non null write
DMA0CONbits.AMODE = 0; //indirect register with post increment
DMA0CONbits.MODE = 1; //One shot, no ping pong
DMA0CNT = 0; //1 transfers
DMA0PAD = (volatile unsigned int) &U1RXREG;
DMA0STA = buffer_fifo_get_dma_addr(sbcp.rx_fifo.tail);
DMA0REQ = 0x000b; //UART 1 RX irq
IFS0bits.DMA0IF = 0; //clear DMA interrupt flag
IEC0bits.DMA0IE = 1; //enable dmao interrupt
//DISABLE CHANNEL
DMA0CONbits.CHEN = 0; //disable channel 0
//activate DMA 0
//initialize DMA 1 for BUS TX
DMA1CONbits.SIZE = 0; //use word
DMA1CONbits.DIR = 1; //from RAM to periph
DMA1CONbits.HALF = 0; //interrupt after all received char
DMA1CONbits.NULLW = 0; //normal mode
DMA1CONbits.AMODE = 0; //indirect register with post increment
DMA1CONbits.MODE = 1; //One shot, no ping pong
DMA1CNT = 0; //1 byte, should be overrwriten when launching
DMA1PAD = (volatile unsigned int) &U1TXREG;
DMA1STA = __builtin_dmaoffset(bus_tx_buffer); //should be overwritten when launching
DMA1REQ = 0x000c; //UART 1 TX IRQ
IFS0bits.DMA1IF = 0; //clear DMA interrupt flag
IEC0bits.DMA1IE = 1; //ENABLE DMA1 INTERRUPT !!!!
//DISABLE CHANNEL, WILL BE CONFIGURED AND ENABLED WHEN NEEDED
DMA1CONbits.CHEN = 0;
}
void sbcp_init_settings(sbcp_settings * s ,
sbcp_class klass, sbcp_id id,
sbcp_fw_version version,
gpio send_enable,
gpio receive_disable) {
s->baudrate = 3310000UL;
s->clock_frequency = 39613750UL;
s->uart = UART_1;
s->timeout_frequency = 2000;
s->klass = klass;
s->id = id;
s->version = version;
s->init_instruction = 0;
s->init_register = 0;
s->send_enable = send_enable;
s->receive_disable = receive_disable;
}
void sbcp_init(sbcp_settings * s){
//set first all intern variables
buffer_fifo_set_empty(sbcp.rx_fifo);
buffer_fifo_set_empty(sbcp.rx_ready_fifo);
sbcp.rx_state = SBCP_RX_WAIT_FOR_HEADER_BYTE;
sbcp.rx_error = 0;
sbcp.current_rx_packet = 0;
sbcp.bus_uart_error_flags = SBCP_UART_ALL_ERRORS_DISABLED;
sbcp.send_enable = s->send_enable;
sbcp.receive_disable = s->receive_disable;
sbcp_clear_low_latency_register_definitions();
sbcp_init_registers(s->klass,s->id,s->version,s->init_register);
//prepare the buffers
//sbcp.ll_payload_size = s->ll_feedback_size;
sbcp.tx_state = SBCP_TX_BUFFER_FREE;
sbcp.ll_flags = SBCP_LL_NOTHING;
sbcp.is_for_us = 0;
sbcp.ll_previous_error_code = SBCP_NO_ERROR;
init_buffers(SBCP_MY_CLASS,SBCP_MY_ID);
sbcp_init_instructions(s->init_instruction);
init_uart_for_sbcp(s->uart,s->baudrate,s->clock_frequency);
init_dma_for_uart();
init_timer_4(s->clock_frequency,s->timeout_frequency);
//now start everything
uart_line_in_rx();
//now start the actual rx
dma_init_bus_rx();
}
/*************************************************************************
*
* FUNCTIONS
*
*************************************************************************/
void sbcp_low_latency_process(){
uint8_t i;
sbcp_error error = SBCP_NO_ERROR;
sbcp_reg_val val;
sbcp_reg_address reg;
if(sbcp.ll_flags & SBCP_LL_RX_IS_AVAILABLE){
sbcp.ll_flags |= SBCP_LL_IS_DISABLED;
sbcp.ll_previous_error_code = SBCP_NO_ERROR;
for(i = 0; i < sbcp.ll_in_size && error == SBCP_NO_ERROR; ++i){
reg = sbcp.ll_in_registers[i];
sbcp.ll_flags |= SBCP_LL_IS_DISABLED;
val.msb = sbcp.ll_payload[2 * i];
val.lsb = sbcp.ll_payload[2 * i + 1];
sbcp.ll_flags &= ~(SBCP_LL_RX_IS_AVAILABLE | SBCP_LL_IS_DISABLED);
IEC0bits.DMA0IE = 1; //will rethrow interrupt
if(sbcp_reg_clbck(reg) != SBCP_REG_NO_CALLBACK){
error = (*(sbcp_reg_clbck(reg)))(reg,&val);
if(error != SBCP_NO_ERROR){
sbcp.ll_previous_error_code = error;
} else {
sbcp_reg_table[reg] = val;
}
}
}
sbcp.ll_flags &= ~(SBCP_LL_RX_IS_AVAILABLE | SBCP_LL_IS_DISABLED);
IEC0bits.DMA0IE = 1; //will rethrow interrupt
}
if(sbcp.ll_flags & SBCP_LL_TX_IS_AVAILABLE && DMA1CONbits.CHEN == 0){
sbcp.ll_flags |= SBCP_LL_IS_DISABLED;
bus_ll_tx_buffer[SBCP_PAYLOAD_SIZE_POS] = sbcp.ll_out_size * 2;
bus_ll_tx_buffer[SBCP_INSTRUCTION_POS] = sbcp.ll_previous_error_code;
uint8_t cs = SBCP_MY_CLASS + SBCP_MY_ID + sbcp.ll_previous_error_code + sbcp.ll_out_size * 2;
// to remove some warnings when LOW_LATENCY_OUT_SIZE == 0
#if SBCP_LOW_LATENCY_OUT_SIZE > 0
for(i = 0 ; i < sbcp.ll_out_size; ++i){
reg = sbcp.ll_out_registers[i];
bus_ll_tx_buffer[SBCP_PAYLOAD_START_POS + 2 * i] = sbcp_reg_msb(reg);
bus_ll_tx_buffer[SBCP_PAYLOAD_START_POS + 2 * i + 1] = sbcp_reg_lsb(reg);
cs += sbcp_reg_msb(reg);
cs += sbcp_reg_lsb(reg);
}
#endif
bus_ll_tx_buffer[SBCP_PAYLOAD_START_POS + sbcp.ll_out_size * 2] = cs;
sbcp.ll_flags &= ~(SBCP_LL_TX_IS_AVAILABLE | SBCP_LL_IS_DISABLED);
IEC0bits.DMA0IE = 1; //will rethrow interrupt
}
}
void sbcp_process()
{
sbcp_low_latency_process();
//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(sbcp.rx_error){
//disable UART and DMA
U1MODEbits.UARTEN = 0;
U1STAbits.UTXEN = 0;
DMA0CONbits.CHEN = 0;
DMA0STA = buffer_fifo_get_dma_addr(sbcp.rx_fifo.tail);
DMA0CNT = 0;
sbcp.rx_state = SBCP_RX_WAIT_FOR_HEADER_BYTE;
DMA0CONbits.CHEN = 1;
U1MODEbits.UARTEN = 1;
U1STAbits.UTXEN = 1 ;
sbcp.rx_error = 0;
}
if(!buffer_fifo_empty(sbcp.rx_ready_fifo)) {
unsigned int * packet = (unsigned int * ) (buffer_fifo_get_cpu_addr(sbcp.rx_ready_fifo.head));
if (packet[SBCP_ID_POS] == SBCP_MY_ID &&
packet[SBCP_CLASS_POS] == SBCP_MY_CLASS) {
unsigned char csPos =
(packet[SBCP_PAYLOAD_SIZE_POS] + SBCP_PAYLOAD_START_POS) & SBCP_PACKET_SIZE_MASK;
unsigned char correctCS = sbcp_compute_packet_cs(packet);
if(packet[csPos] == correctCS){
sbcp_instruction inst = packet[SBCP_INSTRUCTION_POS];
sbcp_process_instruction(inst,packet);
} else {
sbcp_send_error_r_packet(SBCP_CERR_CS_INCORRECT);
}
} else if(DMA0CONbits.CHEN == 0){
dma_init_bus_rx();
}
buffer_fifo_increment_head(sbcp.rx_ready_fifo);
buffer_fifo_increment_head(sbcp.rx_fifo);
}
if (sbcp.tx_state == SBCP_TX_BUFFER_OCCUPIED) { //FLAGS IN_TX not set !
dma_init_bus_tx(bus_tx_buffer);
sbcp.tx_state |= SBCP_TX_BUFFER_IN_TX;//mark it to not send it lot of time !!!!
}
if(sbcp.rx_state == SBCP_RX_OVERFLOW_PENDING ){
if(!buffer_fifo_full(sbcp.rx_fifo)){
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
}
void __attribute__((__interrupt__ , no_auto_psv)) _DMA0Interrupt(void) {
switch (sbcp.rx_state) {
case SBCP_RX_WAIT_FOR_HEADER_BYTE : {
if(*(sbcp.current_rx_packet) != 0X00ff){
//resets the reception
DMA0CONbits.CHEN = 0;
DMA0CONbits.CHEN = 1;
} else {
dma_bus_rx_end_header();
timer_4_start();
//DMA_BUS_ENABLE_ERR_DETECTION;
}
break;
}
case SBCP_RX_WAIT_FOR_FULL_HEADER :
{
dma_bus_rx_full_packet();
break;
}
case SBCP_RX_WAIT_FOR_FULL_PACKET : {
//first of all, we check if the packet is for us.
if(sbcp.current_rx_packet[SBCP_ID_POS] != SBCP_MY_ID ||
sbcp.current_rx_packet[SBCP_CLASS_POS] != SBCP_MY_CLASS){
//the packet is not for us, we re-init the DMA 0 channel, and we
//the current incoming packet.
DMA0STA -= 8; // we remove the 4 first pointed bytes
DMA0CNT = 0; //just one byte reception
DMA0CONbits.CHEN = 1; //channel is resetted
sbcp.rx_state = SBCP_RX_WAIT_FOR_HEADER_BYTE;
//we are waiting the first byte
} else { //the packet is for us
if(sbcp.ll_flags & SBCP_LL_IS_DISABLED){
IEC0bits.DMA0IE = 0;
//we DISABLE interupt, and DON'T CLEAR flag.
//When we clear the FLAG SBCP_IS_DISABLED, we are intended
//to re-enable interrupt, so We will come here again
return;
}
//We check if it is the special low latency instruction
//this instruction should be responded ASAP, so in this interruption.
if (sbcp.current_rx_packet[SBCP_INSTRUCTION_POS] == SBCP_INST_LOW_LATENCY_INSTRUCTION) {
unsigned int i;
//of course checksum should be checked
unsigned char correctChecksum = SBCP_MY_CLASS
+ SBCP_MY_ID
+ SBCP_INST_LOW_LATENCY_INSTRUCTION;
uint8_t payload_size = sbcp.current_rx_packet[SBCP_PAYLOAD_SIZE_POS];
correctChecksum += payload_size;
for(i = 0; i < payload_size; ++i){
correctChecksum += sbcp.current_rx_packet[SBCP_PAYLOAD_START_POS + i];
}
if(correctChecksum == sbcp.current_rx_packet[SBCP_PAYLOAD_START_POS + payload_size]) {
//we use the already prepared standard message
dma_init_bus_tx(bus_ll_tx_buffer);
//we save the incomming payload.
for(i = 0; i < payload_size; ++i){
sbcp.ll_payload[i] = sbcp.current_rx_packet[SBCP_PAYLOAD_START_POS + i];
}
//we specify that new data is available to treat it at the appropriate time
sbcp.ll_flags |= SBCP_LL_RX_IS_AVAILABLE;
} else { //we get a bad checksum
//we use the already prepared error
dma_init_bus_tx(bus_ll_tx_error_buffer);
}
sbcp.tx_state = SBCP_TX_BUFFER_IN_TX;
//we mark it as treated since it was for us, and we have treated it.
buffer_fifo_increment_head(sbcp.rx_ready_fifo);
}
//the packet is for us (just imagine that this line is just
// after the else :) ) so we mark it as ready for treatment. If
// it was a low latency one, it would already have been already
//treated.
buffer_fifo_increment_tail(sbcp.rx_ready_fifo);
}
//now we clear the timer 4. Interruption may have already occured,
//but masked by this one that have a higher priority. To not mess up
//the whole thing, we should clear the corresponding interrupt flag.
timer_4_stop_and_clear();
IFS1bits.T4IF = 0;
//if the interruption have occured for some magic reason, or
//obviously deficient programming skill of mine, it should remove
//any uterly bad effect
sbcp.rx_error &= ~(SBCP_CERR_HOST_TIMEOUT);
break;
}
default :
break;
}
//clear the interrupt flag !
IFS0bits.DMA0IF = 0;
}
//Transfer is completely in UART Queue
void __attribute__((__interrupt__ , no_auto_psv )) _DMA1Interrupt(void){
U1STAbits.UTXISEL0 = 1; //stop only when all operation are finished
//clear any pending flags (which is set BTW)
barrier();
IFS0bits.U1TXIF = 0;
//enable TX interrupt to detect when trnasfer is actually finished (not just in queue)
IEC0bits.U1TXIE = 1;
barrier();
//clear the interrupt flag !
IFS0bits.DMA1IF = 0;
}
void __attribute__((__interrupt__ , no_auto_psv)) _U1TXInterrupt(void) {
/*
while(!(U1STAbits.TRMT)){
Nop();
}
*/
uart_line_in_rx();
//here all Tx operations are done
//We start the reset of the UART. indeed , UART has been of for a time now
//so a OERR could have occur, this is safer for two instructions !
U1MODEbits.UARTEN = 0; //disabled.
U1STAbits.UTXEN = 0;
//we switch the port back to Rx mode
// TODO we may need to re-enable Tx ! check doc for this !
// TODO check the error handling code too !
dma_init_bus_rx();
//now reception is OK !
sbcp.tx_state = SBCP_TX_BUFFER_FREE;
IEC0bits.U1TXIE = 0; //disable interrut
U1STAbits.UTXISEL0 = 0; //Interrupt every char
IFS0bits.U1TXIF = 0; //clear interrupt !
U1MODEbits.UARTEN = 1; //resetted, buffer are now empty !
U1STAbits.UTXEN = 1;
};
/* Timer 3 is used to create the timeout for bus receiver part of the SBCP protocol */
void __attribute__((__interrupt__, no_auto_psv)) _T4Interrupt(void)
{
/* Interrupt Service Routine code goes here */
timer_4_stop_and_clear();
sbcp.rx_error |= SBCP_CERR_BUS_TIMEOUT;
IFS1bits.T4IF = 0; // Clear Timer 3 Interrupt Flag
}
void sbcp_mark_tx_buffer_occupied(){
sbcp.tx_state |= SBCP_TX_BUFFER_OCCUPIED;
}
int sbcp_append_low_latency_in_register(sbcp_reg_address address){
if(address >= SBCP_REG_TABLE_SIZE){
return 1;
}
if(! (sbcp_reg_flags(address) & SBCP_REG_WRITABLE) ){
return 1;
}
if( sbcp_reg_flags(address) & SBCP_REG_PERSISTENT){
return 1;
}
if(sbcp.ll_in_size >= SBCP_LOW_LATENCY_IN_SIZE){
return 1;
}
sbcp.ll_in_registers[sbcp.ll_in_size] = address;
++sbcp.ll_in_size;
return 0;
}
int sbcp_append_low_latency_out_register(sbcp_reg_address address){
if(address >= SBCP_REG_TABLE_SIZE){
return 1;
}
if(! (sbcp_reg_flags(address) & SBCP_REG_READABLE) ){
return 1;
}
if(sbcp.ll_out_size >= SBCP_LOW_LATENCY_OUT_SIZE){
return 1;
}
if(! (sbcp_reg_flags(address) & SBCP_REG_LL_READABLE ) ) {
return 1;
}
sbcp.ll_out_registers[sbcp.ll_out_size] = address;
sbcp.ll_out_size += 1;
return 0;
}
void sbcp_mark_new_low_latency_data_available(){
sbcp.ll_flags |= SBCP_LL_TX_IS_AVAILABLE;
}
void sbcp_clear_low_latency_register_definitions(){
unsigned int i;
for(i = 0; i < SBCP_LOW_LATENCY_IN_SIZE ; ++i){
sbcp.ll_payload[2 * i ] = 0;
sbcp.ll_payload[2 * i + 1 ] = 0;
sbcp.ll_in_registers[i] = 0;
}
for(i = 0; i< SBCP_LOW_LATENCY_OUT_SIZE; ++i){
sbcp.ll_out_registers[i] = 0;
}
sbcp.ll_in_size = 0;
sbcp.ll_out_size = 0;
}
sbcp_payload_size sbcp_get_ll_in_size(){
return sbcp.ll_in_size;
}
sbcp_payload_size sbcp_get_ll_out_size(){
return sbcp.ll_out_size;
}
sbcp_reg_address sbcp_get_ll_in_register(sbcp_payload_size index){
if(index >= sbcp.ll_in_size){
return 0xff;
}
return sbcp.ll_in_registers[index];
}
sbcp_reg_address sbcp_get_ll_out_register(sbcp_payload_size index){
if(index >= sbcp.ll_out_size){
return 0xff;
}
return sbcp.ll_out_registers[index];
}
#else
int sbcp_append_low_latency_in_register(sbcp_reg_address address){
return 1;
}
int sbcp_append_low_latency_out_register(sbcp_reg_address address){
return 1;
}
void sbcp_clear_low_latency_register_definitions(){
}
sbcp_payload_size sbcp_get_ll_in_size(){
return 0;
}
sbcp_payload_size sbcp_get_ll_out_size(){
return 0;
}
sbcp_reg_address sbcp_get_ll_in_register(sbcp_payload_size index){
return 0xff;
}
sbcp_reg_address sbcp_get_ll_out_register(sbcp_payload_size index){
return 0xff;
}
#endif //SBCP_PROVIDE_MAIN
Event Timeline
Log In to Comment