1 /*
2  * Copyright (c) 2024 Titouan Christophe
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * @file
7  * @brief Sample application for USB MIDI 2.0 device class
8  */
9 
10 #include <sample_usbd.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/input/input.h>
15 #include <zephyr/usb/class/usbd_midi2.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(sample_usb_midi, LOG_LEVEL_INF);
19 
20 static const struct device *const midi = DEVICE_DT_GET(DT_NODELABEL(usb_midi));
21 
22 static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0});
23 
key_press(struct input_event * evt,void * user_data)24 static void key_press(struct input_event *evt, void *user_data)
25 {
26 	/* Only handle key presses in the 7bit MIDI range */
27 	if (evt->type != INPUT_EV_KEY || evt->code > 0x7f) {
28 		return;
29 	}
30 	uint8_t command = evt->value ? UMP_MIDI_NOTE_ON : UMP_MIDI_NOTE_OFF;
31 	uint8_t channel = 0;
32 	uint8_t note = evt->code;
33 	uint8_t velocity = 100;
34 
35 	struct midi_ump ump = UMP_MIDI1_CHANNEL_VOICE(0, command, channel,
36 						      note, velocity);
37 	usbd_midi_send(midi, ump);
38 }
39 INPUT_CALLBACK_DEFINE(NULL, key_press, NULL);
40 
on_midi_packet(const struct device * dev,const struct midi_ump ump)41 static void on_midi_packet(const struct device *dev, const struct midi_ump ump)
42 {
43 	LOG_INF("Received MIDI packet (MT=%X)", UMP_MT(ump));
44 
45 	/* Only send MIDI1 channel voice messages back to the host */
46 	if (UMP_MT(ump) == UMP_MT_MIDI1_CHANNEL_VOICE) {
47 		LOG_INF("Send back MIDI1 message %02X %02X %02X", UMP_MIDI_STATUS(ump),
48 			UMP_MIDI1_P1(ump), UMP_MIDI1_P2(ump));
49 		usbd_midi_send(dev, ump);
50 	}
51 }
52 
on_device_ready(const struct device * dev,const bool ready)53 static void on_device_ready(const struct device *dev, const bool ready)
54 {
55 	/* Light up the LED (if any) when USB-MIDI2.0 is enabled */
56 	if (led.port) {
57 		gpio_pin_set_dt(&led, ready);
58 	}
59 }
60 
61 static const struct usbd_midi_ops ops = {
62 	.rx_packet_cb = on_midi_packet,
63 	.ready_cb = on_device_ready,
64 };
65 
main(void)66 int main(void)
67 {
68 	struct usbd_context *sample_usbd;
69 
70 	if (!device_is_ready(midi)) {
71 		LOG_ERR("MIDI device not ready");
72 		return -1;
73 	}
74 
75 	if (led.port) {
76 		if (gpio_pin_configure_dt(&led, GPIO_OUTPUT)) {
77 			LOG_ERR("Unable to setup LED, not using it");
78 			memset(&led, 0, sizeof(led));
79 		}
80 	}
81 
82 	usbd_midi_set_ops(midi, &ops);
83 
84 	sample_usbd = sample_usbd_init_device(NULL);
85 	if (sample_usbd == NULL) {
86 		LOG_ERR("Failed to initialize USB device");
87 		return -1;
88 	}
89 
90 	if (usbd_enable(sample_usbd)) {
91 		LOG_ERR("Failed to enable device support");
92 		return -1;
93 	}
94 
95 	LOG_INF("USB device support enabled");
96 	return 0;
97 }
98