main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2020 Reinhard Panhuber
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. */
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include "bsp/board.h"
  29. #include "tusb.h"
  30. //--------------------------------------------------------------------+
  31. // MACRO CONSTANT TYPEDEF PROTYPES
  32. //--------------------------------------------------------------------+
  33. /* Blink pattern
  34. * - 250 ms : device not mounted
  35. * - 1000 ms : device mounted
  36. * - 2500 ms : device is suspended
  37. */
  38. enum {
  39. BLINK_NOT_MOUNTED = 250,
  40. BLINK_MOUNTED = 1000,
  41. BLINK_SUSPENDED = 2500,
  42. };
  43. static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
  44. // Audio controls
  45. // Current states
  46. bool mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0
  47. uint16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0
  48. uint32_t sampFreq;
  49. uint8_t clkValid;
  50. // Range states
  51. audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_N_CHANNELS_TX+1]; // Volume range state
  52. audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
  53. // Audio test data
  54. uint16_t test_buffer_audio[CFG_TUD_AUDIO_TX_FIFO_SIZE/2];
  55. uint16_t startVal = 0;
  56. void led_blinking_task(void);
  57. void audio_task(void);
  58. /*------------- MAIN -------------*/
  59. int main(void)
  60. {
  61. board_init();
  62. tusb_init();
  63. // Init values
  64. sampFreq = 44100;
  65. clkValid = 1;
  66. sampleFreqRng.wNumSubRanges = 1;
  67. sampleFreqRng.subrange[0].bMin = 44100;
  68. sampleFreqRng.subrange[0].bMax = 44100;
  69. sampleFreqRng.subrange[0].bRes = 0;
  70. while (1)
  71. {
  72. tud_task(); // tinyusb device task
  73. led_blinking_task();
  74. audio_task();
  75. }
  76. return 0;
  77. }
  78. //--------------------------------------------------------------------+
  79. // Device callbacks
  80. //--------------------------------------------------------------------+
  81. // Invoked when device is mounted
  82. void tud_mount_cb(void)
  83. {
  84. blink_interval_ms = BLINK_MOUNTED;
  85. }
  86. // Invoked when device is unmounted
  87. void tud_umount_cb(void)
  88. {
  89. blink_interval_ms = BLINK_NOT_MOUNTED;
  90. }
  91. // Invoked when usb bus is suspended
  92. // remote_wakeup_en : if host allow us to perform remote wakeup
  93. // Within 7ms, device must draw an average of current less than 2.5 mA from bus
  94. void tud_suspend_cb(bool remote_wakeup_en)
  95. {
  96. (void) remote_wakeup_en;
  97. blink_interval_ms = BLINK_SUSPENDED;
  98. }
  99. // Invoked when usb bus is resumed
  100. void tud_resume_cb(void)
  101. {
  102. blink_interval_ms = BLINK_MOUNTED;
  103. }
  104. //--------------------------------------------------------------------+
  105. // AUDIO Task
  106. //--------------------------------------------------------------------+
  107. void audio_task(void)
  108. {
  109. // Yet to be filled - e.g. put meas data into TX FIFOs etc.
  110. asm("nop");
  111. }
  112. //--------------------------------------------------------------------+
  113. // Application Callback API Implementations
  114. //--------------------------------------------------------------------+
  115. // Invoked when audio class specific set request received for an EP
  116. bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
  117. {
  118. (void) rhport;
  119. (void) pBuff;
  120. // We do not support any set range requests here, only current value requests
  121. TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
  122. // Page 91 in UAC2 specification
  123. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  124. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  125. uint8_t ep = TU_U16_LOW(p_request->wIndex);
  126. (void) channelNum; (void) ctrlSel; (void) ep;
  127. return false; // Yet not implemented
  128. }
  129. // Invoked when audio class specific set request received for an interface
  130. bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
  131. {
  132. (void) rhport;
  133. (void) pBuff;
  134. // We do not support any set range requests here, only current value requests
  135. TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
  136. // Page 91 in UAC2 specification
  137. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  138. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  139. uint8_t itf = TU_U16_LOW(p_request->wIndex);
  140. (void) channelNum; (void) ctrlSel; (void) itf;
  141. return false; // Yet not implemented
  142. }
  143. // Invoked when audio class specific set request received for an entity
  144. bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
  145. {
  146. (void) rhport;
  147. // Page 91 in UAC2 specification
  148. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  149. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  150. uint8_t itf = TU_U16_LOW(p_request->wIndex);
  151. uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
  152. (void) itf;
  153. // We do not support any set range requests here, only current value requests
  154. TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
  155. // If request is for our feature unit
  156. if ( entityID == 2 )
  157. {
  158. switch ( ctrlSel )
  159. {
  160. case AUDIO_FU_CTRL_MUTE:
  161. // Request uses format layout 1
  162. TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
  163. mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
  164. TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
  165. return true;
  166. case AUDIO_FU_CTRL_VOLUME:
  167. // Request uses format layout 2
  168. TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
  169. volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur;
  170. TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
  171. return true;
  172. // Unknown/Unsupported control
  173. default:
  174. TU_BREAKPOINT();
  175. return false;
  176. }
  177. }
  178. return false; // Yet not implemented
  179. }
  180. // Invoked when audio class specific get request received for an EP
  181. bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
  182. {
  183. (void) rhport;
  184. // Page 91 in UAC2 specification
  185. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  186. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  187. uint8_t ep = TU_U16_LOW(p_request->wIndex);
  188. (void) channelNum; (void) ctrlSel; (void) ep;
  189. // return tud_control_xfer(rhport, p_request, &tmp, 1);
  190. return false; // Yet not implemented
  191. }
  192. // Invoked when audio class specific get request received for an interface
  193. bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
  194. {
  195. (void) rhport;
  196. // Page 91 in UAC2 specification
  197. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  198. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  199. uint8_t itf = TU_U16_LOW(p_request->wIndex);
  200. (void) channelNum; (void) ctrlSel; (void) itf;
  201. return false; // Yet not implemented
  202. }
  203. // Invoked when audio class specific get request received for an entity
  204. bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
  205. {
  206. (void) rhport;
  207. // Page 91 in UAC2 specification
  208. uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  209. uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  210. // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value
  211. uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
  212. // Input terminal (Microphone input)
  213. if (entityID == 1)
  214. {
  215. switch (ctrlSel)
  216. {
  217. case AUDIO_TE_CTRL_CONNECTOR:;
  218. // The terminal connector control only has a get request with only the CUR attribute.
  219. audio_desc_channel_cluster_t ret;
  220. // Those are dummy values for now
  221. ret.bNrChannels = 1;
  222. ret.bmChannelConfig = 0;
  223. ret.iChannelNames = 0;
  224. TU_LOG2(" Get terminal connector\r\n");
  225. return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
  226. // Unknown/Unsupported control selector
  227. default: TU_BREAKPOINT(); return false;
  228. }
  229. }
  230. // Feature unit
  231. if (entityID == 2)
  232. {
  233. switch (ctrlSel)
  234. {
  235. case AUDIO_FU_CTRL_MUTE:
  236. // Audio control mute cur parameter block consists of only one byte - we thus can send it right away
  237. // There does not exist a range parameter block for mute
  238. TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
  239. return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
  240. case AUDIO_FU_CTRL_VOLUME:
  241. switch (p_request->bRequest)
  242. {
  243. case AUDIO_CS_REQ_CUR:
  244. TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
  245. return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
  246. case AUDIO_CS_REQ_RANGE:
  247. TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
  248. // Copy values - only for testing - better is version below
  249. audio_control_range_2_n_t(1) ret;
  250. ret.wNumSubRanges = 1;
  251. ret.subrange[0].bMin = -90; // -90 dB
  252. ret.subrange[0].bMax = 90; // +90 dB
  253. ret.subrange[0].bRes = 1; // 1 dB steps
  254. return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
  255. // Unknown/Unsupported control
  256. default: TU_BREAKPOINT(); return false;
  257. }
  258. // Unknown/Unsupported control
  259. default: TU_BREAKPOINT(); return false;
  260. }
  261. }
  262. // Clock Source unit
  263. if (entityID == 4)
  264. {
  265. switch (ctrlSel)
  266. {
  267. case AUDIO_CS_CTRL_SAM_FREQ:
  268. // channelNum is always zero in this case
  269. switch (p_request->bRequest)
  270. {
  271. case AUDIO_CS_REQ_CUR:
  272. TU_LOG2(" Get Sample Freq.\r\n");
  273. return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
  274. case AUDIO_CS_REQ_RANGE:
  275. TU_LOG2(" Get Sample Freq. range\r\n");
  276. return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
  277. // Unknown/Unsupported control
  278. default: TU_BREAKPOINT(); return false;
  279. }
  280. case AUDIO_CS_CTRL_CLK_VALID:
  281. // Only cur attribute exists for this request
  282. TU_LOG2(" Get Sample Freq. valid\r\n");
  283. return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
  284. // Unknown/Unsupported control
  285. default: TU_BREAKPOINT(); return false;
  286. }
  287. }
  288. TU_LOG2(" Unsupported entity: %d\r\n", entityID);
  289. return false; // Yet not implemented
  290. }
  291. bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
  292. {
  293. (void) rhport;
  294. (void) itf;
  295. (void) ep_in;
  296. (void) cur_alt_setting;
  297. tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_TX_FIFO_SIZE);
  298. return true;
  299. }
  300. bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
  301. {
  302. (void) rhport;
  303. (void) n_bytes_copied;
  304. (void) itf;
  305. (void) ep_in;
  306. (void) cur_alt_setting;
  307. for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_SIZE/2; cnt++)
  308. {
  309. test_buffer_audio[cnt] = startVal++;
  310. }
  311. return true;
  312. }
  313. bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
  314. {
  315. (void) rhport;
  316. (void) p_request;
  317. startVal = 0;
  318. return true;
  319. }
  320. //--------------------------------------------------------------------+
  321. // BLINKING TASK
  322. //--------------------------------------------------------------------+
  323. void led_blinking_task(void)
  324. {
  325. static uint32_t start_ms = 0;
  326. static bool led_state = false;
  327. // Blink every interval ms
  328. if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
  329. start_ms += blink_interval_ms;
  330. board_led_write(led_state);
  331. led_state = 1 - led_state; // toggle
  332. }