diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml
index 07840f99..6db256a6 100644
--- a/.github/workflows/build_all.yml
+++ b/.github/workflows/build_all.yml
@@ -20,7 +20,7 @@ jobs:
matrix:
spice: [RAMNV1]
conf: [Release, Debug]
- cubeide_docker_tag: ["7.0", "15.0"]
+ cubeide_docker_tag: ["15.0"]
runs-on: ubuntu-latest
steps:
@@ -73,6 +73,10 @@ jobs:
variant: gsusb
enable: "ENABLE_GSUSB"
disable: "ENABLE_CDC"
+ - ecu: TARGET_ECUA
+ variant: gsusb-fdcan
+ enable: "ENABLE_GSUSB ENABLE_GSUSB_CANFD"
+ disable: "ENABLE_CDC"
- ecu: TARGET_ECUA
variant: no_uds
enable: ""
diff --git a/.gitignore b/.gitignore
index 18ea7cee..ce4d5a22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ hardware/V1_revC/0_ramn/fp-info-cache
firmware/RAMNV1/Core/Inc/ramn_screen_template.h
firmware/RAMNV1/Core/Src/ramn_screen_template.c
firmware/RAMNV1/RAMNV1 Debug.launch
+workspace/
diff --git a/firmware/RAMNV1/.cproject b/firmware/RAMNV1/.cproject
index 36979f11..74c1969b 100644
--- a/firmware/RAMNV1/.cproject
+++ b/firmware/RAMNV1/.cproject
@@ -70,6 +70,7 @@
+
@@ -161,6 +162,7 @@
+
diff --git a/firmware/RAMNV1/Core/Inc/ramn_config.h b/firmware/RAMNV1/Core/Inc/ramn_config.h
index 2abeb5e6..9e5b7c62 100644
--- a/firmware/RAMNV1/Core/Inc/ramn_config.h
+++ b/firmware/RAMNV1/Core/Inc/ramn_config.h
@@ -47,12 +47,15 @@
// Enable this flag to enable the candlelight interface (gs_usb drivers)
// Current implementation is experimental:
-// - Error frames are not reported
-// - CAN-FD is not supported
// - Due to clock differences, bit timings are not respected (but equivalent baudrates are used)
// Try increasing _Min_Stack_Size if you run into issues
//#define ENABLE_GSUSB
+// Enable this flag to enable CAN-FD support in the gs_usb interface.
+// When enabled, FD frames (up to 64 bytes) with BRS and ESI flags are supported.
+// Requires ENABLE_GSUSB to be defined.
+//#define ENABLE_GSUSB_CANFD
+
#ifndef ENABLE_GSUSB
#define USBD_VID 0x483
#define USBD_PID 0x5740
@@ -400,6 +403,10 @@
#error Cannot activate GSUSB without enabling USB
#endif
+#if defined(ENABLE_GSUSB_CANFD) && !defined(ENABLE_GSUSB)
+#error Cannot activate GSUSB_CANFD without enabling GSUSB
+#endif
+
#if defined(ENABLE_USB) && !defined(ENABLE_CDC) && !defined(ENABLE_GSUSB)
#error At least one USB interface must be active if you enable USB
#endif
diff --git a/firmware/RAMNV1/Core/Inc/ramn_gsusb.h b/firmware/RAMNV1/Core/Inc/ramn_gsusb.h
index 8043846a..cf451aba 100644
--- a/firmware/RAMNV1/Core/Inc/ramn_gsusb.h
+++ b/firmware/RAMNV1/Core/Inc/ramn_gsusb.h
@@ -30,6 +30,9 @@ RAMN_Result_t RAMN_GSUSB_ProcessRX(FDCAN_RxHeaderTypeDef *canRxHeader, uint8_t *
// Forward a USB message to CAN
RAMN_Result_t RAMN_GSUSB_ProcessTX(FDCAN_TxHeaderTypeDef *canTxHeader, uint8_t *canRxData);
+// Send a CAN error frame to USB
+RAMN_Result_t RAMN_GSUSB_SendErrorFrame(const FDCAN_ProtocolStatusTypeDef *protocolStatus, const FDCAN_ErrorCountersTypeDef *errorCount, uint32_t err);
+
#endif
#endif /* INC_RAMN_GSUSB_H_ */
diff --git a/firmware/RAMNV1/Core/Src/main.c b/firmware/RAMNV1/Core/Src/main.c
index d33da1ca..f93ac547 100644
--- a/firmware/RAMNV1/Core/Src/main.c
+++ b/firmware/RAMNV1/Core/Src/main.c
@@ -1867,7 +1867,6 @@ void RAMN_ErrorTaskFunc(void *argument)
{
/* USER CODE BEGIN RAMN_ErrorTaskFunc */
/* Infinite loop */
- //TODO: report Errors to GS_USB
FDCAN_ErrorCountersTypeDef errorCount;
FDCAN_ProtocolStatusTypeDef protocolStatus;
RAMN_FDCAN_Status_t gw_freeze;
@@ -1904,6 +1903,13 @@ void RAMN_ErrorTaskFunc(void *argument)
if(err & HAL_FDCAN_ERROR_PROTOCOL_DATA) RAMN_FDCAN_Status.slcanFlags |= SLCAN_FLAG_BUS_ERROR;
#endif
+#ifdef ENABLE_GSUSB
+ if(RAMN_USB_Config.gsusbOpened && GSUSB_IsConnected((USBD_HandleTypeDef*)hpcd_USB_FS.pData))
+ {
+ RAMN_GSUSB_SendErrorFrame(&protocolStatus, &errorCount, err);
+ }
+#endif
+
#if defined(AUTO_RECOVER_BUSOFF)
if (protocolStatus.BusOff != 0U)
{
@@ -2287,10 +2293,7 @@ void RAMN_RxTask2Func(void *argument)
else
{
- // TODO implement CAN-FD
-
//recvFrame->echo_id
- //recvFrame.flags
//recvFrame.reserved
@@ -2302,9 +2305,20 @@ void RAMN_RxTask2Func(void *argument)
if (recvFrame->can_id & CAN_EFF_FLAG) CANTxHeader.IdType = FDCAN_EXTENDED_ID;
else CANTxHeader.IdType = FDCAN_STANDARD_ID;
- CANTxHeader.BitRateSwitch = FDCAN_BRS_OFF;
- CANTxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
- CANTxHeader.FDFormat = FDCAN_CLASSIC_CAN;
+#ifdef ENABLE_GSUSB_CANFD
+ if (recvFrame->flags & GS_CAN_FLAG_FD)
+ {
+ CANTxHeader.FDFormat = FDCAN_FD_CAN;
+ CANTxHeader.BitRateSwitch = (recvFrame->flags & GS_CAN_FLAG_BRS) ? FDCAN_BRS_ON : FDCAN_BRS_OFF;
+ CANTxHeader.ErrorStateIndicator = (recvFrame->flags & GS_CAN_FLAG_ESI) ? FDCAN_ESI_PASSIVE : FDCAN_ESI_ACTIVE;
+ }
+ else
+#endif
+ {
+ CANTxHeader.FDFormat = FDCAN_CLASSIC_CAN;
+ CANTxHeader.BitRateSwitch = FDCAN_BRS_OFF;
+ CANTxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
+ }
CANTxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
//CANTxHeader.MessageMarker = 0U;
diff --git a/firmware/RAMNV1/Core/Src/ramn_gsusb.c b/firmware/RAMNV1/Core/Src/ramn_gsusb.c
index 5d71ba66..55d235dd 100644
--- a/firmware/RAMNV1/Core/Src/ramn_gsusb.c
+++ b/firmware/RAMNV1/Core/Src/ramn_gsusb.c
@@ -30,15 +30,6 @@ RAMN_Result_t RAMN_GSUSB_ProcessRX(FDCAN_RxHeaderTypeDef *canRxHeader, uint8_t *
qret = xQueueReceive(RAMN_GSUSB_PoolQueueHandle, &frameData, portMAX_DELAY);
if (qret == pdPASS)
{
- // Does not support CAN FD yet
- if(canRxHeader->FDFormat == FDCAN_FD_CAN)
- {
-#ifdef HANG_ON_ERRORS
- Error_Handler();
-#endif
- return RAMN_ERROR;
- }
-
frameData->can_id = canRxHeader->Identifier;
if (canRxHeader->IdType != FDCAN_STANDARD_ID) frameData->can_id |= CAN_EFF_FLAG;
if (canRxHeader->RxFrameType != FDCAN_DATA_FRAME) frameData->can_id |= CAN_RTR_FLAG;
@@ -49,7 +40,20 @@ RAMN_Result_t RAMN_GSUSB_ProcessRX(FDCAN_RxHeaderTypeDef *canRxHeader, uint8_t *
frameData->can_dlc = canRxHeader->DataLength;
frameData->timestamp_us = (xTaskGetTickCount() * (1000000 /*us per sec*/ / configTICK_RATE_HZ) );
- if (!(frameData->can_id & CAN_RTR_FLAG)) RAMN_memcpy(frameData->data, canRxData, frameData->can_dlc);
+#ifdef ENABLE_GSUSB_CANFD
+ if (canRxHeader->FDFormat == FDCAN_FD_CAN)
+ {
+ frameData->flags |= GS_CAN_FLAG_FD;
+ if (canRxHeader->BitRateSwitch == FDCAN_BRS_ON) frameData->flags |= GS_CAN_FLAG_BRS;
+ if (canRxHeader->ErrorStateIndicator == FDCAN_ESI_PASSIVE) frameData->flags |= GS_CAN_FLAG_ESI;
+ }
+#endif
+
+ if (!(frameData->can_id & CAN_RTR_FLAG))
+ {
+ uint8_t actual = FDCAN_ConvertToActual(frameData->can_dlc);
+ RAMN_memcpy(frameData->data, canRxData, actual);
+ }
// Send to task
qret = xQueueSendToBack(RAMN_GSUSB_SendQueueHandle, &frameData, CAN_QUEUE_TIMEOUT);
@@ -75,21 +79,25 @@ RAMN_Result_t RAMN_GSUSB_ProcessTX(FDCAN_TxHeaderTypeDef *canTxHeader, uint8_t *
qret = xQueueReceive(RAMN_GSUSB_PoolQueueHandle, &frameData, CAN_QUEUE_TIMEOUT);
if (qret == pdPASS)
{
- // Does not support CAN FD yet
- if(canTxHeader->FDFormat == FDCAN_FD_CAN)
- {
-#ifdef HANG_ON_ERRORS
- Error_Handler();
-#endif
- return RAMN_ERROR;
- }
-
frameData->can_id = canTxHeader->Identifier;
frameData->echo_id = 0xFFFFFFFF;
frameData->channel = 0;
+ frameData->flags = 0;
frameData->can_dlc = canTxHeader->DataLength;
frameData->timestamp_us = 0; // timestamps are ignored on send
- RAMN_memcpy(frameData->data, canRxData, frameData->can_dlc);
+
+#ifdef ENABLE_GSUSB_CANFD
+ if (canTxHeader->FDFormat == FDCAN_FD_CAN)
+ {
+ frameData->flags |= GS_CAN_FLAG_FD;
+ if (canTxHeader->BitRateSwitch == FDCAN_BRS_ON) frameData->flags |= GS_CAN_FLAG_BRS;
+ }
+#endif
+
+ {
+ uint8_t actual = FDCAN_ConvertToActual(frameData->can_dlc);
+ RAMN_memcpy(frameData->data, canRxData, actual);
+ }
// Send to task
qret = xQueueSendToBack(RAMN_GSUSB_SendQueueHandle, &frameData, CAN_QUEUE_TIMEOUT);
@@ -103,4 +111,82 @@ RAMN_Result_t RAMN_GSUSB_ProcessTX(FDCAN_TxHeaderTypeDef *canTxHeader, uint8_t *
return ret;
}
+RAMN_Result_t RAMN_GSUSB_SendErrorFrame(const FDCAN_ProtocolStatusTypeDef *protocolStatus, const FDCAN_ErrorCountersTypeDef *errorCount, uint32_t err)
+{
+ BaseType_t qret;
+ struct gs_host_frame *frameData;
+
+ // Get frame data pointer from pool queue (non-blocking)
+ qret = xQueueReceive(RAMN_GSUSB_PoolQueueHandle, &frameData, 0);
+ if (qret != pdPASS) return RAMN_ERROR;
+
+ frameData->echo_id = 0xFFFFFFFF;
+ frameData->can_id = CAN_ERR_FLAG;
+ frameData->can_dlc = CAN_ERR_DLC;
+ frameData->channel = 0;
+ frameData->flags = 0;
+ frameData->reserved = 0;
+ frameData->timestamp_us = (xTaskGetTickCount() * (1000000U / configTICK_RATE_HZ));
+ RAMN_memset(frameData->data, 0, CAN_ERR_DLC);
+
+ // Bus off
+ if (protocolStatus->BusOff != 0U)
+ {
+ frameData->can_id |= CAN_ERR_BUSOFF;
+ }
+
+ // Controller error state
+ if ((protocolStatus->ErrorPassive != 0U) || (protocolStatus->Warning != 0U))
+ {
+ frameData->can_id |= CAN_ERR_CRTL;
+ if (protocolStatus->Warning != 0U)
+ {
+ if (errorCount->TxErrorCnt >= 96U) frameData->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ if (errorCount->RxErrorCnt >= 96U) frameData->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ }
+ if (protocolStatus->ErrorPassive != 0U)
+ {
+ if (errorCount->TxErrorCnt >= 128U) frameData->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ if (errorCount->RxErrorPassive != 0U) frameData->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ }
+ }
+
+ // Protocol errors
+ if ((err & (HAL_FDCAN_ERROR_PROTOCOL_ARBT | HAL_FDCAN_ERROR_PROTOCOL_DATA)) != 0U)
+ {
+ uint32_t lec = protocolStatus->LastErrorCode;
+ frameData->can_id |= CAN_ERR_BUSERROR;
+ if ((lec != FDCAN_PROTOCOL_ERROR_NONE) && (lec != FDCAN_PROTOCOL_ERROR_NO_CHANGE))
+ {
+ frameData->can_id |= CAN_ERR_PROT;
+ switch (lec)
+ {
+ case FDCAN_PROTOCOL_ERROR_STUFF: frameData->data[2] = CAN_ERR_PROT_STUFF; break;
+ case FDCAN_PROTOCOL_ERROR_FORM: frameData->data[2] = CAN_ERR_PROT_FORM; break;
+ case FDCAN_PROTOCOL_ERROR_ACK: frameData->can_id |= CAN_ERR_ACK; break;
+ case FDCAN_PROTOCOL_ERROR_BIT1: frameData->data[2] = CAN_ERR_PROT_BIT1; break;
+ case FDCAN_PROTOCOL_ERROR_BIT0: frameData->data[2] = CAN_ERR_PROT_BIT0; break;
+ case FDCAN_PROTOCOL_ERROR_CRC: frameData->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break;
+ default: frameData->data[2] = CAN_ERR_PROT_UNSPEC; break;
+ }
+ }
+ }
+
+ // Only send if there is actual error info
+ if (frameData->can_id == CAN_ERR_FLAG)
+ {
+ xQueueSendToBack(RAMN_GSUSB_PoolQueueHandle, &frameData, portMAX_DELAY);
+ return RAMN_OK;
+ }
+
+ qret = xQueueSendToBack(RAMN_GSUSB_SendQueueHandle, &frameData, 0);
+ if (qret != pdPASS)
+ {
+ xQueueSendToBack(RAMN_GSUSB_PoolQueueHandle, &frameData, portMAX_DELAY);
+ return RAMN_ERROR;
+ }
+
+ return RAMN_OK;
+}
+
#endif
diff --git a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/CDC/usbd_cdc.c b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/CDC/usbd_cdc.c
index b934cfd4..fd0002c4 100644
--- a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/CDC/usbd_cdc.c
+++ b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/CDC/usbd_cdc.c
@@ -34,6 +34,7 @@
* Public functions *
*==============================================================================*/
+#ifdef ENABLE_CDC
static void cdc_init(USBD_HandleTypeDef *pdev, uint8_t index)
{
if(index == 0)
@@ -61,6 +62,7 @@ static void cdc_init(USBD_HandleTypeDef *pdev, uint8_t index)
((USBD_Composite_HandleTypeDef *)pdev->pClassData)->RxState[0] = 0U;
}
}
+#endif
/**
* @brief USBD_CDC_Init
diff --git a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_breq.c b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_breq.c
index fdde451c..5e92829a 100644
--- a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_breq.c
+++ b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_breq.c
@@ -83,6 +83,11 @@ void breq_set_mode(USBD_GS_CAN_HandleTypeDef *hcan, USBD_SetupReqTypedef *req)
}
else if (mode->mode == GS_CAN_MODE_START)
{
+#ifdef ENABLE_GSUSB_CANFD
+ hcan->enable_fdcan = (mode->flags & GS_CAN_MODE_FD) != 0;
+#else
+ hcan->enable_fdcan = 0;
+#endif
FDCAN_InitQueues(hcan);
hcan->timestamps_enabled = (mode->flags & GS_CAN_MODE_HW_TIMESTAMP) != 0;
hcan->pad_pkts_to_max_pkt_size = (mode->flags & GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE) != 0;
@@ -121,6 +126,7 @@ void breq_set_bittiming(USBD_GS_CAN_HandleTypeDef *hcan, USBD_SetupReqTypedef *r
*/
void breq_set_data_bittiming(USBD_GS_CAN_HandleTypeDef *hcan, USBD_SetupReqTypedef *req)
{
+#ifdef ENABLE_GSUSB_CANFD
struct gs_device_bittiming *timing;
timing = (struct gs_device_bittiming *)hcan->ep0_buf;
@@ -133,6 +139,7 @@ void breq_set_data_bittiming(USBD_GS_CAN_HandleTypeDef *hcan, USBD_SetupReqTyped
);
hcan->enable_fdcan = 1;
+#endif
}
#endif
diff --git a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_fdcan.c b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_fdcan.c
index a67433ee..c756f9f4 100644
--- a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_fdcan.c
+++ b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/gs_usb_fdcan.c
@@ -91,9 +91,9 @@ void FDCAN_DefaultInit(FDCAN_Instance *fdcan_data)
fdcan_data->bitrate_info.sjw = hfdcan1.Init.NominalSyncJumpWidth;
fdcan_data->data_bitrate_info.prescaler = hfdcan1.Init.DataPrescaler;
- fdcan_data->data_bitrate_info.phase_seg1 = hfdcan1.Init.DataPrescaler;
- fdcan_data->data_bitrate_info.phase_seg2 = hfdcan1.Init.DataPrescaler;
- fdcan_data->data_bitrate_info.sjw = hfdcan1.Init.DataPrescaler;
+ fdcan_data->data_bitrate_info.phase_seg1 = hfdcan1.Init.DataTimeSeg1;
+ fdcan_data->data_bitrate_info.phase_seg2 = hfdcan1.Init.DataTimeSeg2;
+ fdcan_data->data_bitrate_info.sjw = hfdcan1.Init.DataSyncJumpWidth;
}
/*!
@@ -214,11 +214,58 @@ void FDCAN_DeinitQueues(void)
* @brief get current queue max size
* @retval current queue max size
*/
-uint32_t FDCAN_GetQueueSize()
+uint32_t FDCAN_GetQueueSize(void)
{
return g_frames_list_len;
}
+/*!
+ * @brief get can dlc associated HAL macro value
+ * @param[in] n actual byte length
+ * @retval FDCAN_DLC_BYTES_xx(see HAL macro stm32l5xx_hal_fdcan.h)
+ */
+uint32_t FDCAN_ConvertToDLC(int n)
+{
+ if (n <= 0) return FDCAN_DLC_BYTES_0;
+ if (n <= 8) return (uint32_t)n;
+ if (n <= 12) return FDCAN_DLC_BYTES_12;
+ if (n <= 16) return FDCAN_DLC_BYTES_16;
+ if (n <= 20) return FDCAN_DLC_BYTES_20;
+ if (n <= 24) return FDCAN_DLC_BYTES_24;
+ if (n <= 32) return FDCAN_DLC_BYTES_32;
+ if (n <= 48) return FDCAN_DLC_BYTES_48;
+ return FDCAN_DLC_BYTES_64;
+}
+
+/*!
+ * @brief get actual byte length from HAL macro value (see HAL macro stm32l5xx_hal_fdcan.h)
+ * @param[in] dlc HAL macro value
+ * @retval actual byte length
+ */
+uint8_t FDCAN_ConvertToActual(uint32_t dlc)
+{
+ switch (dlc)
+ {
+ case FDCAN_DLC_BYTES_0: return 0;
+ case FDCAN_DLC_BYTES_1: return 1;
+ case FDCAN_DLC_BYTES_2: return 2;
+ case FDCAN_DLC_BYTES_3: return 3;
+ case FDCAN_DLC_BYTES_4: return 4;
+ case FDCAN_DLC_BYTES_5: return 5;
+ case FDCAN_DLC_BYTES_6: return 6;
+ case FDCAN_DLC_BYTES_7: return 7;
+ case FDCAN_DLC_BYTES_8: return 8;
+ case FDCAN_DLC_BYTES_12: return 12;
+ case FDCAN_DLC_BYTES_16: return 16;
+ case FDCAN_DLC_BYTES_20: return 20;
+ case FDCAN_DLC_BYTES_24: return 24;
+ case FDCAN_DLC_BYTES_32: return 32;
+ case FDCAN_DLC_BYTES_48: return 48;
+ case FDCAN_DLC_BYTES_64: return 64;
+ default: return 0;
+ }
+}
+
#endif
/* USER CODE END 1 */
diff --git a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.c b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.c
index f5a89d3a..f9f28b26 100644
--- a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.c
+++ b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.c
@@ -64,7 +64,12 @@ const struct gs_device_bt_const gscan_btconst = {
| GS_CAN_FEATURE_HW_TIMESTAMP
| GS_CAN_FEATURE_IDENTIFY
| GS_CAN_FEATURE_USER_ID
- | GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE,
+ | GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE
+#ifdef ENABLE_GSUSB_CANFD
+ | GS_CAN_FEATURE_FD
+ | GS_CAN_FEATURE_BT_CONST_EXT
+#endif
+ ,
48000000, // can timing base clock
1, // tseg1 min
16, // tseg1 max
@@ -76,6 +81,36 @@ const struct gs_device_bt_const gscan_btconst = {
1, // brp increment;
};
+#ifdef ENABLE_GSUSB_CANFD
+static const struct gs_device_bt_const_extended gscan_btconst_ext = {
+ GS_CAN_FEATURE_LISTEN_ONLY // supported features
+ | GS_CAN_FEATURE_LOOP_BACK
+ | GS_CAN_FEATURE_HW_TIMESTAMP
+ | GS_CAN_FEATURE_IDENTIFY
+ | GS_CAN_FEATURE_USER_ID
+ | GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE
+ | GS_CAN_FEATURE_FD
+ | GS_CAN_FEATURE_BT_CONST_EXT,
+ 48000000, // can timing base clock
+ 1, // tseg1 min
+ 16, // tseg1 max
+ 2, // tseg2 min
+ 8, // tseg2 max
+ 4, // sjw max
+ 1, // brp min
+ 512, // brp_max
+ 1, // brp increment
+ 1, // dtseg1 min
+ 16, // dtseg1 max
+ 2, // dtseg2 min
+ 8, // dtseg2 max
+ 4, // dsjw max
+ 1, // dbrp min
+ 512, // dbrp_max
+ 1, // dbrp increment
+};
+#endif
+
/* Microsoft Compatible ID Feature Descriptor */
static const uint8_t USBD_MS_COMP_ID_FEATURE_DESC[] = {
@@ -224,11 +259,15 @@ static uint8_t gsusb_config_request(USBD_HandleTypeDef *pdev, USBD_SetupReqTyped
USBD_CtlPrepareRx(pdev, hcan->ep0_buf, req->wLength);
break;
case GS_USB_BREQ_DATA_BITTIMING:
-
+#ifdef ENABLE_GSUSB_CANFD
hcan->enable_fdcan = 1;
hcan->last_setup_request = *req;
USBD_CtlPrepareRx(pdev, hcan->ep0_buf, req->wLength);
break;
+#else
+ ret = USBD_FAIL;
+ break;
+#endif
case GS_USB_BREQ_DEVICE_CONFIG:
RAMN_memcpy(hcan->ep0_buf, &gscan_dconf, sizeof(gscan_dconf));
USBD_CtlSendData(pdev, hcan->ep0_buf, req->wLength);
@@ -239,6 +278,14 @@ static uint8_t gsusb_config_request(USBD_HandleTypeDef *pdev, USBD_SetupReqTyped
USBD_CtlSendData(pdev, hcan->ep0_buf, req->wLength);
break;
+#ifdef ENABLE_GSUSB_CANFD
+ case GS_USB_BREQ_BT_CONST_EXT:
+ // Use USBD_DescBuf instead of ep0_buf: extended bt_const (72 bytes) exceeds ep0_buf (64 bytes)
+ RAMN_memcpy(USBD_DescBuf, &gscan_btconst_ext, sizeof(gscan_btconst_ext));
+ USBD_CtlSendData(pdev, USBD_DescBuf, MIN(sizeof(gscan_btconst_ext), req->wLength));
+ break;
+#endif
+
case GS_USB_BREQ_TIMESTAMP:
RAMN_memcpy(hcan->ep0_buf, &hcan->sof_timestamp_us, sizeof(hcan->sof_timestamp_us));
USBD_CtlSendData(pdev, hcan->ep0_buf, sizeof(hcan->sof_timestamp_us));
@@ -254,8 +301,8 @@ static uint8_t gsusb_config_request(USBD_HandleTypeDef *pdev, USBD_SetupReqTyped
static uint8_t gsusb_vendor_request(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
- uint8_t req_rcpt = req->bRequest & 0x1F;
- uint8_t req_type = (req->bRequest >> 5) & 0x03;
+ uint8_t req_rcpt = req->bmRequest & 0x1F;
+ uint8_t req_type = (req->bmRequest >> 5) & 0x03;
if (
(req_type == 0x01) // class request
@@ -279,7 +326,7 @@ USBD_StatusTypeDef USBD_GSUSB_Init(USBD_HandleTypeDef *pdev)
}
pdev->ep_in[GSUSB_IN_EP & 0xFU].is_used = 1U;
- USBD_LL_OpenEP(pdev, GSUSB_OUT_EP, USBD_EP_TYPE_BULK, CAN_DATA_MAX_PACKET_SIZE);
+ ret = USBD_LL_OpenEP(pdev, GSUSB_OUT_EP, USBD_EP_TYPE_BULK, CAN_DATA_MAX_PACKET_SIZE);
if(ret != USBD_OK)
{
return ret;
@@ -412,9 +459,20 @@ void GSUSB_MarshalFrame(USBD_HandleTypeDef *pdev, struct gs_host_frame *in, uint
out[ofs++] = in->channel;
out[ofs++] = in->flags;
out[ofs++] = in->reserved;
- RAMN_memcpy(&out[ofs], in->data, in->can_dlc); ofs += in->can_dlc;
- if(!hcan->enable_fdcan) RAMN_memset(&out[ofs], 0x00, 8 - in->can_dlc);
- else RAMN_memset(&out[ofs], 0x00, 64 - in->can_dlc);
+ {
+ uint8_t actual = FDCAN_ConvertToActual(in->can_dlc);
+ RAMN_memcpy(&out[ofs], in->data, actual);
+ if(!hcan->enable_fdcan)
+ {
+ RAMN_memset(&out[ofs + actual], 0x00, 8 - actual);
+ ofs += 8;
+ }
+ else
+ {
+ RAMN_memset(&out[ofs + actual], 0x00, 64 - actual);
+ ofs += 64;
+ }
+ }
if (hcan->timestamps_enabled)
{
@@ -438,9 +496,20 @@ void GSUSB_UnmarshalFrame(USBD_HandleTypeDef *pdev, uint8_t *in, uint16_t inlen,
out->channel = in[ofs++];
out->flags = in[ofs++];
out->reserved = in[ofs++];
- RAMN_memcpy(out->data, &in[ofs], out->can_dlc); ofs += out->can_dlc;
- if(!hcan->enable_fdcan) RAMN_memset(&out->data[ofs], 0x00, 8 - out->can_dlc);
- else RAMN_memset(&out->data[ofs], 0x00, 64 - out->can_dlc);
+ {
+ uint8_t actual = FDCAN_ConvertToActual(out->can_dlc);
+ RAMN_memcpy(out->data, &in[ofs], actual);
+ if(!hcan->enable_fdcan)
+ {
+ RAMN_memset(&out->data[actual], 0x00, 8 - actual);
+ ofs += 8;
+ }
+ else
+ {
+ RAMN_memset(&out->data[actual], 0x00, 64 - actual);
+ ofs += 64;
+ }
+ }
if (hcan->timestamps_enabled)
{
diff --git a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.h b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.h
index 6d1b1652..66bb9c16 100644
--- a/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.h
+++ b/firmware/RAMNV1/Middlewares/ST/STM32_USB_Device_Library/USBClass/Composite/gs_usb/usbd_gs_usb.h
@@ -46,6 +46,7 @@ THE SOFTWARE.
#define GS_CAN_MODE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_MODE_ONE_SHOT (1<<3)
#define GS_CAN_MODE_HW_TIMESTAMP (1<<4)
+#define GS_CAN_MODE_FD (1<<5)
#define GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE (1<<7)
@@ -58,8 +59,13 @@ THE SOFTWARE.
#define GS_CAN_FEATURE_USER_ID (1<<6)
#define GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE (1<<7)
+#define GS_CAN_FEATURE_FD (1<<8)
+#define GS_CAN_FEATURE_BT_CONST_EXT (1<<10)
#define GS_CAN_FLAG_OVERFLOW 1
+#define GS_CAN_FLAG_FD (1<<1)
+#define GS_CAN_FLAG_BRS (1<<2)
+#define GS_CAN_FLAG_ESI (1<<3)
#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
@@ -161,6 +167,8 @@ enum gs_usb_breq {
GS_USB_BREQ_TIMESTAMP,
GS_USB_BREQ_IDENTIFY,
GS_USB_BREQ_DATA_BITTIMING,
+ GS_USB_BREQ_GET_USER_ID, // not implemented, placeholder for correct enum numbering
+ GS_USB_BREQ_BT_CONST_EXT,
};
enum gs_can_mode {
@@ -229,6 +237,27 @@ struct __attribute__ ((__packed__)) gs_device_bt_const {
uint32_t brp_inc;
};
+struct __attribute__ ((__packed__)) gs_device_bt_const_extended {
+ uint32_t feature;
+ uint32_t fclk_can;
+ uint32_t tseg1_min;
+ uint32_t tseg1_max;
+ uint32_t tseg2_min;
+ uint32_t tseg2_max;
+ uint32_t sjw_max;
+ uint32_t brp_min;
+ uint32_t brp_max;
+ uint32_t brp_inc;
+ uint32_t dtseg1_min;
+ uint32_t dtseg1_max;
+ uint32_t dtseg2_min;
+ uint32_t dtseg2_max;
+ uint32_t dsjw_max;
+ uint32_t dbrp_min;
+ uint32_t dbrp_max;
+ uint32_t dbrp_inc;
+};
+
struct __attribute__ ((__packed__)) gs_host_frame {
uint32_t echo_id;
diff --git a/scripts/build/_build_ecu.sh b/scripts/build/_build_ecu.sh
index 837a0e76..494ff9cd 100755
--- a/scripts/build/_build_ecu.sh
+++ b/scripts/build/_build_ecu.sh
@@ -9,10 +9,15 @@ shift 2 2>/dev/null || shift $#
SKIP_IMPORT=false
BUILD_MODE="-cleanBuild"
-for arg in "$@"; do
- case "$arg" in
- --skip-import) SKIP_IMPORT=true ;;
- --no-clean) BUILD_MODE="-build" ;;
+EXTRA_DEFINES=""
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --skip-import) SKIP_IMPORT=true; shift ;;
+ --no-clean) BUILD_MODE="-build"; shift ;;
+ -D) EXTRA_DEFINES="${EXTRA_DEFINES} -D $2"; shift 2 ;;
+ -D*) EXTRA_DEFINES="${EXTRA_DEFINES} $1"; shift ;;
+ *) shift ;;
esac
done
@@ -32,4 +37,4 @@ fi
# when the Docker container's clock differs from the host that created the files.
find "${WORKSPACE}" -type f -exec touch -c {} + 2>/dev/null || true
-headless-build.sh -data /tmp/stm-workspace ${BUILD_MODE} ${PROJECT_NAME}/${PROJECT_CONF} -D ${ECU}
+headless-build.sh -data /tmp/stm-workspace ${BUILD_MODE} ${PROJECT_NAME}/${PROJECT_CONF} -D ${ECU} ${EXTRA_DEFINES}