stdglue.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include "stdglue.h"
  2. #include "check.h"
  3. #include "memmgr.h"
  4. #include <main.h>
  5. #include <cmsis_os2.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <m-dict.h>
  9. extern UART_HandleTypeDef DEBUG_UART;
  10. DICT_DEF2(
  11. FuriStdglueCallbackDict,
  12. uint32_t,
  13. M_DEFAULT_OPLIST,
  14. FuriStdglueWriteCallback,
  15. M_PTR_OPLIST)
  16. typedef struct {
  17. osMutexId_t mutex;
  18. FuriStdglueCallbackDict_t global_outputs;
  19. FuriStdglueCallbackDict_t thread_outputs;
  20. } FuriStdglue;
  21. static FuriStdglue* furi_stdglue = NULL;
  22. static ssize_t stdout_write(void* _cookie, const char* data, size_t size) {
  23. furi_assert(furi_stdglue);
  24. osKernelState_t state = osKernelGetState();
  25. osThreadId_t thread_id = osThreadGetId();
  26. if(state == osKernelRunning && thread_id &&
  27. osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK) {
  28. // We are in the thread context
  29. // Handle global callbacks
  30. FuriStdglueCallbackDict_it_t it;
  31. for(FuriStdglueCallbackDict_it(it, furi_stdglue->global_outputs);
  32. !FuriStdglueCallbackDict_end_p(it);
  33. FuriStdglueCallbackDict_next(it)) {
  34. osThreadId_t it_thread = (osThreadId_t)FuriStdglueCallbackDict_ref(it)->key;
  35. FuriStdglueWriteCallback it_callback = FuriStdglueCallbackDict_ref(it)->value;
  36. if(thread_id != it_thread) {
  37. it_callback(_cookie, data, size);
  38. }
  39. }
  40. // Handle thread callbacks
  41. FuriStdglueWriteCallback* callback_ptr =
  42. FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)thread_id);
  43. if(callback_ptr) {
  44. (*callback_ptr)(_cookie, data, size);
  45. }
  46. furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
  47. }
  48. // Flush
  49. if(data == 0) {
  50. /*
  51. * This means that we should flush internal buffers. Since we
  52. * don't we just return. (Remember, "handle" == -1 means that all
  53. * handles should be flushed.)
  54. */
  55. return 0;
  56. }
  57. // Debug uart
  58. HAL_UART_Transmit(&DEBUG_UART, (uint8_t*)data, (uint16_t)size, HAL_MAX_DELAY);
  59. // All data consumed
  60. return size;
  61. }
  62. void furi_stdglue_init() {
  63. furi_stdglue = furi_alloc(sizeof(FuriStdglue));
  64. // Init outputs structures
  65. furi_stdglue->mutex = osMutexNew(NULL);
  66. furi_check(furi_stdglue->mutex);
  67. FuriStdglueCallbackDict_init(furi_stdglue->global_outputs);
  68. FuriStdglueCallbackDict_init(furi_stdglue->thread_outputs);
  69. // Prepare and set stdout descriptor
  70. FILE* fp = fopencookie(
  71. NULL,
  72. "w",
  73. (cookie_io_functions_t){
  74. .read = NULL,
  75. .write = stdout_write,
  76. .seek = NULL,
  77. .close = NULL,
  78. });
  79. setvbuf(fp, NULL, _IOLBF, 0);
  80. stdout = fp;
  81. }
  82. bool furi_stdglue_set_global_stdout_callback(FuriStdglueWriteCallback callback) {
  83. furi_assert(furi_stdglue);
  84. osThreadId_t thread_id = osThreadGetId();
  85. if(thread_id) {
  86. furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK);
  87. if(callback) {
  88. FuriStdglueCallbackDict_set_at(
  89. furi_stdglue->global_outputs, (uint32_t)thread_id, callback);
  90. } else {
  91. FuriStdglueCallbackDict_erase(furi_stdglue->global_outputs, (uint32_t)thread_id);
  92. }
  93. furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
  94. return true;
  95. } else {
  96. return false;
  97. }
  98. }
  99. bool furi_stdglue_set_thread_stdout_callback(FuriStdglueWriteCallback callback) {
  100. furi_assert(furi_stdglue);
  101. osThreadId_t thread_id = osThreadGetId();
  102. if(thread_id) {
  103. furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK);
  104. if(callback) {
  105. FuriStdglueCallbackDict_set_at(
  106. furi_stdglue->thread_outputs, (uint32_t)thread_id, callback);
  107. } else {
  108. FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)thread_id);
  109. }
  110. furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
  111. return true;
  112. } else {
  113. return false;
  114. }
  115. }