Skip to content

USB demo

This tutorial is based on a USB testing demo using gint, fxlink bulk USB, and JustUI.

The demo combines USB helpers with a touch interface:

#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <justui/jbutton.h>
#include <justui/jlabel.h>
#include <justui/jlayout.h>
#include <justui/jscene.h>
#include <justui/jwidget.h>

usb-ff-bulk.h provides the fxlink-style bulk interface.

The USB stack needs a list of interfaces:

static usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL};

The final NULL marks the end of the list.

The demo sends short text and optionally the VRAM:

static usb_fxlink_header_t header_text;
static usb_fxlink_header_t header_image;
static char const *short_text = "Hello JustUI!";
static char read_buffer[256];

Before sending data, headers are filled with usb_fxlink_fill_header().

The UI has a tab with status text and buttons:

jlabel *usb_status = jlabel_create("USB Status: Idle", tab4);
jbutton *btn_u1 = jbutton_create("Open", col1);
jbutton *btn_u3 = jbutton_create("Close", col1);
jbutton *btn_u6 = jbutton_create("WA Text", col1);

The button labels are short so they fit on the ClassPad screen.

When a button is triggered, call the matching USB function and update the status label:

else if (e.source == btn_u1) {
int rc = usb_open(interfaces, GINT_CALL_NULL);
sprintf(status_buf, "usb_open: %d", rc);
jlabel_set_text(usb_status, status_buf);
}

The demo includes both async and sync writes, commits, and reads.

Use usb_close() when you are done testing, and keep an Exit button in the UI so the app can leave the test screen.

This is the demo source.

#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <justui/jbutton.h>
#include <justui/jlabel.h>
#include <justui/jlayout.h>
#include <justui/jscene.h>
#include <justui/jwidget.h>
#include <stdio.h>
#include <string.h>
static usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL};
static usb_fxlink_header_t header_text;
static usb_fxlink_header_t header_image;
static char const *short_text = "Hello JustUI!";
static char read_buffer[256];
int main(void)
{
usb_fxlink_fill_header(&header_text, "justui", "text", strlen(short_text));
int vram_size = DWIDTH * DHEIGHT * sizeof(color_t);
usb_fxlink_fill_header(&header_image, "justui", "image", vram_size);
jscene *scene = jscene_create_fullscreen(NULL);
jlayout_set_vbox(scene)->spacing = 0;
jwidget *stack = jwidget_create(scene);
jlayout_set_stack(stack);
jwidget_set_stretch(stack, 1, 1, false);
jwidget *tab1 = jwidget_create(stack);
jlayout_set_vbox(tab1)->spacing = 10;
jwidget_set_padding(tab1, 15, 15, 15, 15);
jlabel_create("Welcome to JustUI ClassPad!", tab1);
jlabel_create("This is Tab 1.", tab1);
jlabel_create("Select bottom buttons to navigate.", tab1);
jwidget *tab2 = jwidget_create(stack);
jlayout_set_vbox(tab2)->spacing = 15;
jwidget_set_padding(tab2, 15, 15, 15, 15);
jlabel_create("Features (Tab 2)", tab2);
jbutton *btn_action = jbutton_create("Click Me!", tab2);
jwidget_set_padding(btn_action, 15, 20, 15, 20);
jlabel *t2_status = jlabel_create("Button not clicked yet.", tab2);
jwidget *tab3 = jwidget_create(stack);
jlayout_set_vbox(tab3)->spacing = 10;
jwidget_set_padding(tab3, 15, 15, 15, 15);
jlabel_create("About JustUI (Tab 3)", tab3);
jlabel_create("JustUI elegantly handles layout.", tab3);
jlabel_create("It automatically supports touch!", tab3);
jlabel_create("Stack layouts make tabs easy.", tab3);
jwidget *tab4 = jwidget_create(stack);
jlayout_set_vbox(tab4)->spacing = 2;
jwidget_set_padding(tab4, 5, 5, 5, 5);
jlabel *usb_status = jlabel_create("USB Status: Idle", tab4);
jwidget *usb_cols = jwidget_create(tab4);
jlayout_set_hbox(usb_cols)->spacing = 10;
jwidget_set_stretch(usb_cols, 1, 1, false);
jwidget *col1 = jwidget_create(usb_cols);
jlayout_set_vbox(col1)->spacing = 5;
jwidget_set_stretch(col1, 1, 1, false);
jwidget *col2 = jwidget_create(usb_cols);
jlayout_set_vbox(col2)->spacing = 5;
jwidget_set_stretch(col2, 1, 1, false);
void style_usb_btn(jbutton *b) {
jwidget_set_padding(b, 12, 5, 12, 5);
}
jbutton *btn_u1 = jbutton_create("Open", col1); style_usb_btn(btn_u1);
jbutton *btn_u2 = jbutton_create("Open Wait", col1); style_usb_btn(btn_u2);
jbutton *btn_u3 = jbutton_create("Close", col1); style_usb_btn(btn_u3);
jbutton *btn_u4 = jbutton_create("WA TxtHead", col1); style_usb_btn(btn_u4);
jbutton *btn_u5 = jbutton_create("WA ImgHead", col1); style_usb_btn(btn_u5);
jbutton *btn_u6 = jbutton_create("WA Text", col1); style_usb_btn(btn_u6);
jbutton *btn_u7 = jbutton_create("WA VRAM", col1); style_usb_btn(btn_u7);
jbutton *btn_u14 = jbutton_create("Read Async", col1); style_usb_btn(btn_u14);
jbutton *btn_u8 = jbutton_create("WS TxtHead", col2); style_usb_btn(btn_u8);
jbutton *btn_u9 = jbutton_create("WS ImgHead", col2); style_usb_btn(btn_u9);
jbutton *btn_u10 = jbutton_create("WS Text", col2); style_usb_btn(btn_u10);
jbutton *btn_u11 = jbutton_create("WS VRAM", col2); style_usb_btn(btn_u11);
jbutton *btn_u12 = jbutton_create("Commit A", col2); style_usb_btn(btn_u12);
jbutton *btn_u13 = jbutton_create("Commit S", col2); style_usb_btn(btn_u13);
jbutton *btn_u15 = jbutton_create("Read Sync", col2); style_usb_btn(btn_u15);
jwidget *buttons = jwidget_create(scene);
jlayout_set_hbox(buttons)->spacing = 6;
jwidget_set_stretch(buttons, 1, 0, false);
jwidget_set_padding(buttons, 8, 8, 8, 8);
jbutton *b_tab1 = jbutton_create("Tab 1", buttons);
jbutton *b_tab2 = jbutton_create("Tab 2", buttons);
jbutton *b_tab3 = jbutton_create("Tab 3", buttons);
jbutton *b_tab4 = jbutton_create("USB", buttons);
jwidget *spacer = jwidget_create(buttons);
jwidget_set_stretch(spacer, 1, 0, false);
jbutton *b_exit = jbutton_create("Exit", buttons);
jscene_show_and_focus(scene, tab1);
jbutton_set_disabled(b_tab1, true);
int action_count = 0;
bool running = true;
static char status_buf[64];
while (running)
{
jevent e = jscene_run(scene);
if (e.type == JSCENE_PAINT)
{
dclear(C_WHITE);
jscene_render(scene);
dupdate();
}
else if (e.type == JBUTTON_TRIGGERED)
{
if (e.source == b_exit) {
running = false;
}
else if (e.source == b_tab1) {
jscene_show_and_focus(scene, tab1);
jbutton_set_disabled(b_tab1, true);
jbutton_set_disabled(b_tab2, false);
jbutton_set_disabled(b_tab3, false);
jbutton_set_disabled(b_tab4, false);
}
else if (e.source == b_tab2) {
jscene_show_and_focus(scene, tab2);
jbutton_set_disabled(b_tab1, false);
jbutton_set_disabled(b_tab2, true);
jbutton_set_disabled(b_tab3, false);
jbutton_set_disabled(b_tab4, false);
}
else if (e.source == b_tab3) {
jscene_show_and_focus(scene, tab3);
jbutton_set_disabled(b_tab1, false);
jbutton_set_disabled(b_tab2, false);
jbutton_set_disabled(b_tab3, true);
jbutton_set_disabled(b_tab4, false);
}
else if (e.source == b_tab4) {
jscene_show_and_focus(scene, tab4);
jbutton_set_disabled(b_tab1, false);
jbutton_set_disabled(b_tab2, false);
jbutton_set_disabled(b_tab3, false);
jbutton_set_disabled(b_tab4, true);
}
else if (e.source == btn_action) {
action_count++;
static char buf[64];
sprintf(buf, "Clicked %d times!", action_count);
jlabel_set_text(t2_status, buf);
}
else if (e.source == btn_u1) {
int rc = usb_open(interfaces, GINT_CALL_NULL);
sprintf(status_buf, "usb_open: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u2) {
usb_open_wait();
jlabel_set_text(usb_status, "usb_open_wait: done");
}
else if (e.source == btn_u3) {
usb_close();
jlabel_set_text(usb_status, "usb_close: done");
}
else if (e.source == btn_u4) {
int rc = usb_write_async(usb_ff_bulk_output(), &header_text, sizeof(header_text), false, GINT_CALL_NULL);
sprintf(status_buf, "WA TxtHead: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u5) {
int rc = usb_write_async(usb_ff_bulk_output(), &header_image, sizeof(header_image), false, GINT_CALL_NULL);
sprintf(status_buf, "WA ImgHead: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u6) {
int rc = usb_write_async(usb_ff_bulk_output(), short_text, strlen(short_text), false, GINT_CALL_NULL);
sprintf(status_buf, "WA Text: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u7) {
int rc = usb_write_async(usb_ff_bulk_output(), gint_vram, vram_size, false, GINT_CALL_NULL);
sprintf(status_buf, "WA VRAM: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u8) {
int rc = usb_write_sync(usb_ff_bulk_output(), &header_text, sizeof(header_text), false);
sprintf(status_buf, "WS TxtHead: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u9) {
int rc = usb_write_sync(usb_ff_bulk_output(), &header_image, sizeof(header_image), false);
sprintf(status_buf, "WS ImgHead: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u10) {
int rc = usb_write_sync(usb_ff_bulk_output(), short_text, strlen(short_text), false);
sprintf(status_buf, "WS Text: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u11) {
int rc = usb_write_sync(usb_ff_bulk_output(), gint_vram, vram_size, false);
sprintf(status_buf, "WS VRAM: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u12) {
int rc = usb_commit_async(usb_ff_bulk_output(), GINT_CALL_NULL);
sprintf(status_buf, "Commit A: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u13) {
usb_commit_sync(usb_ff_bulk_output());
jlabel_set_text(usb_status, "Commit S: done");
}
else if (e.source == btn_u14) {
int rc = usb_read_async(usb_ff_bulk_input(), read_buffer, 64, USB_READ_IGNORE_ZEROS, NULL, NULL, GINT_CALL_NULL);
sprintf(status_buf, "Read A started: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
else if (e.source == btn_u15) {
memset(read_buffer, 0, 64);
int rc = usb_read_sync(usb_ff_bulk_input(), read_buffer, 64, false);
sprintf(status_buf, "Read Sync: %d", rc);
jlabel_set_text(usb_status, status_buf);
}
}
else if (e.type == JWIDGET_KEY && e.key.type == KEYEV_DOWN)
{
if (e.key.key == KEY_EXIT || e.key.key == KEY_CLEAR) {
running = false;
}
}
}
jwidget_destroy(scene);
return 1;
}