pcan_pro_x/Src/pcanpro_protocol.c

967 lines
28 KiB
C

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include "pcanpro_can.h"
#include "pcan_usbpro_fw.h"
#include "pcanpro_timestamp.h"
#include "pcanpro_protocol.h"
#include "pcanpro_led.h"
#include "pcanpro_usbd.h"
#include "usb_device.h"
#define CAN_CHANNEL_MAX (2)
#define PCAN_USBPRO_RTR 0x01
#define PCAN_USBPRO_EXT 0x02
#define PCAN_USBPRO_SR 0x80
/* PCAN-USB-PRO status flags */
#define PCAN_USBPRO_BUS_HEAVY 0x01
#define PCAN_USBPRO_BUS_OVERRUN 0x0c
static struct
{
struct
{
/* error handling related */
uint8_t err;
uint8_t ecc;
uint8_t rx_err;
uint8_t tx_err;
/* config */
uint8_t silient;
uint8_t bus_active;
uint8_t loopback;
uint8_t err_mask;
uint32_t ccbt; /* current baudrate value */
uint32_t channel_nr;
uint8_t led_is_busy;
}
can[CAN_CHANNEL_MAX];
uint32_t device_nr;
uint32_t time_calibration_mode;
uint32_t last_time_sync;
uint32_t last_flush;
}
pcan_device =
{
.device_nr = 0xFFFFFFFF,
.can[0] =
{
.channel_nr = 0xFFFFFFFF
},
.can[1] =
{
.channel_nr = 0xFFFFFFFF
},
};
/* internal structure used to handle messages sent to bulk urb */
struct pcan_usbpro_msg
{
uint8_t * rec_ptr;
int rec_buffer_size;
int rec_buffer_len;
union
{
uint16_t * rec_counter_read;
uint32_t * rec_counter;
uint8_t * rec_buffer;
} u;
};
#define PCAN_USB_DATA_BUFFER_SIZE 1024
static uint8_t resp_buffer[2][PCAN_USB_DATA_BUFFER_SIZE];
static uint8_t temp_resp_buffer[2][PCAN_USB_DATA_BUFFER_SIZE];
static uint8_t drv_load_packet[16];
static struct pcan_usbpro_msg resp[2];
static struct t_m2h_fsm resp_fsm[2] =
{
[0] = {
.state = 0,
.ep_addr = PCAN_USB_EP_CMDIN,
.pdbuf = temp_resp_buffer[0],
.dbsize = PCAN_USB_DATA_BUFFER_SIZE,
},
[1] = {
.state = 0,
.ep_addr = PCAN_USB_EP_MSGIN_CH1,
.pdbuf = temp_resp_buffer[1],
.dbsize = PCAN_USB_DATA_BUFFER_SIZE,
}
};
/* low level requests */
uint8_t pcan_protocol_device_setup( USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req )
{
switch( req->bRequest )
{
case USB_VENDOR_REQUEST_INFO:
switch( req->wValue )
{
case USB_VENDOR_REQUEST_wVALUE_INFO_BOOTLOADER:
{
static struct pcan_usbpro_bootloader_info bi =
{
.ctrl_type = BOOTLOADER_INFO_STRUCT_TYPE,
.version[0] = 0,
.version[1] = 0,
.version[2] = 0,
.version[3] = 0,
.day = 0,
.month = 0,
.year = 0,
.dummy = 0,
.serial_num_high = 200030,
.serial_num_low = 1,
.hw_type = 0,
.hw_rev = 0,
};
return USBD_CtlSendData( pdev, (void*)&bi, sizeof( struct pcan_usbpro_bootloader_info ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_FIRMWARE:
{
static struct pcan_usbpro_ext_firmware_info fwi =
{
.ctrl_type = EXT_FIRMWARE_INFO_STRUCT_TYPE,
.version[0] = 1,
.version[1] = 3,
.version[2] = 3,
.version[3] = 0,
.day = 0,
.month = 0,
.year = 0,
.dummy = 0,
.fw_type = 0,
};
return USBD_CtlSendData( pdev, (void*)&fwi, sizeof( struct pcan_usbpro_ext_firmware_info ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_uC_CHIPID:
{
static struct pcan_usbpro_uc_chipid uc_chid =
{
.ctrl_type = uC_CHIPID_STRUCT_TYPE,
.chip_id = 0,
};
return USBD_CtlSendData( pdev, (void*)&uc_chid, sizeof( struct pcan_usbpro_uc_chipid ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_USB_CHIPID:
{
static struct pcan_usbpro_usb_chipid usb_chid =
{
.ctrl_type = USB_CHIPID_STRUCT_TYPE,
.chip_id = 0,
};
return USBD_CtlSendData( pdev, (void*)&usb_chid, sizeof( struct pcan_usbpro_usb_chipid ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_DEVICENR:
{
static struct pcan_usbpro_device_nr device_nr =
{
.ctrl_type = DEVICE_NR_STRUCT_TYPE,
.device_nr = 0xFFFFFFFF,
};
return USBD_CtlSendData( pdev, (void*)&device_nr, sizeof( struct pcan_usbpro_device_nr ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_CPLD:
{
static struct pcan_usbpro_cpld_info cpldi =
{
.ctrl_type = CPLD_INFO_STRUCT_TYPE,
.cpld_nr = 0,
};
return USBD_CtlSendData( pdev, (void*)&cpldi, sizeof( struct pcan_usbpro_cpld_info ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_MODE:
{
static struct pcan_usbpro_info_mode info = { 0 };
return USBD_CtlSendData( pdev, (void*)&info, sizeof( struct pcan_usbpro_info_mode ) );
}
case USB_VENDOR_REQUEST_wVALUE_INFO_TIMEMODE:
{
static struct pcan_usbpro_time_mode info = { 0 };
return USBD_CtlSendData( pdev, (void*)&info, sizeof( struct pcan_usbpro_time_mode ) );
}
default:
assert(0);
break;
}
break;
case USB_VENDOR_REQUEST_FKT:
switch( req->wValue )
{
case USB_VENDOR_REQUEST_wVALUE_SETFKT_BOOT:
break;
case USB_VENDOR_REQUEST_wVALUE_SETFKT_DEBUG_CAN:
break;
case USB_VENDOR_REQUEST_wVALUE_SETFKT_DEBUG_LIN:
break;
case USB_VENDOR_REQUEST_wVALUE_SETFKT_DEBUG1:
break;
case USB_VENDOR_REQUEST_wVALUE_SETFKT_DEBUG2:
break;
case USB_VENDOR_REQUEST_wVALUE_SETFKT_INTERFACE_DRIVER_LOADED:
{
USBD_CtlPrepareRx( pdev, drv_load_packet, 16 );
return USBD_OK;
}
break;
default:
assert(0);
break;
}
break;
case USB_VENDOR_REQUEST_ZERO:
break;
default:
USBD_CtlError( pdev, req );
return USBD_FAIL;
}
return USBD_FAIL;
}
void pcan_ep0_receive( void )
{
/* CAN */
if( drv_load_packet[0] == 0 )
{
pcan_flush_ep( PCAN_USB_EP_MSGIN_CH1 );
pcan_flush_ep( PCAN_USB_EP_CMDIN );
pcan_led_set_mode( LED_STAT, LED_MODE_BLINK_SLOW, 0xFFFFFFFF );
}
else
{
/* LIN */
;
}
}
/*
* static int pcan_usbpro_sizeof_rec(uint8_t data_type)
*/
static int pcan_usbpro_sizeof_rec(uint8_t data_type)
{
switch (data_type)
{
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_8:
return sizeof(struct pcan_usbpro_canmsg_rx);
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_4:
return sizeof(struct pcan_usbpro_canmsg_rx) - 4;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_0:
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RTR_RX:
return sizeof(struct pcan_usbpro_canmsg_rx) - 8;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_STATUS_ERROR_RX:
return sizeof(struct pcan_usbpro_canmsg_status_error_rx);
case DATA_TYPE_USB2CAN_STRUCT_CALIBRATION_TIMESTAMP_RX:
return sizeof(struct pcan_usbpro_calibration_ts_rx);
case DATA_TYPE_USB2CAN_STRUCT_BUSLAST_RX:
return sizeof(struct pcan_usbpro_buslast_rx);
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_8:
return sizeof(struct pcan_usbpro_canmsg_tx);
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_4:
return sizeof(struct pcan_usbpro_canmsg_tx) - 4;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_0:
return sizeof(struct pcan_usbpro_canmsg_tx) - 8;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETBAUDRATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETBAUDRATE:
return sizeof(struct pcan_usbpro_baudrate);
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUSACTIVATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETCANBUSACTIVATE:
return sizeof(struct pcan_usbpro_bus_activity);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETSILENTMODE:
return sizeof(struct pcan_usbpro_silent_mode);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETDEVICENR:
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETDEVICENR:
return sizeof(struct pcan_usbpro_dev_nr);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETWARNINGLIMIT:
return sizeof(struct pcan_usbpro_warning_limit);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETLOOKUP_EXPLICIT:
return sizeof(struct pcan_usbpro_lookup_explicit);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETLOOKUP_GROUP:
return sizeof(struct pcan_usbpro_lookup_group);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETFILTERMODE:
return sizeof(struct pcan_usbpro_filter_mode);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETRESET_MODE:
return sizeof(struct pcan_usbpro_reset_mode);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETERRORFRAME:
return sizeof(struct pcan_usbpro_error_frame);
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUS_ERROR_STATUS:
return sizeof(struct pcan_usbpro_error_status);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETREGISTER:
return sizeof(struct pcan_usbpro_set_register);
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETREGISTER:
return sizeof(struct pcan_usbpro_get_register);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_CALIBRATION_MSG:
return sizeof(struct pcan_usbpro_calibration);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_BUSLAST_MSG:
return sizeof(struct pcan_usbpro_buslast);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETSTRING:
return sizeof(struct pcan_usbpro_set_string);
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETSTRING:
return sizeof(struct pcan_usbpro_get_string);
case DATA_TYPE_USB2CAN_STRUCT_FKT_STRING:
return sizeof(struct pcan_usbpro_string);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SAVEEEPROM:
return sizeof(struct pcan_usbpro_save_eeprom);
case DATA_TYPE_USB2CAN_STRUCT_FKT_USB_IN_PACKET_DELAY:
return sizeof(struct pcan_usbpro_packet_delay);
case DATA_TYPE_USB2CAN_STRUCT_FKT_TIMESTAMP_PARAM:
return sizeof(struct pcan_usbpro_timestamp_param);
case DATA_TYPE_USB2CAN_STRUCT_FKT_ERROR_GEN_ID:
return sizeof(struct pcan_usbpro_error_gen_id);
case DATA_TYPE_USB2CAN_STRUCT_FKT_ERROR_GEN_NOW:
return sizeof(struct pcan_usbpro_error_gen_now);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_SOFTFILER:
return sizeof(struct pcan_usbpro_softfiler);
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_CANLED:
return sizeof(struct pcan_usbpro_set_can_led);
default:
assert( 0 );
}
return -1;
}
/*
* static uint8_t * pcan_usbpro_msg_init(struct pcan_usbpro_msg *pm,
* void *buffer_addr, int buffer_size)
*
* Initialize PCAN USB-PRO message data structure
*/
static uint8_t * pcan_usbpro_msg_init(struct pcan_usbpro_msg *pm,
void *buffer_addr, int buffer_size)
{
if (buffer_size < 4)
return NULL;
pm->u.rec_buffer = (uint8_t *)buffer_addr;
pm->rec_buffer_size = pm->rec_buffer_len = buffer_size;
pm->rec_ptr = pm->u.rec_buffer + 4;
return pm->rec_ptr;
}
static uint8_t * pcan_usbpro_msg_init_empty(struct pcan_usbpro_msg *pm,
void *buffer_addr, int buffer_size)
{
uint8_t *pr = pcan_usbpro_msg_init(pm, buffer_addr, buffer_size);
if (pr) {
pm->rec_buffer_len = 4;
*pm->u.rec_counter = 0;
}
return pr;
}
static void pcan_usbpro_msg_reset( struct pcan_usbpro_msg *pm )
{
pm->rec_ptr = pm->u.rec_buffer + 4;
pm->rec_buffer_len = 4;
*pm->u.rec_counter = 0;
}
/*
* static int pcan_usbpro_msg_add_rec(struct pcan_usbpro_msg *pm,
* int id, ...)
*
* Add one record to a message being built.
*/
static int pcan_usbpro_msg_add_rec(struct pcan_usbpro_msg *pm,
int id, ...)
{
int l, i;
uint8_t *pc;
va_list ap;
va_start(ap, id);
if( pm->rec_buffer_size < ( pcan_usbpro_sizeof_rec( id ) + pm->rec_buffer_len ))
{
for(;;);
}
pc = pm->rec_ptr + 1;
i = 0;
switch (id) {
case DATA_TYPE_USB2CAN_STRUCT_BUSLAST_RX:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // buslast_val
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // timestamp
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_8:
i += 4;
/* fall through */
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_4:
i += 4;
/* fall through */
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_0:
*pc++ = (uint8_t )va_arg(ap, int); // client
*pc++ = (uint8_t )va_arg(ap, int); // flags
*pc++ = (uint8_t )va_arg(ap, int); // len
*(uint32_t *)pc = va_arg(ap, uint32_t); // id
pc += 4;
memcpy(pc, va_arg(ap, int *), i);
pc += i;
break;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_8:
i += 4;
/* fall through */
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_4:
i += 4;
/* fall through */
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_0:
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_RTR_RX:
*pc++ = (uint8_t )va_arg(ap, int); // client
*pc++ = (uint8_t )va_arg(ap, int); // flags
*pc++ = (uint8_t )va_arg(ap, int); // len
*(uint32_t *)pc = va_arg(ap, uint32_t); // timestamp
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // id
pc += 4;
memcpy(pc, va_arg(ap, int *), i);
pc += i;
break;
case DATA_TYPE_USB2CAN_STRUCT_CALIBRATION_TIMESTAMP_RX:
pc += 3; // dummy
*(uint32_t *)pc = va_arg(ap, uint32_t); // timestamp64[0] usb frame index
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // timestamp64[1] ts us
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUSACTIVATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUS_ERROR_STATUS:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // onoff,status
pc += 2;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETBAUDRATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETBAUDRATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETDEVICENR:
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETDEVICENR:
*pc++ = (uint8_t )va_arg(ap, int); // channel
pc += 2; // dummy
/* CCBT, devicenr */
*(uint32_t *)pc = va_arg(ap, uint32_t);
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETCANBUSACTIVATE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETSILENTMODE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETWARNINGLIMIT:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETFILTERMODE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETRESET_MODE:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETERRORFRAME:
case DATA_TYPE_USB2CAN_STRUCT_FKT_TIMESTAMP_PARAM:
case DATA_TYPE_USB2CAN_STRUCT_FKT_ERROR_GEN_NOW:
*pc++ = (uint8_t )va_arg(ap, int); // channel
/* onoff, silentmode, warninglimit, filter_mode, reset, mode, */
/* start_or_end, bit_pos */
*(uint16_t *)pc = (uint16_t )va_arg(ap, int);
pc += 2;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETLOOKUP_EXPLICIT:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_CANLED:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // id_type,mode
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // id, timeout
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETLOOKUP_GROUP:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // id_type
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // id_start
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // id_end
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETREGISTER:
*pc++ = (uint8_t )va_arg(ap, int); // irq_off
pc += 2; // dummy
*(uint32_t *)pc = va_arg(ap, uint32_t); // address
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // value
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // mask
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETREGISTER:
*pc++ = (uint8_t )va_arg(ap, int); // irq_off
pc += 2; // dummy
*(uint32_t *)pc = va_arg(ap, uint32_t); // address
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // value
pc += 4;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_CALIBRATION_MSG:
case DATA_TYPE_USB2CAN_STRUCT_FKT_USB_IN_PACKET_DELAY:
pc++; // dummy
/* mode, delay */
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // mode
pc += 2;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_BUSLAST_MSG:
*pc++ = (uint8_t )va_arg(ap, int); // channel
pc++; // dummy
*pc++ = (uint8_t )va_arg(ap, int); // mode
//*(uint16_t *)pc = (uint16_t )va_arg(ap, int)); // prescaler
pc += 2; // prescale (readonly)
//*(uint16_t *)pc = (uint16_t )va_arg(ap, int)); // sampletimequanta
*(uint16_t *)pc = 4096; // sampletimequanta
pc += 2;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETSTRING:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*pc++ = (uint8_t )va_arg(ap, int); // offset
*pc++ = (uint8_t )va_arg(ap, int); // len
memcpy(pc, va_arg(ap, uint8_t *), 60);
pc += 60;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETSTRING:
case DATA_TYPE_USB2CAN_STRUCT_FKT_SAVEEEPROM:
*pc++ = (uint8_t )va_arg(ap, int); // channel
pc += 2; // dummy
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_STRING:
*pc++ = (uint8_t )va_arg(ap, int); // channel
pc += 2; // dummy
memcpy(pc, va_arg(ap, uint8_t *), 250);
pc += 250;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_ERROR_GEN_ID:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // bit_pos
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // id
pc += 4;
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // ok_counter
pc += 2;
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); //error_counter
pc += 2;
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_SOFTFILER:
*pc++ = (uint8_t )va_arg(ap, int); // channel
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // accmask
pc += 4;
*(uint32_t *)pc = va_arg(ap, uint32_t); // acccode
pc += 4;
break;
#if 0
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_CANLED:
*pc++ = (uint8_t )va_arg(ap, int); // channel
*(uint16_t *)pc = (uint16_t )va_arg(ap, int); // mode
pc += 2;
*(uint32_t *)pc = va_arg(ap, uint32_t); // timeout
pc += 4;
break;
#endif
default:
assert( 0 );
break;
}
l = pc - pm->rec_ptr;
if (l > 0) {
*pm->u.rec_counter = *pm->u.rec_counter+1;
*(pm->rec_ptr) = (uint8_t )id;
pm->rec_ptr = pc;
pm->rec_buffer_len += l;
}
va_end(ap);
return l;
}
int pcan_protocol_set_baudrate( uint8_t channel, uint32_t ccbt )
{
#define PCAN_USBPRO_SYSCLK_HZ (56000000u)
#define PCAN_STM32_SYSCLK_HZ (24000000u)
uint32_t brp, pcan_brp;
uint32_t tseg1, tseg2;
uint32_t sjw;
uint32_t tsam; /* triple sampling */
uint32_t bitrate, pcan_bitrate;
tsam = ( ccbt >> 23 ) & 1;
(void)tsam;
tseg2 = (( ccbt >> 20) & 0x07 ) + 1;
tseg1 = (( ccbt >> 16) & 0x0f ) + 1;
sjw = (( ccbt >> 14) & 0x03 ) + 1;
brp = ( ccbt & 0x3fff ) + 1;
pcan_brp = (24*brp)/56;
bitrate = (((PCAN_USBPRO_SYSCLK_HZ)/brp)/(1/*tq*/ + tseg1 + tseg2 ));
pcan_bitrate = (((PCAN_STM32_SYSCLK_HZ)/pcan_brp)/(1/*tq*/ + tseg1 + tseg2 ));
if( bitrate != pcan_bitrate )
{
pcan_can_set_bitrate( channel, bitrate, 0 );
}
else
{
pcan_can_set_bitrate_ex( channel, pcan_brp, tseg1, tseg2, sjw );
}
/* save driver value without adjustments */
pcan_device.can[channel].ccbt = ccbt;
return 0;
}
int pcan_protocol_rx_frame( uint8_t channel, struct t_can_msg *pmsg )
{
uint8_t rec_type;
uint8_t client;
uint8_t flags;
if( !pcan_device.can[channel].led_is_busy && !(pmsg->flags & MSG_FLAG_ECHO) )
{
pcan_led_set_mode( channel ? LED_CH1_RX:LED_CH0_RX, LED_MODE_BLINK_FAST, 237 );
}
if( pmsg->flags & MSG_FLAG_RTR )
rec_type = DATA_TYPE_USB2CAN_STRUCT_CANMSG_RTR_RX;
else if( pmsg->size == 0 )
rec_type = DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_0;
else if( pmsg->size <= 4 )
rec_type = DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_4;
else
rec_type = DATA_TYPE_USB2CAN_STRUCT_CANMSG_RX_8;
client = 0;
flags = 0;
if( pmsg->flags & MSG_FLAG_ECHO )
{
flags |= 0x04; /* SELF RECIEVE */
client = pmsg->dummy;
}
if( pmsg->flags & MSG_FLAG_RTR )
flags |= PCAN_USBPRO_RTR;
if( pmsg->flags & MSG_FLAG_EXT )
flags |= PCAN_USBPRO_EXT;
pcan_usbpro_msg_add_rec( &resp[PCAN_USB_BUFFER_DATA], rec_type,
client, flags,
( (channel<<4)| pmsg->size),
pmsg->timestamp,
pmsg->id,
pmsg->data );
return 0;
}
int pcan_protocol_tx_frame_cb( uint8_t channel, struct t_can_msg *pmsg )
{
if( pmsg->flags & MSG_FLAG_ECHO )
{
(void)pcan_protocol_rx_frame( channel, pmsg );
}
if( !pcan_device.can[channel].led_is_busy )
{
pcan_led_set_mode( channel ? LED_CH1_TX:LED_CH0_TX, LED_MODE_BLINK_FAST, 237 );
}
return 0;
}
int pcan_protocol_tx_frame( struct pcan_usbpro_canmsg_tx *pmsg )
{
struct t_can_msg msg = { 0 };
uint8_t channel;
channel = (pmsg->len>>4)&0x0f;
if( channel >= CAN_CHANNEL_MAX )
return -1;
msg.id = pmsg->id;
msg.size = pmsg->len & 0x0f;
if( msg.size > sizeof( msg.data ) )
return -1;
if (pmsg->flags & PCAN_USBPRO_RTR)
msg.flags |= MSG_FLAG_RTR;
if (pmsg->flags & PCAN_USBPRO_EXT)
msg.flags |= MSG_FLAG_EXT;
if (pmsg->client & PCAN_USBPRO_SR)
{
msg.flags |= MSG_FLAG_ECHO;
msg.dummy = pmsg->client;
}
memcpy( msg.data, pmsg->data, msg.size );
msg.timestamp = pcan_timestamp_us();
if( pcan_can_write( channel, &msg ) < 0 )
{
/* tx queue overflow ? */
pcan_device.can[channel].err |= 0;
}
#if 0
if( msg.flags & CAN_FLAG_ECHO )
{
(void)pcan_protocol_rx_frame( channel, &msg );
}
#endif
return 0;
}
void pcan_protocol_process_data( uint8_t ep, uint8_t *ptr, uint16_t size )
{
struct pcan_usbpro_msg m = { 0 };
uint8_t *rec_ptr = 0;
static volatile uint32_t wow_big = 0;
if( size > 64 )
{
++wow_big;
}
rec_ptr = pcan_usbpro_msg_init( &m, ptr, size );
if( !rec_ptr )
return;
int buffer_ep = ( ep == 1 ) ? PCAN_USB_BUFFER_CMD: PCAN_USB_BUFFER_DATA;
uint32_t r;
for( r = 0; r < *m.u.rec_counter_read; r++ )
{
int rec_size;
union pcan_usbpro_rec *prec = (void*)rec_ptr;
rec_size = pcan_usbpro_sizeof_rec( prec->data_type );
if( rec_size < 0 || size < ( rec_size + 4 ) )
return; /* bad data */
switch( prec->data_type )
{
default:
assert( 0 );
break;
/* windows only */
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETWARNINGLIMIT:
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETFILTERMODE:
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETERRORFRAME:
break;
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_8:
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_4:
case DATA_TYPE_USB2CAN_STRUCT_CANMSG_TX_0:
if( (prec->canmsg_tx.len>>4) < CAN_CHANNEL_MAX )
{
(void)pcan_protocol_tx_frame( &prec->canmsg_tx );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETBAUDRATE:
if( prec->baudrate.channel < CAN_CHANNEL_MAX )
{
pcan_usbpro_msg_add_rec( &resp[buffer_ep], DATA_TYPE_USB2CAN_STRUCT_FKT_GETBAUDRATE,
prec->baudrate.channel, pcan_device.can[prec->dev_nr.channel].ccbt );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETBAUDRATE:
if( prec->baudrate.channel < CAN_CHANNEL_MAX )
{
(void)pcan_protocol_set_baudrate( prec->baudrate.channel, prec->baudrate.CCBT );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUSACTIVATE:
if( prec->bus_activity.channel < CAN_CHANNEL_MAX )
{
pcan_usbpro_msg_add_rec( &resp[buffer_ep], DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUSACTIVATE,
prec->bus_activity.channel, pcan_device.can[prec->dev_nr.channel].bus_active );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETCANBUSACTIVATE:
if( prec->bus_activity.channel < CAN_CHANNEL_MAX )
{
uint8_t ch = prec->bus_activity.channel;
pcan_device.can[ch].bus_active = prec->bus_activity.onoff;
pcan_can_set_bus_active( (ch == 0)?CAN_BUS_1:CAN_BUS_2, prec->bus_activity.onoff );
if( !pcan_device.can[ch].led_is_busy )
{
pcan_led_set_mode( ch ? LED_CH1_RX:LED_CH0_RX, prec->bus_activity.onoff ? LED_MODE_ON: LED_MODE_OFF, 0xFFFFFFFF );
}
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETSILENTMODE:
if( prec->silent_mode.channel < CAN_CHANNEL_MAX )
{
pcan_device.can[prec->bus_activity.channel].silient = prec->silent_mode.onoff;
pcan_can_set_silent( (prec->silent_mode.channel == 0)?CAN_BUS_1:CAN_BUS_2, prec->silent_mode.onoff );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUS_ERROR_STATUS:
if( prec->error_status.channel < CAN_CHANNEL_MAX )
{
pcan_usbpro_msg_add_rec( &resp[buffer_ep], DATA_TYPE_USB2CAN_STRUCT_FKT_GETCANBUS_ERROR_STATUS,
prec->error_status.channel, 0x0000 );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_CALIBRATION_MSG:
pcan_device.time_calibration_mode = prec->calibration.mode;
if( !pcan_device.time_calibration_mode )
break;
pcan_device.last_time_sync = 0;
pcan_usbpro_msg_add_rec( &resp[PCAN_USB_BUFFER_DATA], DATA_TYPE_USB2CAN_STRUCT_CALIBRATION_TIMESTAMP_RX,
pcan_usb_frame_number(), pcan_timestamp_us() );
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETGET_BUSLAST_MSG:
/* TODO: */
(void)prec->buslast.channel;
(void)prec->buslast.mode;
(void)prec->buslast.prescaler;
(void)prec->buslast.sampletimequanta;
pcan_usbpro_msg_add_rec( &resp[PCAN_USB_BUFFER_DATA], DATA_TYPE_USB2CAN_STRUCT_BUSLAST_RX,
prec->buslast.channel, 0, pcan_timestamp_us() );
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_GETDEVICENR:
if( prec->dev_nr.channel < CAN_CHANNEL_MAX )
{
pcan_usbpro_msg_add_rec( &resp[PCAN_USB_BUFFER_CMD], DATA_TYPE_USB2CAN_STRUCT_FKT_GETDEVICENR,
prec->dev_nr.channel, pcan_device.can[prec->dev_nr.channel].channel_nr );
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SETDEVICENR:
if( prec->dev_nr.channel < CAN_CHANNEL_MAX )
{
pcan_device.can[prec->dev_nr.channel].channel_nr = prec->dev_nr.serial_num;
}
break;
case DATA_TYPE_USB2CAN_STRUCT_FKT_SET_CANLED:
if( prec->dev_nr.channel < CAN_CHANNEL_MAX )
{
pcan_device.can[prec->dev_nr.channel].led_is_busy = prec->set_can_led.mode;
pcan_led_set_mode( prec->dev_nr.channel, prec->set_can_led.mode, prec->set_can_led.timeout );
}
break;
}
rec_ptr += rec_size;
size -= rec_size;
}
}
void pcan_protocol_init( void )
{
pcan_can_init_ex( CAN_BUS_1, 500000 );
pcan_can_set_filter_mask( CAN_BUS_1, 0, 0, 0, 0 );
pcan_can_init_ex( CAN_BUS_2, 500000 );
pcan_can_set_filter_mask( CAN_BUS_2, 0, 0, 0, 0 );
pcan_usbpro_msg_init_empty( &resp[PCAN_USB_BUFFER_CMD], &resp_buffer[PCAN_USB_BUFFER_CMD], sizeof( resp_buffer[PCAN_USB_BUFFER_CMD] ) );
pcan_usbpro_msg_init_empty( &resp[PCAN_USB_BUFFER_DATA], &resp_buffer[PCAN_USB_BUFFER_DATA], sizeof( resp_buffer[PCAN_USB_BUFFER_DATA] ) );
pcan_can_install_rx_callback( CAN_BUS_1, pcan_protocol_rx_frame );
pcan_can_install_rx_callback( CAN_BUS_2, pcan_protocol_rx_frame );
pcan_can_install_tx_callback( CAN_BUS_1, pcan_protocol_tx_frame_cb );
pcan_can_install_tx_callback( CAN_BUS_2, pcan_protocol_tx_frame_cb );
}
void pcan_protocol_poll( void )
{
uint32_t ts_ms = pcan_timestamp_millis();
pcan_can_poll();
for( int i = 0; i < 2; i++ )
{
struct pcan_usbpro_msg *prec = &resp[i];
if( prec->rec_buffer_len > 4 )
{
int res = pcan_flush_data( &resp_fsm[i], prec->u.rec_buffer, prec->rec_buffer_len );
if( res )
{
pcan_usbpro_msg_reset( prec );
}
}
}
if( pcan_device.time_calibration_mode )
{
if( ( ts_ms - pcan_device.last_time_sync ) >= 1000u )
{
pcan_device.last_time_sync = ts_ms;
pcan_usbpro_msg_add_rec( &resp[PCAN_USB_BUFFER_DATA], DATA_TYPE_USB2CAN_STRUCT_CALIBRATION_TIMESTAMP_RX,
pcan_usb_frame_number(), pcan_timestamp_us() );
}
}
}