valuemutex.h 3.7 KB

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