api-hal-vcp.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include <api-hal-vcp.h>
  2. #include <usbd_cdc_if.h>
  3. #include <furi.h>
  4. #include <stream_buffer.h>
  5. #define API_HAL_VCP_RX_BUFFER_SIZE 600
  6. typedef struct {
  7. StreamBufferHandle_t rx_stream;
  8. osSemaphoreId_t tx_semaphore;
  9. volatile bool alive;
  10. volatile bool underrun;
  11. } ApiHalVcp;
  12. static ApiHalVcp* api_hal_vcp = NULL;
  13. static const uint8_t ascii_soh = 0x01;
  14. static const uint8_t ascii_eot = 0x04;
  15. void _api_hal_vcp_init();
  16. void _api_hal_vcp_deinit();
  17. void _api_hal_vcp_control_line(uint8_t state);
  18. void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size);
  19. void _api_hal_vcp_tx_complete(size_t size);
  20. void api_hal_vcp_init() {
  21. api_hal_vcp = furi_alloc(sizeof(ApiHalVcp));
  22. api_hal_vcp->rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1);
  23. api_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL);
  24. api_hal_vcp->alive = false;
  25. api_hal_vcp->underrun = false;
  26. }
  27. void _api_hal_vcp_init() {
  28. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  29. }
  30. void _api_hal_vcp_deinit() {
  31. api_hal_vcp->alive = false;
  32. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  33. }
  34. void _api_hal_vcp_control_line(uint8_t state) {
  35. // bit 0: DTR state, bit 1: RTS state
  36. // bool dtr = state & 0b01;
  37. bool rts = state & 0b10;
  38. if (rts) {
  39. api_hal_vcp->alive = true;
  40. _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
  41. } else {
  42. api_hal_vcp->alive = false;
  43. _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
  44. }
  45. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  46. }
  47. void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) {
  48. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  49. size_t ret = xStreamBufferSendFromISR(api_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken);
  50. if (ret != size) {
  51. api_hal_vcp->underrun = true;
  52. }
  53. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  54. }
  55. void _api_hal_vcp_tx_complete(size_t size) {
  56. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  57. }
  58. size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) {
  59. furi_assert(api_hal_vcp);
  60. return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY);
  61. }
  62. void api_hal_vcp_tx(const uint8_t* buffer, size_t size) {
  63. furi_assert(api_hal_vcp);
  64. while (size > 0 && api_hal_vcp->alive) {
  65. furi_check(osSemaphoreAcquire(api_hal_vcp->tx_semaphore, osWaitForever) == osOK);
  66. size_t batch_size = size;
  67. if (batch_size > APP_TX_DATA_SIZE) {
  68. batch_size = APP_TX_DATA_SIZE;
  69. }
  70. if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) {
  71. size -= batch_size;
  72. buffer += batch_size;
  73. } else {
  74. // Shouldn't be there
  75. osDelay(100);
  76. }
  77. }
  78. }