dolphin_state.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "dolphin_state.h"
  2. #include <storage/storage.h>
  3. #include <furi.h>
  4. #include <math.h>
  5. #define DOLPHIN_STORE_KEY "/int/dolphin.state"
  6. #define DOLPHIN_STORE_HEADER_MAGIC 0xD0
  7. #define DOLPHIN_STORE_HEADER_VERSION 0x01
  8. #define DOLPHIN_LVL_THRESHOLD 20.0f
  9. typedef struct {
  10. uint8_t magic;
  11. uint8_t version;
  12. uint8_t checksum;
  13. uint8_t flags;
  14. uint32_t timestamp;
  15. } DolphinStoreHeader;
  16. typedef struct {
  17. uint32_t limit_ibutton;
  18. uint32_t limit_nfc;
  19. uint32_t limit_ir;
  20. uint32_t limit_rfid;
  21. uint32_t flags;
  22. uint32_t icounter;
  23. uint32_t butthurt;
  24. } DolphinStoreData;
  25. typedef struct {
  26. DolphinStoreHeader header;
  27. DolphinStoreData data;
  28. } DolphinStore;
  29. struct DolphinState {
  30. Storage* fs_api;
  31. DolphinStoreData data;
  32. bool dirty;
  33. };
  34. DolphinState* dolphin_state_alloc() {
  35. DolphinState* dolphin_state = furi_alloc(sizeof(DolphinState));
  36. dolphin_state->fs_api = furi_record_open("storage");
  37. return dolphin_state;
  38. }
  39. void dolphin_state_free(DolphinState* dolphin_state) {
  40. furi_record_close("storage");
  41. free(dolphin_state);
  42. }
  43. bool dolphin_state_save(DolphinState* dolphin_state) {
  44. if(!dolphin_state->dirty) {
  45. return true;
  46. }
  47. FURI_LOG_I("dolphin-state", "State is dirty, saving to \"%s\"", DOLPHIN_STORE_KEY);
  48. DolphinStore store;
  49. // Calculate checksum
  50. uint8_t* source = (uint8_t*)&dolphin_state->data;
  51. uint8_t checksum = 0;
  52. for(size_t i = 0; i < sizeof(DolphinStoreData); i++) {
  53. checksum += source[i];
  54. }
  55. // Set header
  56. store.header.magic = DOLPHIN_STORE_HEADER_MAGIC;
  57. store.header.version = DOLPHIN_STORE_HEADER_VERSION;
  58. store.header.checksum = checksum;
  59. store.header.flags = 0;
  60. store.header.timestamp = 0;
  61. // Set data
  62. store.data = dolphin_state->data;
  63. // Store
  64. File* file = storage_file_alloc(dolphin_state->fs_api);
  65. bool save_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_WRITE, FSOM_CREATE_ALWAYS);
  66. if(save_result) {
  67. uint16_t bytes_count = storage_file_write(file, &store, sizeof(DolphinStore));
  68. if(bytes_count != sizeof(DolphinStore)) {
  69. save_result = false;
  70. }
  71. }
  72. if(!save_result) {
  73. FURI_LOG_E(
  74. "dolphin-state",
  75. "Save failed. Storage returned: %s",
  76. storage_file_get_error_desc(file));
  77. }
  78. storage_file_close(file);
  79. storage_file_free(file);
  80. dolphin_state->dirty = !save_result;
  81. FURI_LOG_I("dolphin-state", "Saved");
  82. return save_result;
  83. }
  84. bool dolphin_state_load(DolphinState* dolphin_state) {
  85. DolphinStore store;
  86. // Read Dolphin State Store
  87. FURI_LOG_I("dolphin-state", "Loading state from \"%s\"", DOLPHIN_STORE_KEY);
  88. File* file = storage_file_alloc(dolphin_state->fs_api);
  89. bool load_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_READ, FSOM_OPEN_EXISTING);
  90. if(load_result) {
  91. uint16_t bytes_count = storage_file_read(file, &store, sizeof(DolphinStore));
  92. if(bytes_count != sizeof(DolphinStore)) {
  93. load_result = false;
  94. }
  95. }
  96. if(!load_result) {
  97. FURI_LOG_E(
  98. "dolphin-state",
  99. "Load failed. Storage returned: %s",
  100. storage_file_get_error_desc(file));
  101. } else {
  102. FURI_LOG_I("dolphin-state", "State loaded, verifying header");
  103. if(store.header.magic == DOLPHIN_STORE_HEADER_MAGIC &&
  104. store.header.version == DOLPHIN_STORE_HEADER_VERSION) {
  105. FURI_LOG_I(
  106. "dolphin-state",
  107. "Magic(%d) and Version(%d) match",
  108. store.header.magic,
  109. store.header.version);
  110. uint8_t checksum = 0;
  111. const uint8_t* source = (const uint8_t*)&store.data;
  112. for(size_t i = 0; i < sizeof(DolphinStoreData); i++) {
  113. checksum += source[i];
  114. }
  115. if(store.header.checksum == checksum) {
  116. FURI_LOG_I("dolphin-state", "Checksum(%d) match", store.header.checksum);
  117. dolphin_state->data = store.data;
  118. } else {
  119. FURI_LOG_E(
  120. "dolphin-state",
  121. "Checksum(%d != %d) mismatch",
  122. store.header.checksum,
  123. checksum);
  124. load_result = false;
  125. }
  126. } else {
  127. FURI_LOG_E(
  128. "dolphin-state",
  129. "Magic(%d != %d) and Version(%d != %d) mismatch",
  130. store.header.magic,
  131. DOLPHIN_STORE_HEADER_MAGIC,
  132. store.header.version,
  133. DOLPHIN_STORE_HEADER_VERSION);
  134. load_result = false;
  135. }
  136. }
  137. storage_file_close(file);
  138. storage_file_free(file);
  139. dolphin_state->dirty = !load_result;
  140. return load_result;
  141. }
  142. void dolphin_state_clear(DolphinState* dolphin_state) {
  143. memset(&dolphin_state->data, 0, sizeof(DolphinStoreData));
  144. }
  145. void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) {
  146. const DolphinDeedWeight* deed_weight = dolphin_deed_weight(deed);
  147. int32_t icounter = dolphin_state->data.icounter + deed_weight->icounter;
  148. if(icounter >= 0) {
  149. dolphin_state->data.icounter = icounter;
  150. }
  151. dolphin_state->dirty = true;
  152. }
  153. uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state) {
  154. return dolphin_state->data.icounter;
  155. }
  156. uint32_t dolphin_state_get_butthurt(DolphinState* dolphin_state) {
  157. return dolphin_state->data.butthurt;
  158. }
  159. uint32_t dolphin_state_get_level(DolphinState* dolphin_state) {
  160. return 0.5f +
  161. sqrtf(1.0f + 8.0f * ((float)dolphin_state->data.icounter / DOLPHIN_LVL_THRESHOLD)) /
  162. 2.0f;
  163. }
  164. uint32_t dolphin_state_xp_to_levelup(DolphinState* dolphin_state, uint32_t level, bool remaining) {
  165. return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) -
  166. (remaining ? dolphin_state->data.icounter : 0);
  167. }