pcm_core.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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 <string.h>
  13. #include <stdlib.h>
  14. #include "pcm.h"
  15. static int 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. return luaL_pcallx( L, 1, returns );
  21. }
  22. return LUA_OK;
  23. }
  24. void pcm_data_vu( task_param_t param, uint8 prio )
  25. {
  26. cfg_t *cfg = (cfg_t *)param;
  27. lua_State *L = lua_getstate();
  28. if (cfg->cb_vu_ref != LUA_NOREF) {
  29. lua_rawgeti( L, LUA_REGISTRYINDEX, cfg->cb_vu_ref );
  30. lua_rawgeti( L, LUA_REGISTRYINDEX, cfg->self_ref );
  31. lua_pushnumber( L, (LUA_NUMBER)(cfg->vu_peak) );
  32. luaL_pcallx( L, 2, 0 );
  33. }
  34. }
  35. void pcm_data_play( task_param_t param, uint8 prio )
  36. {
  37. cfg_t *cfg = (cfg_t *)param;
  38. pcm_buf_t *buf = &(cfg->bufs[cfg->fbuf_idx]);
  39. size_t string_len;
  40. const char *data = NULL;
  41. uint8_t need_pop = FALSE;
  42. lua_State *L = lua_getstate();
  43. // retrieve new data from callback
  44. if ((cfg->isr_throttled >= 0) &&
  45. (cfg->cb_data_ref != LUA_NOREF)) {
  46. if(dispatch_callback( L, cfg->self_ref, cfg->cb_data_ref, 1 ) != LUA_OK)
  47. return;
  48. need_pop = TRUE;
  49. if (lua_type( L, -1 ) == LUA_TSTRING) {
  50. data = lua_tolstring( L, -1, &string_len );
  51. if (string_len > buf->buf_size) {
  52. uint8_t *new_data = (uint8_t *) malloc( string_len );
  53. if (new_data) {
  54. if (buf->data) free( buf->data );
  55. buf->buf_size = string_len;
  56. buf->data = new_data;
  57. }
  58. }
  59. }
  60. }
  61. if (data) {
  62. size_t to_copy = string_len > buf->buf_size ? buf->buf_size : string_len;
  63. memcpy( buf->data, data, to_copy );
  64. buf->rpos = 0;
  65. buf->len = to_copy;
  66. buf->empty = FALSE;
  67. dbg_platform_gpio_write( PLATFORM_GPIO_HIGH );
  68. lua_pop( L, 1 );
  69. if (cfg->isr_throttled > 0) {
  70. uint8_t other_buf = cfg->fbuf_idx ^ 1;
  71. if (cfg->bufs[other_buf].empty) {
  72. // rerun data callback to get next buffer chunk
  73. dbg_platform_gpio_write( PLATFORM_GPIO_LOW );
  74. cfg->fbuf_idx = other_buf;
  75. pcm_data_play( param, 0 );
  76. }
  77. // unthrottle ISR
  78. cfg->isr_throttled = 0;
  79. }
  80. } else {
  81. dbg_platform_gpio_write( PLATFORM_GPIO_HIGH );
  82. if (need_pop) lua_pop( L, 1 );
  83. if (cfg->isr_throttled > 0) {
  84. // ISR found no further data
  85. // this was the last invocation of the reader task, fire drained cb
  86. cfg->isr_throttled = -1;
  87. dispatch_callback( L, cfg->self_ref, cfg->cb_drained_ref, 0 );
  88. }
  89. }
  90. }