2023-02-09 08:14 AM
Hi. I am using a STM32F756-EVAL board for USB_FS transmission.
messageprocesser.c
#include "messageprocesser.h"
#include "main.h"
#include "usbd_cdc_if.h"
#include <string.h>
#include "string.h"
//Sample cmd: TOARM_FIRMV_00000000_4C\r\n
#define MESSAGE_LENGTH 25
#define DESTINATION_LENGTH 5
#define COMMAND_CHAR 6 //See SW Protocol or sample cmd
#define COMMAND_LENGTH 5
#define DATA_CHAR 12
#define DATA_LENGTH 8
#define CHECKSUM_CHAR 21
#define CHECKSUM_LENGTH 2
enum cmd {FIRMV, VALCN, RQSPC, INVAL};
enum cmd cmd_Converter(unsigned char* inputCmd){//Converts the input cmd from uint8_t to an enum.
switch (inputCmd[0]){ //Currently we are using a switch-case. If we get too many commands (+100), switch to something else.
case 'F':
if (memcmp(inputCmd, "FIRMV", COMMAND_LENGTH) == 0) return FIRMV;
else return INVAL;
break;
case 'R':
if (memcmp(inputCmd, "RQSPC", COMMAND_LENGTH) == 0) return RQSPC;
else return INVAL;
break;
case 'V':
if (memcmp(inputCmd, "VALCN", COMMAND_LENGTH) == 0) return VALCN;
else return INVAL;
break;
default:
return INVAL;
}
}
void process_Message(uint8_t* message, uint16_t Len){
//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
unsigned char inputCmd[COMMAND_LENGTH]; //These are not null-terminated strings.
unsigned char inputData[DATA_LENGTH]; //These are just an array of chars.
memcpy((char*) inputCmd, (const char*)message + COMMAND_CHAR, COMMAND_LENGTH);
memcpy((char*) inputData, (const char*)message + DATA_CHAR, DATA_LENGTH);
enum cmd enumCmd = cmd_Converter(inputCmd);
void (*cmd_Function_Pointer[])(unsigned char* inputData) = {FIRMV_F, VALCN_F, RQSPC_F, INVAL_F}; //Is this even needed?
(*cmd_Function_Pointer[enumCmd])(inputData); //What is going on here?
}
//void seperate_Cmd_Data(uint8_t* message, uint16_t Len, **extCmd, **extData){ //Delete by 16/02/23.
//
//}
void FIRMV_F(unsigned char *inputData){
//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
unsigned char outputCmd[COMMAND_LENGTH];
unsigned char outputData[DATA_LENGTH];
memcpy(outputCmd, "FIRMV", COMMAND_LENGTH);
memcpy(outputData, "01050A00", DATA_LENGTH);
unsigned char *outputMessage;
build_Outgoing_Message(outputCmd, outputData, &outputMessage);
CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
free(outputMessage);
}
void VALCN_F(unsigned char *inputData){
//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
unsigned char outputCmd[COMMAND_LENGTH];
unsigned char outputData[DATA_LENGTH];
memcpy(outputCmd, "VALCN", COMMAND_LENGTH);
memcpy(outputData, "00000000", DATA_LENGTH);
unsigned char *outputMessage;
build_Outgoing_Message(outputCmd, outputData, &outputMessage);
CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
free(outputMessage);
}
void RQSPC_F(unsigned char *inputData){
int messageCount = 2;
unsigned char outputMessage[MESSAGE_LENGTH * messageCount];
//Load all elements into 2D array
unsigned char outputCmd [messageCount][COMMAND_LENGTH];
unsigned char outputData [messageCount][DATA_LENGTH];
memcpy(outputCmd[0], "GVP01", COMMAND_LENGTH);
memcpy(outputData[0], "00000000", DATA_LENGTH); //Data is serial number
memcpy(outputCmd[1], "GVP02", COMMAND_LENGTH);
memcpy(outputData[1], "30082022", DATA_LENGTH); //Data is date of lid calibration
unsigned char *outputMessageBuf;
build_Outgoing_Message(outputCmd[0], outputData[0], &outputMessageBuf);
//Function that combines all strings
memcpy(outputMessage, outputMessageBuf, MESSAGE_LENGTH);
memset(outputMessageBuf, '\0', MESSAGE_LENGTH);
build_Outgoing_Message(outputCmd[1], outputData[1], &outputMessageBuf);
//Function that combines all strings
memcpy(outputMessage + MESSAGE_LENGTH * 1, outputMessageBuf, MESSAGE_LENGTH);
CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH * messageCount);
free(outputMessage);
}
void INVAL_F(unsigned char *inputData){
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
unsigned char outputCmd[COMMAND_LENGTH];
unsigned char outputData[DATA_LENGTH];
memcpy(outputCmd, "REEEE", COMMAND_LENGTH);
memcpy(outputData, "99999999", DATA_LENGTH);
unsigned char *outputMessage;
build_Outgoing_Message(outputCmd, outputData, &outputMessage);
CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
free(outputMessage);
}
int checkSum_Generator(uint8_t* message){
int checkSum = 0;
for (int i = 0; i < CHECKSUM_CHAR; i++){ //Gives the cs of TOARM_COMND_DATA0000_.
checkSum ^= message[i];
}
return checkSum;
}
void checkSum_Hex_Converter(int checkSum_Dec){
//char outputCheckSumHex[2] = {'0', '0'};
}
void build_Outgoing_Message(uint8_t* cmd, uint8_t* data, uint8_t **message){
unsigned char *outputMessage = malloc(MESSAGE_LENGTH);
//uint8_t outputMessage[MESSAGE_LENGTH] = "TOWST_";
unsigned char outputDestination[5] = {'T', 'O', 'W', 'S', 'T'};
memcpy((char*) outputMessage, (const char*) outputDestination, DESTINATION_LENGTH); //Need to split the macros.
outputMessage[COMMAND_CHAR - 1] = '_';
memcpy((char*) outputMessage + COMMAND_CHAR, (const char*) cmd, COMMAND_LENGTH);
outputMessage[COMMAND_CHAR + COMMAND_LENGTH] = '_';
memcpy((char*) outputMessage + DATA_CHAR, (const char*) data, DATA_LENGTH);
outputMessage[DATA_CHAR + DATA_LENGTH] = '_';
//Deal with checksum
int outputCheckSum = checkSum_Generator(outputMessage);
char outputCheckSumHex[2] = {'0', '0'};
itoa (outputCheckSum, outputCheckSumHex, 16);
if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
outputCheckSumHex[1] = outputCheckSumHex[0];
outputCheckSumHex[0] = '0';
}
outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
memcpy((char*) outputMessage + CHECKSUM_CHAR, (const char*) outputCheckSumHex, CHECKSUM_LENGTH);
outputMessage[23] = '\r';
outputMessage[24] = '\n';
//Return char array outside
*message = outputMessage;
}
usbd_cdc_if.c
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
memset (buffer, '\0', 64); // clear the buffer
uint8_t len = (uint8_t)*Len; //Converts Len as uint32_t to len as uint8_t
memcpy(buffer, Buf, len); // copy the data to the buffer
memset(Buf, '\0', len); // clear the Buf also
process_Message(buffer, len);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* @brief CDC_Transmit_FS
* Data to send over USB IN endpoint are sent over CDC interface
* through this function.
* @note
*
*
* @param Buf: Buffer of data to be sent
* @param Len: Number of data to be sent (in bytes)
* @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; //hcdc is given the data of pClassData. What is pClassData?
if (hcdc->TxState != 0){ //If TxState in hcdc is not 0, return USBD_BUSY.
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); //SetTxBuffer sets the size of the buffer, as well as the buffer itself.
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); //USBD_CDC_TransmitPacket(&hUsbDeviceFS) transmits
/* USER CODE END 7 */
return result;
}
On my output I am facing a partially truncated results. I am expecting an output like:
TOWST_REEEE_99999999_27
But I am getting:
T_REEEE_99999999_27
I have used the debugger to determine that the message is "TOWST_REEEE_99999999_27\r\n" at the outputMessage at line 115, as well as line 36, usbd_cdc_if.c
However, it is "T_REEEE_99999999_27\r\n" at stm32f7xx_ll_usb.c, USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint8_t *pSrc = src;
uint32_t count32b;
uint32_t i;
if (dma == 0U)
{
count32b = ((uint32_t)len + 3U) / 4U;
for (i = 0U; i < count32b; i++)
{
USBx_DFIFO((uint32_t)ch_ep_num) = __UNALIGNED_UINT32_READ(pSrc); //What is USBx_DFIFO((uint32_t)ch_ep_num)?
pSrc++;
pSrc++;
pSrc++;
pSrc++;
}
}
return HAL_OK;
}
This issue only started showing up after I implemented line 134/135 in messageprocesser.c
unsigned char outputDestination[5] = {'T', 'O', 'W', 'S', 'T'};
memcpy((char*) outputMessage, (const char*) outputDestination, DESTINATION_LENGTH); //Need to split the macros.
Please let me know if more information is required to solve this issue.
2023-02-09 08:39 AM
I don't use Cube, but the buffer, from which you are transmitting, should probably be persistent. Transmission does not happen at the moment when you call CDC_Transmit_FS, but later, when host sends IN token, when data are actually copied into the FIFO, so those data must be unchanged until that moment.
Citing from CDC chapter of UM1734:
6.5.2 Data IN transfer management (from device to host)
The data transfer is managed periodically depending on host request (the device specifies
the interval between packet requests). For this reason, a circular static buffer is used for
storing data sent by the device terminal (i.e. USART in the case of Virtual COM Port
terminal).
JW