stdglue.c 4.2 KB

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