163 lines
5.3 KiB
C
163 lines
5.3 KiB
C
/*
|
||
* ld_device.c
|
||
*
|
||
* Created on: 22 авг. 2023 г.
|
||
* Author: malyarenko
|
||
*/
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
|
||
#include <sysctl.h>
|
||
|
||
#include <usb.h>
|
||
#include <usblib.h>
|
||
#include <usbdevice.h>
|
||
|
||
#include "../device_desc.h"
|
||
#include "ld_device_desc.h"
|
||
#include "ld_device.h"
|
||
|
||
static struct ld_device* ld_device_handler = NULL;
|
||
|
||
static const size_t MAX_PACKAGE_SIZE = 64;
|
||
|
||
static inline bool ld_device_cmd_init(struct ld_device* handler, const struct efc_usb_ld_config* config) {
|
||
if ((handler == NULL) || (config == NULL)) return false;
|
||
|
||
handler->cmd.rx_handle = config->cmd.rx_handle;
|
||
handler->cmd.rx_handle_param = config->cmd.rx_handle_param;
|
||
atomic_flag_test_and_set(&handler->cmd.rx_lock);
|
||
|
||
handler->cmd.tx_handle = config->cmd.tx_handle;
|
||
handler->cmd.tx_handle_param = config->cmd.tx_handle_param;
|
||
atomic_flag_clear(&handler->cmd.tx_lock);
|
||
|
||
// if (!ld_cmd_dma_init(handler)) return false;
|
||
return true;
|
||
}
|
||
|
||
bool ld_device_init(struct ld_device* device_handler, const struct efc_usb_ld_config* config) {
|
||
if ((device_handler == NULL) || (config == NULL)) return false;
|
||
// TODO: валидация
|
||
//if (!ld_device_validate_config(config)) return false;
|
||
|
||
device_handler->usb_base = USB_BASE;
|
||
device_handler->flags.connected = false;
|
||
device_handler->flags.cmd_active = true;
|
||
|
||
device_handler->reset_handle = config->reset_handle;
|
||
device_handler->reset_handle_param = config->reset_handle_param;
|
||
|
||
/* Командный интерфейс */
|
||
if (!ld_device_cmd_init(device_handler, config)) return false;
|
||
|
||
ld_device_handler = device_handler;
|
||
|
||
return true;
|
||
}
|
||
|
||
void ld_device_fini(struct ld_device* device_handler) {
|
||
if (device_handler == NULL) return;
|
||
|
||
USBDCDTerm(0);
|
||
|
||
device_handler->usb_base = 0;
|
||
|
||
ld_device_handler = NULL;
|
||
}
|
||
|
||
efc_usb_status_t efc_usb_ld_data_recv(uint8_t* buffer, size_t buffer_max_size, size_t* received_data_size, size_t* data_size_avail){
|
||
const uint32_t ep_id = IndexToUSBEP(EFC_USB_LD_EP1_O_ADDR);
|
||
|
||
/* Проверка параметров вызова */
|
||
if (NULL == buffer){
|
||
return EFC_USB_EARG;
|
||
}
|
||
|
||
/* Проверка состояния драйвера */
|
||
struct ld_device* const handler = ld_device_handler;
|
||
if ((handler == NULL) || !handler->flags.connected || !handler->flags.cmd_active){
|
||
return EFC_USB_ENOOP;
|
||
}
|
||
|
||
/* Проверка статуса EP */
|
||
const uint32_t ep_status = USBEndpointStatus(handler->usb_base, ep_id);
|
||
if ((ep_status & USB_DEV_RX_PKT_RDY) == 0){
|
||
return EFC_USB_EBUSY;
|
||
}
|
||
|
||
/* Защита от повторного чтения
|
||
const bool is_locked = atomic_flag_test_and_set(&handler->cmd.rx_lock);
|
||
if (is_locked){
|
||
return EFC_USB_EBUSY;
|
||
}
|
||
*/
|
||
USBEndpointDataGet(handler->usb_base, ep_id, buffer, &buffer_max_size);
|
||
|
||
*received_data_size = buffer_max_size;
|
||
*data_size_avail = USBEndpointDataAvail(handler->usb_base, ep_id);
|
||
|
||
if(0 == *data_size_avail){
|
||
USBDevEndpointDataAck(handler->usb_base, ep_id, true);
|
||
}
|
||
|
||
return EFC_USB_OK;
|
||
}
|
||
|
||
efc_usb_status_t efc_usb_ld_data_send(const uint8_t* header, size_t header_size, const uint8_t* data, size_t data_size){
|
||
const uint32_t ep_id = IndexToUSBEP(EFC_USB_LD_EP1_I_ADDR);
|
||
|
||
// Проверка параметров вызова
|
||
if (NULL == data && 0 < data_size){
|
||
return EFC_USB_EARG;
|
||
}
|
||
|
||
// Проверка состояния драйвера
|
||
struct ld_device* const handler = ld_device_handler;
|
||
if ((handler == NULL) || !handler->flags.connected || !handler->flags.cmd_active){
|
||
return EFC_USB_ENOOP;
|
||
}
|
||
|
||
// Проверка статуса EP
|
||
const uint32_t ep_status = USBEndpointStatus(handler->usb_base, ep_id);
|
||
if ((ep_status & USB_DEV_TX_TXPKTRDY) != 0){
|
||
return EFC_USB_EBUSY;
|
||
}
|
||
|
||
uint32_t status = USBEndpointDataPut(handler->usb_base, ep_id, header, header_size);
|
||
|
||
const uint16_t DATA_MAX_SIZE = MAX_PACKAGE_SIZE;
|
||
uint16_t sending_data_bytes = 0;
|
||
do{
|
||
// Если размер данных больше максимального размера USB буфера, то в конце нам нужно записать меньшее количество байт.
|
||
uint16_t send_bytes_count = data_size + header_size - sending_data_bytes < DATA_MAX_SIZE
|
||
? data_size + header_size - sending_data_bytes
|
||
: DATA_MAX_SIZE;
|
||
|
||
if(0 < send_bytes_count){
|
||
// Добавляем данные
|
||
const uint8_t* data_sent = data + sending_data_bytes;
|
||
status = USBEndpointDataPut(handler->usb_base, ep_id, data_sent, send_bytes_count - header_size);
|
||
}
|
||
|
||
status = USBEndpointDataSend(handler->usb_base, ep_id, USB_TRANS_IN);
|
||
uint32_t send_status = USBEndpointStatus(handler->usb_base, ep_id);
|
||
|
||
while((send_status & USB_DEV_TX_FIFO_NE) != 0){
|
||
send_status = USBEndpointStatus(handler->usb_base, ep_id);
|
||
}
|
||
|
||
if(0 != status){
|
||
return EFC_USB_ERR;
|
||
}
|
||
|
||
// Заголовок отправляется только один раз.
|
||
sending_data_bytes += send_bytes_count - header_size;
|
||
header_size = 0;
|
||
} while(sending_data_bytes < data_size);
|
||
|
||
return EFC_USB_OK;
|
||
}
|