stdglue.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "stdglue.h"
  2. #include "check.h"
  3. #include "memmgr.h"
  4. #include <FreeRTOS.h>
  5. #include <task.h>
  6. #include <furi_hal.h>
  7. #include <m-dict.h>
  8. DICT_DEF2(
  9. FuriStdglueCallbackDict,
  10. uint32_t,
  11. M_DEFAULT_OPLIST,
  12. FuriStdglueWriteCallback,
  13. M_PTR_OPLIST)
  14. typedef struct {
  15. osMutexId_t mutex;
  16. FuriStdglueCallbackDict_t thread_outputs;
  17. } FuriStdglue;
  18. static FuriStdglue* furi_stdglue = NULL;
  19. static ssize_t stdout_write(void* _cookie, const char* data, size_t size) {
  20. furi_assert(furi_stdglue);
  21. bool consumed = false;
  22. osKernelState_t state = osKernelGetState();
  23. FuriThreadId task_id = furi_thread_get_current_id();
  24. if(state == osKernelRunning && task_id &&
  25. osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK) {
  26. // We are in the thread context
  27. // Handle thread callbacks
  28. FuriStdglueWriteCallback* callback_ptr =
  29. FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)task_id);
  30. if(callback_ptr) {
  31. (*callback_ptr)(_cookie, data, size);
  32. consumed = true;
  33. }
  34. furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
  35. }
  36. // Flush
  37. if(data == 0) {
  38. /*
  39. * This means that we should flush internal buffers. Since we
  40. * don't we just return. (Remember, "handle" == -1 means that all
  41. * handles should be flushed.)
  42. */
  43. return 0;
  44. }
  45. // Debug uart
  46. if(!consumed) furi_hal_console_tx((const uint8_t*)data, size);
  47. // All data consumed
  48. return size;
  49. }
  50. void furi_stdglue_init() {
  51. furi_stdglue = malloc(sizeof(FuriStdglue));
  52. // Init outputs structures
  53. furi_stdglue->mutex = osMutexNew(NULL);
  54. furi_check(furi_stdglue->mutex);
  55. FuriStdglueCallbackDict_init(furi_stdglue->thread_outputs);
  56. // Prepare and set stdout descriptor
  57. FILE* fp = fopencookie(
  58. NULL,
  59. "w",
  60. (cookie_io_functions_t){
  61. .read = NULL,
  62. .write = stdout_write,
  63. .seek = NULL,
  64. .close = NULL,
  65. });
  66. setvbuf(fp, NULL, _IOLBF, 0);
  67. stdout = fp;
  68. }
  69. bool furi_stdglue_set_thread_stdout_callback(FuriStdglueWriteCallback callback) {
  70. furi_assert(furi_stdglue);
  71. FuriThreadId task_id = furi_thread_get_current_id();
  72. if(task_id) {
  73. furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK);
  74. if(callback) {
  75. FuriStdglueCallbackDict_set_at(
  76. furi_stdglue->thread_outputs, (uint32_t)task_id, callback);
  77. } else {
  78. FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)task_id);
  79. }
  80. furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
  81. return true;
  82. } else {
  83. return false;
  84. }
  85. }
  86. void __malloc_lock(struct _reent* REENT) {
  87. UNUSED(REENT);
  88. vTaskSuspendAll();
  89. }
  90. void __malloc_unlock(struct _reent* REENT) {
  91. UNUSED(REENT);
  92. xTaskResumeAll();
  93. }