pcm_core.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. This file contains core routines for the PCM sub-system.
  3. pcm_data_play_task()
  4. Triggered by the driver ISR when further data for play mode is required.
  5. It handles the play buffer allocation and forwards control to 'data' and 'drained'
  6. callbacks in Lua land.
  7. pcm_data_rec_task() - n/a yet
  8. Triggered by the driver ISR when data for record mode is available.
  9. */
  10. #include "lauxlib.h"
  11. #include "task/task.h"
  12. #include "c_string.h"
  13. #include "c_stdlib.h"
  14. #include "pcm.h"
  15. static void dispatch_callback( lua_State *L, int self_ref, int cb_ref, int returns )
  16. {
  17. if (cb_ref != LUA_NOREF) {
  18. lua_rawgeti( L, LUA_REGISTRYINDEX, cb_ref );
  19. lua_rawgeti( L, LUA_REGISTRYINDEX, self_ref );
  20. lua_call( L, 1, returns );
  21. }
  22. }
  23. void pcm_data_vu_task( task_param_t param, uint8 prio )
  24. {
  25. cfg_t *cfg = (cfg_t *)param;
  26. lua_State *L = lua_getstate();
  27. if (cfg->cb_vu_ref != LUA_NOREF) {
  28. lua_rawgeti( L, LUA_REGISTRYINDEX, cfg->cb_vu_ref );
  29. lua_rawgeti( L, LUA_REGISTRYINDEX, cfg->self_ref );
  30. lua_pushnumber( L, (LUA_NUMBER)(cfg->vu_peak) );
  31. lua_call( L, 2, 0 );
  32. }
  33. }
  34. void pcm_data_play_task( task_param_t param, uint8 prio )
  35. {
  36. cfg_t *cfg = (cfg_t *)param;
  37. pcm_buf_t *buf = &(cfg->bufs[cfg->fbuf_idx]);
  38. size_t string_len;
  39. const char *data = NULL;
  40. uint8_t need_pop = FALSE;
  41. lua_State *L = lua_getstate();
  42. // retrieve new data from callback
  43. if ((cfg->isr_throttled >= 0) &&
  44. (cfg->cb_data_ref != LUA_NOREF)) {
  45. dispatch_callback( L, cfg->self_ref, cfg->cb_data_ref, 1 );
  46. need_pop = TRUE;
  47. if (lua_type( L, -1 ) == LUA_TSTRING) {
  48. data = lua_tolstring( L, -1, &string_len );
  49. if (string_len > buf->buf_size) {
  50. uint8_t *new_data = (uint8_t *) c_malloc( string_len );
  51. if (new_data) {
  52. if (buf->data) c_free( buf->data );
  53. buf->buf_size = string_len;
  54. buf->data = new_data;
  55. }
  56. }
  57. }
  58. }
  59. if (data) {
  60. size_t to_copy = string_len > buf->buf_size ? buf->buf_size : string_len;
  61. c_memcpy( buf->data, data, to_copy );
  62. buf->rpos = 0;
  63. buf->len = to_copy;
  64. buf->empty = FALSE;
  65. dbg_platform_gpio_write( PLATFORM_GPIO_HIGH );
  66. lua_pop( L, 1 );
  67. if (cfg->isr_throttled > 0) {
  68. uint8_t other_buf = cfg->fbuf_idx ^ 1;
  69. if (cfg->bufs[other_buf].empty) {
  70. // rerun data callback to get next buffer chunk
  71. dbg_platform_gpio_write( PLATFORM_GPIO_LOW );
  72. cfg->fbuf_idx = other_buf;
  73. pcm_data_play_task( param, 0 );
  74. }
  75. // unthrottle ISR
  76. cfg->isr_throttled = 0;
  77. }
  78. } else {
  79. dbg_platform_gpio_write( PLATFORM_GPIO_HIGH );
  80. if (need_pop) lua_pop( L, 1 );
  81. if (cfg->isr_throttled > 0) {
  82. // ISR found no further data
  83. // this was the last invocation of the reader task, fire drained cb
  84. cfg->isr_throttled = -1;
  85. dispatch_callback( L, cfg->self_ref, cfg->cb_drained_ref, 0 );
  86. }
  87. }
  88. }