#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
#include "usb_descriptors.h"
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
void led_blinking_task(void);
void video_task(void);
int main(void)
{
board_init();
tusb_init();
while (1)
{
tud_task(); led_blinking_task();
video_task();
}
return 0;
}
void tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
void tud_umount_cb(void)
{
blink_interval_ms = BLINK_NOT_MOUNTED;
}
void tud_suspend_cb(bool remote_wakeup_en)
{
(void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
void tud_resume_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
static unsigned frame_num = 0;
static unsigned tx_busy = 0;
static unsigned interval_ms = 1000 / FRAME_RATE;
#ifdef CFG_EXAMPLE_VIDEO_READONLY
#include "images.h"
#else
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
static void fill_color_bar(uint8_t *buffer, unsigned start_position)
{
static uint8_t const bar_color[8][4] = {
{ 235, 128, 235, 128},
{ 219, 16, 219, 138},
{ 188, 154, 188, 16},
{ 173, 42, 173, 26},
{ 78, 214, 78, 230},
{ 63, 102, 63, 240},
{ 32, 240, 32, 118},
{ 16, 128, 16, 128},
};
uint8_t *p;
uint8_t *end = &buffer[FRAME_WIDTH * 2];
unsigned idx = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2));
p = &buffer[idx * 4];
for (unsigned i = 0; i < 8; ++i) {
for (int j = 0; j < FRAME_WIDTH / (2 * 8); ++j) {
memcpy(p, &bar_color[i], 4);
p += 4;
if (end <= p) {
p = buffer;
}
}
}
p = &buffer[FRAME_WIDTH * 2];
for (unsigned i = 1; i < FRAME_HEIGHT; ++i) {
memcpy(p, buffer, FRAME_WIDTH * 2);
p += FRAME_WIDTH * 2;
}
}
#endif
void video_task(void)
{
static unsigned start_ms = 0;
static unsigned already_sent = 0;
if (!tud_video_n_streaming(0, 0)) {
already_sent = 0;
frame_num = 0;
return;
}
if (!already_sent) {
already_sent = 1;
start_ms = board_millis();
#ifdef CFG_EXAMPLE_VIDEO_READONLY
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t) &frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
#else
fill_color_bar(frame_buffer, frame_num);
tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);
#endif
}
unsigned cur = board_millis();
if (cur - start_ms < interval_ms) return; if (tx_busy) return;
start_ms += interval_ms;
#ifdef CFG_EXAMPLE_VIDEO_READONLY
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t) &frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
#else
fill_color_bar(frame_buffer, frame_num);
tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);
#endif
}
void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
{
(void)ctl_idx; (void)stm_idx;
tx_busy = 0;
++frame_num;
}
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
video_probe_and_commit_control_t const *parameters)
{
(void)ctl_idx; (void)stm_idx;
interval_ms = parameters->dwFrameInterval / 10000;
return VIDEO_ERROR_NONE;
}
void led_blinking_task(void)
{
static uint32_t start_ms = 0;
static bool led_state = false;
if ( board_millis() - start_ms < blink_interval_ms) return; start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; }