~ruther/stm32h747i-disco-usb-image-viewer

f392640c73298948e44976684270613df08949db — Rutherther 3 months ago 241e200
feat: allow skipping queue for larger memory moves
3 files changed, 104 insertions(+), 22 deletions(-)

M firmware/include/usb_device_cdc.h
M firmware/src/main.c
M firmware/src/usb_device_cdc.c
M firmware/include/usb_device_cdc.h => firmware/include/usb_device_cdc.h +7 -2
@@ 96,7 96,8 @@ typedef struct {
} usb_cdc_call_management_functional_decriptor_t;
_Static_assert(sizeof(usb_cdc_call_management_functional_decriptor_t) == 5, "Size check");

typedef void (*cdc_receive_callback_t)(usb_device_t* device, uint16_t count);
typedef uint16_t (*cdc_receive_callback_t)(usb_device_t* device, uint8_t* data, uint16_t count);
typedef uint8_t* (*cdc_receive_location_callback_t)(usb_device_t* device, uint16_t count);

/* typedef enum { */
/*   CDC_STATE_NONE, */


@@ 116,7 117,8 @@ typedef struct {
  uint8_t functional_descriptors_count;
  usb_cdc_functional_descriptor_header_t** functional_descriptors;

  cdc_receive_callback_t callback;
  cdc_receive_callback_t receive_callback;
  cdc_receive_location_callback_t receive_location_callback;

  // Internal state.
  queue_t* rx_buffer;


@@ 143,6 145,9 @@ void cdc_acm_configure(usb_device_t *device, uint16_t rx_queue_size);
void cdc_data_set_receive_callback(usb_device_t *device,
                                   cdc_receive_callback_t callback);

void cdc_data_set_receive_location_callback(usb_device_t *device,
                                            cdc_receive_location_callback_t callback);

int32_t cdc_data_send_blocking(usb_device_t *device, uint8_t *data, uint16_t size);
int32_t cdc_data_send(usb_device_t* device, uint8_t* data, uint16_t size);


M firmware/src/main.c => firmware/src/main.c +74 -17
@@ 21,6 21,8 @@ pin_t wkup;
pin_t led1;
exti_t exti_wkup;

uint8_t* global_framebuffer;


void init_fmc(fmc_t *fmc)
{


@@ 239,7 241,7 @@ usb_device_t* init_usb()
  void *usb_dev = usb_device_init(USB_OTG_HS1, &USB_CLASS_CDC_ACM,
                                  0x1234, 0x1111, u"Frantisek Bohacek",
                                  u"Display", 1, NULL);
  cdc_acm_configure(usb_dev, 512 * 8); // 8 full packets maximum
  cdc_acm_configure(usb_dev, 512 * 8); // 8 full packets maximum size
  usb_device_setup(usb_dev);

  return usb_dev;


@@ 450,6 452,9 @@ pixel_rgb888_t* init_display(display_t* display, fmc_t* fmc)

void app_loop(usb_device_t* usb_dev, display_t* display, pixel_rgb888_t* framebuffer);

uint16_t cdc_receive_callback(usb_device_t* device, uint8_t* data, uint16_t count);
uint8_t* cdc_receive_location_callback(usb_device_t* device, uint16_t count);

void main()
{
  fmc_t fmc;


@@ 490,21 495,70 @@ void main()
  app_loop(usb_dev, &display, framebuffer);
}

bool image_command_handling = false;
bool image_command_handled = false;
uint8_t* framebuffer_ptr;
uint32_t read_count;
#define TOTAL_PIXEL_BYTES DISPLAY_WIDTH * DISPLAY_HEIGHT * 3

uint16_t cdc_receive_callback(usb_device_t *device, uint8_t *data,
                              uint16_t count) {

  if (!image_command_handling && data[0] == 'i') {
    framebuffer_ptr = global_framebuffer;
    read_count = 0;
    image_command_handling = true;

    for (uint16_t i = 0; i < count - 1; i++) {
      framebuffer_ptr[i] = data[i + 1];
    }
    framebuffer_ptr += count - 1;
    read_count += count - 1;
    return count;
  }

  return 0;
}

uint8_t* cdc_receive_location_callback(usb_device_t *device, uint16_t count) {
  if (!image_command_handling) {
    return NULL;
  }

  uint8_t* ptr = framebuffer_ptr;
  framebuffer_ptr += count;
  read_count += count;

  if (read_count >= TOTAL_PIXEL_BYTES) {
    image_command_handling = false;
    image_command_handled = true;
  }

  return framebuffer_ptr;
}

void app_loop(usb_device_t* usb_dev, display_t* display, pixel_rgb888_t* framebuffer)
{
  uint8_t data[1024];
  global_framebuffer = (uint8_t*)framebuffer;

  cdc_data_set_receive_callback(usb_dev, cdc_receive_callback);
  cdc_data_set_receive_location_callback(usb_dev, cdc_receive_location_callback);

  uint8_t data[16];

  bool handling_cmd = false;
  uint8_t cmd;
  uint32_t pos = 0;
  uint32_t max_size = 1;

  display_refresh(display);

  while (1) {
    uint16_t received = cdc_data_receive(usb_dev, data, max_size);
    uint16_t received = cdc_data_receive(usb_dev, data, 1);

    max_size = 1;
    if (image_command_handled) {
      display_refresh(display);
      image_command_handled = false;
    }

    if (received == 0) {
      continue;


@@ 563,24 617,27 @@ void app_loop(usb_device_t* usb_dev, display_t* display, pixel_rgb888_t* framebu
      }
      display_refresh(display);
      break;
    case 'i':
      handling_cmd = true;
      max_size = 1024;
    case 'i': {
      uint8_t* framebuffer_ptr = (uint8_t*)framebuffer;
      uint32_t bytes = DISPLAY_WIDTH * DISPLAY_HEIGHT * 3;

      for (uint16_t i = 0; i < received; i++) {
        if (pos > 0) {
          ((uint8_t *)framebuffer)[pos - 1] = data[i];
      pos = 0;

      while (pos < bytes) {
        uint32_t max = bytes - pos;
        if (max > 65535) {
          max = 65535;
        }
        pos++;
      }

      if (pos >= DISPLAY_WIDTH * DISPLAY_HEIGHT * 3) {
        handling_cmd = false;
        display_refresh(display);
        max_size = 1;
        uint16_t received = cdc_data_receive(usb_dev, framebuffer_ptr, max);
        pos += received;
        framebuffer_ptr += received;
      }

      display_refresh(display);
      break;
    }
    }
  }
}


M firmware/src/usb_device_cdc.c => firmware/src/usb_device_cdc.c +23 -3
@@ 585,14 585,28 @@ void usb_device_cdc_enable_endpoint_maybe(usb_device_t* device, usb_device_cdc_t

void usb_device_cdc_received_data_callback(usb_device_t *device, packet_info_t *packet) {
  usb_device_cdc_t* cdc = (usb_device_cdc_t*)device->class;
  uint8_t data[4*MAX_PACKET_SIZE];
  uint8_t data[2*MAX_PACKET_SIZE];
  uint16_t len = packet->byte_count;

  volatile uint32_t* fifo = &device->fifos[packet->endpoint_num].data[0];

  if (packet->packet_status == PACKET_OUT_DATA_PACKET_RCVD) {
    // TODO: could be optimized until pointer has to wrap
    if (cdc->receive_location_callback != NULL) {
      uint8_t* receive_location = cdc->receive_location_callback(device, len);
      if (receive_location != NULL) {
        usb_generic_read(receive_location, len, fifo);
        return;
      }
    }

    usb_generic_read(data, len, fifo);

    if (cdc->receive_callback != NULL) {
      uint16_t app_read = cdc->receive_callback(device, data, len);
      len -= app_read;
    }

    // TODO: could be optimized until pointer has to wrap
    if (queue_space(cdc->rx_buffer) < len) {
      cdc->lost_data += len - queue_space(cdc->rx_buffer);
    }


@@ 624,7 638,13 @@ void usb_device_cdc_nyet_callback(usb_device_t *device, uint8_t endpoint) {
void cdc_data_set_receive_callback(usb_device_t *device,
                                   cdc_receive_callback_t callback) {
  usb_device_cdc_t* cdc = (usb_device_cdc_t*)device->class;
  cdc->callback = callback;
  cdc->receive_callback = callback;
}

void cdc_data_set_receive_location_callback(usb_device_t *device,
                                   cdc_receive_location_callback_t callback) {
  usb_device_cdc_t* cdc = (usb_device_cdc_t*)device->class;
  cdc->receive_location_callback = callback;
}

int32_t cdc_data_send_blocking(usb_device_t *device, uint8_t *data, uint16_t size) {

Do not follow this link