valuemutex.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #pragma once
  2. #include <cmsis_os2.h>
  3. #include <stdbool.h>
  4. #include "mutex.h"
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. /**
  9. * == ValueMutex ==
  10. * The most simple concept is ValueMutex.
  11. * It is wrapper around mutex and value pointer.
  12. * You can take and give mutex to work with value and read and write value.
  13. */
  14. typedef struct {
  15. void* value;
  16. size_t size;
  17. osMutexId_t mutex;
  18. } ValueMutex;
  19. /**
  20. * Creates ValueMutex.
  21. */
  22. bool init_mutex(ValueMutex* valuemutex, void* value, size_t size);
  23. /**
  24. * Free resources allocated by `init_mutex`.
  25. * This function doesn't free the memory occupied by `ValueMutex` itself.
  26. */
  27. bool delete_mutex(ValueMutex* valuemutex);
  28. /**
  29. * Call for work with data stored in mutex.
  30. * @return pointer to data if success, NULL otherwise.
  31. */
  32. void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout);
  33. /**
  34. * Helper: infinitly wait for mutex
  35. */
  36. static inline void* acquire_mutex_block(ValueMutex* valuemutex) {
  37. return acquire_mutex(valuemutex, osWaitForever);
  38. }
  39. /**
  40. * With statement for value mutex, acts as lambda
  41. * @param name a resource name, const char*
  42. * @param function_body a (){} lambda declaration,
  43. * executed within you parent function context.
  44. */
  45. #define with_value_mutex(value_mutex, function_body) \
  46. { \
  47. void* p = acquire_mutex_block(value_mutex); \
  48. furi_check(p); \
  49. ({ void __fn__ function_body __fn__; })(p); \
  50. release_mutex(value_mutex, p); \
  51. }
  52. /**
  53. * Release mutex after end of work with data.
  54. * Call `release_mutex` and pass ValueData instance and pointer to data.
  55. */
  56. bool release_mutex(ValueMutex* valuemutex, const void* value);
  57. /**
  58. * Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions.
  59. * Both functions return true in case of success, false otherwise.
  60. */
  61. bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout);
  62. bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout);
  63. inline static bool write_mutex_block(ValueMutex* valuemutex, void* data, size_t len) {
  64. return write_mutex(valuemutex, data, len, osWaitForever);
  65. }
  66. inline static bool read_mutex_block(ValueMutex* valuemutex, void* data, size_t len) {
  67. return read_mutex(valuemutex, data, len, osWaitForever);
  68. }
  69. #ifdef __cplusplus
  70. }
  71. #endif
  72. /*
  73. Usage example
  74. ```C
  75. // MANIFEST
  76. // name="example-provider-app"
  77. // stack=128
  78. void provider_app(void* _p) {
  79. // create record with mutex
  80. uint32_t example_value = 0;
  81. ValueMutex example_mutex;
  82. // call `init_mutex`.
  83. if(!init_mutex(&example_mutex, (void*)&example_value, sizeof(uint32_t))) {
  84. printf("critical error\n");
  85. flapp_exit(NULL);
  86. }
  87. furi_record_create("provider/example", (void*)&example_mutex);
  88. // we are ready to provide record to other apps
  89. flapp_ready();
  90. // get value and increment it
  91. while(1) {
  92. uint32_t* value = acquire_mutex(&example_mutex, OsWaitForever);
  93. if(value != NULL) {
  94. value++;
  95. }
  96. release_mutex(&example_mutex, value);
  97. osDelay(100);
  98. }
  99. }
  100. // MANIFEST
  101. // name="example-consumer-app"
  102. // stack=128
  103. // require="example-provider-app"
  104. void consumer_app(void* _p) {
  105. // this app run after flapp_ready call in all requirements app
  106. // open mutex value
  107. ValueMutex* counter_mutex = furi_record_open("provider/example");
  108. if(counter_mutex == NULL) {
  109. printf("critical error\n");
  110. flapp_exit(NULL);
  111. }
  112. // continously read value every 1s
  113. uint32_t counter;
  114. while(1) {
  115. if(read_mutex(counter_mutex, &counter, sizeof(counter), OsWaitForever)) {
  116. printf("counter value: %d\n", counter);
  117. }
  118. osDelay(1000);
  119. }
  120. }
  121. ```
  122. */