Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
b55c7d94eThis file is pinned to the selected release. Download the original to open it in your design tool.
// 11/2015 Rene Hopf<renehopf@mac.com> and Ian McMahon<facetious.ian@gmail.com>
//using CMD_TX
//using CMD_RX
HAL_COMP(sserial);
//dump:
//sigrok-cli --driver fx2lafw --config samplerate=24m --time 1s --channels 3=rx,2=tx -t rx=f -o sserial.sr
//decode:
//sigrok-cli -i sserial.sr -P uart:baudrate=2500000:tx=tx:rx=rx:format=hex -A uart=tx-data:rx-data
//decode more:
//sigrok-cli -i sserial.sr -P uart:baudrate=2500000:tx=tx:rx=rx,sserial
#define UnitNumberRPC 0xbc
#define DiscoveryRPC 0xbb
#define ProcessDataRPC 0xbd
//local commands
#define LBPCookieCMD 0xdf
#define LBPCookie 0x5a
#define LBPStatusCMD 0xc1
#define LBPCardName "stbl"
#define LBPCardName0Cmd 0xd0
#define LBPCardName1Cmd 0xd1
#define LBPCardName2Cmd 0xd2
#define LBPCardName3Cmd 0xd3
#define CT_RW 1 // 01b
#define CT_RPC 2 // 10b
#define CT_LOCAL 3 // 11b
typedef union{
struct {
uint8_t ds:2;//DataSize: Specifies data size, 00b = 1 bytes, 01b = 2 bytes, 10 b= 4 bytes, 11b = 8 bytes.
uint8_t as:1;//AddressSize: 0 to specify current address, 1 to specify 2 byte address.
uint8_t ai:1;//AutoInc: 0 leaves address unchanged, 1 specifies that address is post incremented by data size in bytes.
uint8_t rid:1;//RPCIncludesData: 0 specifies that data is from stream, 1, that data is from RPC (RPC only, ignored for non RPC commands)
uint8_t wr:1;//Write: 1 to specify write, 0 to specify read
uint8_t ct:2;//CommandType: Must be 01b to specify data read/write command
// 01:rw 11:local command 10:rpc
};
struct {
uint8_t rpc:6;
uint8_t dummy:2;
//01:rw 11: local command 10:rpc
};
uint8_t byte;
} lbp_t;
#define MEM_SIZE 2048
#define RECORD_TYPE_PROCESS_DATA_RECORD 0xA0
#define RECORD_TYPE_MODE_DATA_RECORD 0xB0
//process data
#define DATA_TYPE_PAD 0x00
#define DATA_TYPE_BITS 0x01
#define DATA_TYPE_UNSIGNED 0x02
#define DATA_TYPE_SIGNED 0x03
#define DATA_TYPE_NONVOL_UNSIGNED 0x04
#define DATA_TYPE_NONVOL_SIGNED 0x05
#define DATA_TYPE_NONVOL_STREAM 0x06
#define DATA_TYPE_NONVOL_BOOLEAN 0x07
#define DATA_DIRECTION_INPUT 0x00
#define DATA_DIRECTION_BI_DIRECTIONAL 0x40
#define DATA_DIRECTION_OUTPUT 0x80
#define MEMPTR(p) ((uint32_t)&p-(uint32_t)&memory)
#define MEMU8(ptr) (memory.bytes[ptr])
#define MEMU16(ptr) (memory.bytes[ptr] | memory.bytes[ptr+1]<<8)
#define MEMU32(ptr) (memory.bytes[ptr] | memory.bytes[ptr+1]<<8 | memory.bytes[ptr+2]<<16 | memory.bytes[ptr+3]<<24)
#define MEMFLOAT(ptr) ((float)({uint32_t tmp = MEMU32(ptr);*((float*)&tmp);}))
#define NUM_BYTES(bits) (bits / 8 + (bits % 8 > 0 ? 1 : 0))
#define IS_INPUT(pdr) (pdr->data_direction != 0x80)
#define IS_OUTPUT(pdr) (pdr->data_direction != 0x00)
#define SIGNED(pdr) (pdr->data_type == DATA_TYPE_SIGNED || pdr->data_type == DATA_TYPE_NONVOL_SIGNED)
#define UNSIGNED(pdr) (pdr->data_type == DATA_TYPE_UNSIGNED || pdr->data_type == DATA_TYPE_NONVOL_UNSIGNED)
// pins
HAL_PIN(dump_pd_vals) = 0.0;
HAL_PIN(error) = 0.0;//counts unknown commands
HAL_PIN(crc_error) = 0.0;//counts crc errors
HAL_PIN(connected) = 0.0;//connection status TODO: not stable during startup, needs link to pd
HAL_PIN(timeout) = 100.0;// 20khz / 1khz * 2 reads = 40
HAL_PIN(pos_cmd) = 0.0;
HAL_PIN(pos_fb) = 0.0;
HAL_PIN(vel_fb) = 0.0;
HAL_PIN(in0) = 0.0;
HAL_PIN(in1) = 0.0;
HAL_PIN(in2) = 0.0;
HAL_PIN(in3) = 0.0;
HAL_PIN(out0) = 0.0;
HAL_PIN(out1) = 0.0;
HAL_PIN(out2) = 0.0;
HAL_PIN(out3) = 0.0;
typedef struct{
uint8_t record_type;//0xa0
uint8_t data_size;
uint8_t data_type;
uint8_t data_direction;
float param_min;
float param_max;
uint16_t data_addr;
char names;
} process_data_descriptor_t;
typedef struct{
uint8_t record_type;//0xb0
uint8_t index;
uint8_t type;
uint8_t unused;
char names;
} mode_descriptor_t;
typedef struct{
uint8_t input; //process data input bytes
uint8_t output; //process data output bytes
uint16_t ptocp; //pointer to process data table start
uint16_t gtocp; //pointer to mode data table start
} discovery_rpc_t;
typedef union {
struct {
discovery_rpc_t discovery;
uint16_t foo;
uint8_t heap[MEM_SIZE - sizeof(discovery_rpc_t)];
};
uint8_t bytes[MEM_SIZE];
} memory_t;
typedef struct {
process_data_descriptor_t *ptr;
float range;
uint32_t bitmax;
} pd_metadata_t;
typedef struct {
pd_metadata_t pos_cmd;
pd_metadata_t scale;
pd_metadata_t pos_fb;
pd_metadata_t vel_fb;
pd_metadata_t input_pins;
pd_metadata_t output_pins;
} pd_table_t;
MEM(volatile uint8_t rxbuf[128]);
MEM(volatile uint8_t txbuf[20]);
MEM(uint16_t address);//current address pointer
MEM(int rxpos);
MEM(memory_t memory);
MEM(uint8_t *heap_ptr);
MEM(uint32_t timeout);
MEM(pd_table_t pd_table);
//pb13 txen
//pc12 usart5 tx
//pa9 usart1 tx as rx
void init_hardware() {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
//USART TX
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART RX
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = 2500000;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx;
USART_Init(USART1, &USART_InitStruct);
USART_HalfDuplexCmd(USART1,ENABLE);
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_Init(UART5, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
USART_Cmd(UART5, ENABLE);
//RX DMA
DMA_Cmd(DMA2_Stream5, DISABLE);
DMA_DeInit(DMA2_Stream5);
// DMA2-Config
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&rxbuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = sizeof(rxbuf);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream5, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream5, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
//TX DMA
DMA_Cmd(DMA1_Stream7, DISABLE);
DMA_DeInit(DMA1_Stream7);
// DMA2-Config
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(UART5->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&txbuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = sizeof(txbuf);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Priority_Low;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream7, &DMA_InitStructure);
//DMA_Cmd(DMA1_Stream7, ENABLE);
USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
GPIO_SetBits(GPIOB, GPIO_Pin_13);//tx enable
}
process_data_descriptor_t create_pdr(uint8_t data_size_in_bits, uint8_t data_type, uint8_t data_dir, float param_min, float param_max) {
process_data_descriptor_t pd;
pd.record_type = RECORD_TYPE_PROCESS_DATA_RECORD;
pd.data_size = data_size_in_bits;
pd.data_type = data_type;
pd.data_direction = data_dir;
pd.param_min = param_min;
pd.param_max = param_max;
return pd;
}
mode_descriptor_t create_mdr(uint8_t index, uint8_t type) {
mode_descriptor_t md;
md.record_type = RECORD_TYPE_MODE_DATA_RECORD;
md.index = index;
md.type = type;
md.unused = 0x00;
return md;
}
uint16_t add_pd(char *name_string, char *unit_string, uint8_t data_size_in_bits, uint8_t data_type, uint8_t data_dir, float param_min, float param_max) {
process_data_descriptor_t pdr = create_pdr(data_size_in_bits, data_type, data_dir, param_min, param_max);
pdr.data_addr = MEMPTR(*heap_ptr);
heap_ptr += NUM_BYTES(data_size_in_bits);
// this aligns the heap pointer to 32bit. Not doing this causes the floats in the pd to be misaligned, which crashes the arm.
if((uint32_t)heap_ptr % 4){
heap_ptr += 4 - (uint32_t)heap_ptr % 4;
}
memcpy(heap_ptr, &pdr, sizeof(process_data_descriptor_t));
// note that we don't store the names in the struct anymore. The fixed-length struct is copied into memory, and then the nmaes go in directly behind it, so they'll read out properly
uint16_t pd_ptr = MEMPTR(*heap_ptr); // save off the ptr to return, before we modify the heap ptr
heap_ptr = (uint8_t *)&(((process_data_descriptor_t *)heap_ptr)->names);
// copy the strings in after the pd
strcpy((char *)heap_ptr, unit_string);
heap_ptr += strlen(unit_string)+1;
strcpy((char *)heap_ptr, name_string);
heap_ptr += strlen(name_string)+1;
// moved this up to before the pd record
/*
// this aligns the heap pointer to 32bit. Not doing this causes the floats in the pd to be misaligned, which crashes the arm.
if((uint32_t)heap_ptr % 4){
heap_ptr += 4 - (uint32_t)heap_ptr % 4;
}
*/
return pd_ptr;
}
uint16_t add_mode(char *name_string, uint8_t index, uint8_t type) {
mode_descriptor_t mdr = create_mdr(index, type);
memcpy(heap_ptr, &mdr, sizeof(mode_descriptor_t));
uint16_t md_ptr = MEMPTR(*heap_ptr);
heap_ptr = (uint8_t *)&(((mode_descriptor_t *)heap_ptr)->names);
strcpy((char *)heap_ptr, name_string);
heap_ptr += strlen(name_string)+1;
return md_ptr;
}
#define INDIRECT_PD(pd_ptr) ((process_data_descriptor_t *)(memory.bytes + *pd_ptr))
#define DATA_DIR(pd_ptr) INDIRECT_PD(pd_ptr)->data_direction
#define DATA_SIZE(pd_ptr) INDIRECT_PD(pd_ptr)->data_size
#define ADD_PROCESS_VAR(args) *ptocp = add_pd args; input_bits += IS_INPUT(INDIRECT_PD(ptocp)) ? DATA_SIZE(ptocp) : 0; output_bits += IS_OUTPUT(INDIRECT_PD(ptocp)) ? DATA_SIZE(ptocp) : 0; last_pd = INDIRECT_PD(ptocp++)
#define ADD_GLOBAL_VAR(args) *gtocp++ = add_pd args
#define ADD_MODE(args) *gtocp++ = add_mode args
void metadata(pd_metadata_t *pdm, process_data_descriptor_t *ptr) {
pdm->ptr = ptr;
pdm->range = ptr->data_type == DATA_TYPE_SIGNED ? MAX(ptr->param_min, ptr->param_max)*2 : ptr->param_max;
pdm->bitmax = (1<<ptr->data_size)-1;
}
RT_INIT(
init_hardware();
rxpos = 0;
heap_ptr = memory.heap;
uint16_t input_bits = 8; // this starts at 8 bits = 1 byte for the fault byte
uint16_t output_bits = 0;
// these are temp toc arrays that the macros will write pointers into. the tocs get copied to main memory after everything else is written in
uint16_t ptoc[32];
uint16_t gtoc[32];
uint16_t *ptocp = ptoc; uint16_t *gtocp = gtoc;
process_data_descriptor_t *last_pd;
ADD_PROCESS_VAR(("output_pins", "none", 2, DATA_TYPE_BITS, DATA_DIRECTION_OUTPUT, 0, 1)); metadata(&(pd_table.output_pins), last_pd);
ADD_PROCESS_VAR(("pos_cmd", "rad", 16, DATA_TYPE_SIGNED, DATA_DIRECTION_OUTPUT, -3.2, 3.2)); metadata(&(pd_table.pos_cmd), last_pd);
ADD_PROCESS_VAR(("input_pins", "none", 2, DATA_TYPE_BITS, DATA_DIRECTION_INPUT, -100, 100)); metadata(&(pd_table.input_pins), last_pd);
ADD_PROCESS_VAR(("pos_fb", "rad", 16, DATA_TYPE_SIGNED, DATA_DIRECTION_INPUT, -3.2, 3.2)); metadata(&(pd_table.pos_fb), last_pd);
//ADD_PROCESS_VAR(("input_pins", "none", 1, DATA_TYPE_BITS, DATA_DIRECTION_INPUT, 0, 1)); metadata(&(pd_table.input_pins), last_pd);
ADD_GLOBAL_VAR(("swr", "non", 8, DATA_TYPE_UNSIGNED, DATA_DIRECTION_OUTPUT, 0, 0));
ADD_MODE(("foo", 0, 0));
ADD_MODE(("io_", 1, 1));
// automatically create padding pds based on the mod remainder of input/output bits
if (input_bits % 8) ADD_PROCESS_VAR(("", "", 8 - (input_bits%8), DATA_TYPE_PAD, DATA_DIRECTION_INPUT, 0, 0));
if (output_bits % 8) ADD_PROCESS_VAR(("", "", 8 - (output_bits%8), DATA_TYPE_PAD, DATA_DIRECTION_OUTPUT, 0, 0));
// now that all the toc entries have been added, write out the tocs to memory and set up the toc pointers
memory.discovery.input = input_bits >> 3;
memory.discovery.output = output_bits >> 3;
memory.discovery.ptocp = MEMPTR(*heap_ptr);
for(uint8_t i = 0; i < ptocp - ptoc; i++) {
*heap_ptr++ = ptoc[i] & 0x00FF;
*heap_ptr++ = (ptoc[i] & 0xFF00) >> 8;
}
*heap_ptr++ = 0x00; *heap_ptr++ = 0x00; // this is the ptoc end marker
memory.discovery.gtocp = MEMPTR(*heap_ptr);
for(uint8_t i = 0; i < gtocp - gtoc; i++) {
*heap_ptr++ = gtoc[i] & 0x00FF;
*heap_ptr++ = (gtoc[i] & 0xFF00) >> 8;
}
*heap_ptr++ = 0x00; *heap_ptr++ = 0x00; // this is the gtoc end marker
timeout = 1000;
);
uint8_t crc_reuest(uint8_t len) {
uint8_t crc = crc8_init();
for(int i = rxpos; i < rxpos+len; i++){
crc = crc8_update(crc, (void*)&(rxbuf[i%sizeof(rxbuf)]), 1);
}
crc8_finalize(crc);
return crc == rxbuf[(rxpos+len)%sizeof(rxbuf)];
}
uint8_t crc8( uint8_t *addr, uint8_t len) {
uint8_t crc = crc8_init();
crc = crc8_update(crc, addr, len);
return crc8_finalize(crc);
}
void send(uint8_t len, uint8_t docrc){
timeout = 0;
if(docrc){
txbuf[len] = crc8((uint8_t *)txbuf,len);
DMA_SetCurrDataCounter(DMA1_Stream7,len+1);
}else{
DMA_SetCurrDataCounter(DMA1_Stream7,len);
}
DMA_Cmd(DMA1_Stream7, DISABLE);
DMA_ClearFlag(DMA1_Stream7, DMA_FLAG_TCIF7);
DMA_Cmd(DMA1_Stream7, ENABLE);
}
#define BITSLEFT(ptr) (8-ptr)
void process_data_rpc(uint8_t fault, volatile uint8_t *input, volatile uint8_t *output) {
uint16_t *ptocp = (uint16_t *)(memory.bytes + memory.discovery.ptocp);
uint32_t local_rxpos = rxpos;
*(input++) = fault;
*input = 0x00;
// data needs to be packed and unpacked based on its type and size
// input is a pointer to the data that gets sent back to the host
// need a bit pointer to keep track of partials
uint8_t output_bit_ptr = 0;
uint8_t input_bit_ptr = 0;
while(*ptocp != 0x0000) {
process_data_descriptor_t *pd = (process_data_descriptor_t *)(memory.bytes + *ptocp++);
if (IS_INPUT(pd)) {
uint16_t data_addr = pd->data_addr;
uint8_t data_size = pd->data_size;
uint8_t data_bit_ptr = 0;
while(data_size > 0) {
uint8_t bits_to_pack = data_size < BITSLEFT(input_bit_ptr) ? data_size : BITSLEFT(input_bit_ptr);
if (BITSLEFT(data_bit_ptr) < bits_to_pack) { bits_to_pack = BITSLEFT(data_bit_ptr); }
uint8_t mask = ((1<<bits_to_pack) - 1) << (data_bit_ptr);
*input |= ((MEMU8(data_addr) & mask) >> data_bit_ptr) << input_bit_ptr;
input_bit_ptr += bits_to_pack;
data_bit_ptr += bits_to_pack;
data_size -= bits_to_pack;
if((input_bit_ptr %= 8) == 0) *(++input) = 0x00; // make sure we clear the input buffer whenever we increment bytes
if((data_bit_ptr %= 8) == 0) data_addr++;
}
}
if (IS_OUTPUT(pd)) {
uint16_t data_addr = pd->data_addr;
uint8_t data_size = pd->data_size;
uint8_t val_bits_remaining = 8;
uint8_t val = 0x00;
while(data_size > 0) {
// the number of bits to unpack this iteration is the number of bits remaining in the pd, or the number of bits remaining in the output byte,
// whichever is smaller. Then, it can be even smaller if we have less room in the current val.
uint8_t bits_to_unpack = data_size < BITSLEFT(output_bit_ptr) ? data_size : BITSLEFT(output_bit_ptr);
if (val_bits_remaining < bits_to_unpack) { bits_to_unpack = val_bits_remaining; }
// create a bitmask the width of the bits to read, shifted to the position in the output byte that we're pointing to
uint8_t mask = ((1<<bits_to_unpack) - 1) << (output_bit_ptr);
// val is what we get when we mask off output and then shift it to the proper place.
val = val | ((rxbuf[(local_rxpos+1)%sizeof(rxbuf)] & mask) >> (output_bit_ptr)) << (8-val_bits_remaining);
val_bits_remaining -= bits_to_unpack;
data_size -= bits_to_unpack;
output_bit_ptr += bits_to_unpack;
// rxpos is a ringbuf and wraps around
// note: this replaces the output argument
if((output_bit_ptr %= 8) == 0){
local_rxpos++;
local_rxpos = local_rxpos % sizeof(rxbuf);
}
if(val_bits_remaining == 0 || data_size == 0) {
MEMU8(data_addr++) = val;
val_bits_remaining = 8;
val = 0x00;
}
}
// now we've finished unpacking it and storing it in memory, but we have to fix up the high bits if it wasn't a byte-aligned datasize.
// for instance, if we receive 0xFFF in a 12 bit field, that is a negative number, but we stored it as 0x0FFF in memory.
// strategy is to set the most significant n bits of the MSB to the most significant bit of the output value, iff the pd is defined as signed.
if (SIGNED(pd) && pd->data_size % 8 != 0) {
//printf("in output fixup. data_addr %h data_size %i num_bytes %i\n", pd->data_addr, pd->data_size, NUM_BYTES(pd->data_size));
uint8_t msb_addr = pd->data_addr + NUM_BYTES(pd->data_size) - 1;
//printf("in output fixup. MSB (at %h): %h\n", msb_addr, MEMU8(msb_addr));
// these two masks use data_size%8, this is the number of bits in the most significant byte, and since we tested for %8!=0 above, we know it's a partial byte
if(MEMU8(msb_addr) & 1<<(pd->data_size%8 - 1)) { // this test uses a mask that is 1 in the most significant bit position, we only need to fixup the val if it's 1 (ie negative)
// this mask is all the unused high bits set
uint8_t mask = 0xFF ^ ((1<<pd->data_size%8) - 1);
//printf("applying mask: %h\n", mask);
MEMU8(msb_addr) |= mask;
}
//printf("fixed up val: %h\n", MEMU8(msb_addr));
}
}
}
}
float scale_out(pd_metadata_t pd, int32_t val) {
return val * pd.range / (float)pd.bitmax;
}
int32_t scale_in(pd_metadata_t pd, float val) {
return CLAMP(val, pd.ptr->param_min, pd.ptr->param_max) * pd.bitmax / pd.range;
}
#define BOOLPIN(pin) (uint8_t)(PIN(pin) != 0.0)
RT (
// update all hal pins with values from their associated pds
PIN(pos_cmd) = scale_out(pd_table.pos_cmd, (int16_t)(MEMU16(pd_table.pos_cmd.ptr->data_addr)));
uint8_t outpins = MEMU8(pd_table.output_pins.ptr->data_addr);
PIN(out0) = outpins & 1 ? 1.0 : 0.0;
PIN(out1) = outpins & 1 ? 1.0 : 0.0;
PIN(out2) = outpins & 1 ? 1.0 : 0.0;
PIN(out3) = outpins & 1 ? 1.0 : 0.0;
// todo: how to handle bidirectional pins properly?
*((uint16_t *)&(memory.bytes[pd_table.pos_fb.ptr->data_addr])) = (uint16_t)scale_in(pd_table.pos_fb, PIN(pos_fb));
MEMU8(pd_table.input_pins.ptr->data_addr) = BOOLPIN(in0)<<0 | BOOLPIN(in1)<<1 | BOOLPIN(in2)<<2 | BOOLPIN(in3)<<3;
);
FRT(
lbp_t lbp;
char name[] = LBPCardName;
int bufferpos;
int available;
for(int j = 0;j<2;j++){
//next received packet will be written to bufferpos
bufferpos = sizeof(rxbuf) - DMA_GetCurrDataCounter(DMA2_Stream5);
//how many packets we have the the rx buffer for processing
available = (bufferpos - rxpos + sizeof(rxbuf)) % sizeof(rxbuf);
if (available >= 1) {
lbp.byte = rxbuf[rxpos];
if (lbp.ct == CT_LOCAL && lbp.wr == 0) { //local read, cmd+crc = 2b
if(available >= 2){
switch(lbp.byte) {
case LBPCookieCMD:
txbuf[0] = LBPCookie;
break;
case LBPStatusCMD: //TODO: return status
txbuf[0] = 0x00;
break;
case LBPCardName0Cmd ... LBPCardName3Cmd:
txbuf[0] = name[lbp.byte-LBPCardName0Cmd];
break;
default: //TODO: handle unknown command condition
txbuf[0] = 0x00;
}
send(1,1);
rxpos += 2;
}else{
continue;
}
}else if(lbp.ct == CT_LOCAL && lbp.wr == 1){//local write, cmd+data+crc = 3b
//0xFF and 0xFC are not followed by crc
if(rxbuf[rxpos] == 0xFF){
// reset parser
timeout = 0;
rxpos += 1;
}else if(rxbuf[rxpos] == 0xFC){
// todo
timeout = 0;
rxpos += 1;
}else if(available >= 3){//writes do not expect crc in reply
txbuf[0] = 0x00;
send(1,0);
rxpos += 3;
}else{
continue;
}
}else if(lbp.ct == CT_RPC){//RPC
if(lbp.byte == UnitNumberRPC && available >= 2){//unit number, cmd+crc = 2b
txbuf[0] = 0x76;
txbuf[1] = 0x01;
txbuf[2] = 0x00;
txbuf[3] = 0x10;
send(4,1);
rxpos += 2;
}else if(lbp.byte == DiscoveryRPC && available >= 2){//discovery, cmd+crc = 2b
memcpy((void*)txbuf,((uint8_t*)&memory.discovery),sizeof(memory.discovery));
send(sizeof(memory.discovery),1);
rxpos += 2;
}else if(lbp.byte == ProcessDataRPC && available >= memory.discovery.output + 2){//process data, requires cmd+output bytes+crc
//TODO: maybe packing and unpacking can be moved to RT
process_data_rpc(0x00, txbuf, &(rxbuf[rxpos+1])); // todo: send a proper fault byte?
send(memory.discovery.input,1);
//we cannot send the reply based on crc, as this causes timeouts
//instead we should check for errors in RT
if(!crc_reuest(memory.discovery.output + 1)){
PIN(crc_error)++;
}
rxpos += memory.discovery.output + 2;
}else{
continue;
}
}else if (lbp.ct == CT_RW && lbp.wr == 0){ //read
if(available >= 2){
if (lbp.as == 1){ //address included in command = cmd+addr+addr+crc
if (available >= 4) {
address = rxbuf[(rxpos+1)%sizeof(rxbuf)] + (rxbuf[(rxpos+2)%sizeof(rxbuf)]<<8);
rxpos += 4;
}else{
continue;
}
}else{ //address not included in command = cmd+crc
rxpos += 2;
}
memcpy((void*)txbuf,&memory.bytes[address],(1<<lbp.ds));
send((1<<lbp.ds),1);
if(lbp.ai == 1){//auto increment address by datasize
address += (1<<lbp.ds);
}
}else{
continue;
}
} else {
//TODO: handle unkown packet
PIN(error)++;
}
}
timeout++;
if(timeout > PIN(timeout)){//TODO: clamping
PIN(connected) = 0;
rxpos = bufferpos;
}else{
PIN(connected) = 1;
}
rxpos = rxpos % sizeof(rxbuf);
}
);
NRT(
if(PIN(dump_pd_vals) != 0.0) {
if(PIN(error) != 0) {
printf("Error count: %f\n", PIN(error));
}
PIN(dump_pd_vals) = 0.0;
printf("pos_cmd: %f\n", PIN(pos_cmd));
uint16_t *ptocp = (uint16_t *)(memory.bytes + memory.discovery.ptocp);
while(*ptocp != 0x0000) {
process_data_descriptor_t *pd = (process_data_descriptor_t *)(memory.bytes + *ptocp++);
printf("pd has data at %x with value %x\n", pd->data_addr, MEMU16(pd->data_addr));
}
}
);
ENDCOMP;