protocol_metakom.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include "protocol_metakom.h"
  4. #define METAKOM_DATA_SIZE sizeof(uint32_t)
  5. #define METAKOM_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond())
  6. #define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f)
  7. #define METAKOM_0_HI (METAKOM_PERIOD * 0.66f)
  8. #define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f)
  9. #define METAKOM_1_HI (METAKOM_PERIOD * 0.33f)
  10. #define METAKOM_PERIOD_SAMPLE_COUNT 10
  11. typedef enum {
  12. METAKOM_WAIT_PERIOD_SYNC,
  13. METAKOM_WAIT_START_BIT,
  14. METAKOM_WAIT_START_WORD,
  15. METAKOM_READ_WORD,
  16. METAKOM_READ_STOP_WORD,
  17. } MetakomState;
  18. typedef enum {
  19. METAKOM_BIT_WAIT_FRONT_HIGH,
  20. METAKOM_BIT_WAIT_FRONT_LOW,
  21. } MetakomBitState;
  22. typedef struct {
  23. // high + low period time
  24. uint32_t period_time;
  25. uint32_t low_time_storage;
  26. uint8_t period_sample_index;
  27. uint32_t period_sample_data[METAKOM_PERIOD_SAMPLE_COUNT];
  28. uint8_t tmp_data;
  29. uint8_t tmp_counter;
  30. uint8_t key_data_index;
  31. MetakomBitState bit_state;
  32. MetakomState state;
  33. } ProtocolMetakomDecoder;
  34. typedef struct {
  35. uint32_t index;
  36. } ProtocolMetakomEncoder;
  37. typedef struct {
  38. uint32_t data;
  39. ProtocolMetakomDecoder decoder;
  40. ProtocolMetakomEncoder encoder;
  41. } ProtocolMetakom;
  42. static ProtocolMetakom* protocol_metakom_alloc(void) {
  43. ProtocolMetakom* proto = malloc(sizeof(ProtocolMetakom));
  44. return (void*)proto;
  45. }
  46. static void protocol_metakom_free(ProtocolMetakom* proto) {
  47. free(proto);
  48. }
  49. static uint8_t* protocol_metakom_get_data(ProtocolMetakom* proto) {
  50. return (uint8_t*)&proto->data;
  51. }
  52. static void protocol_metakom_decoder_start(ProtocolMetakom* proto) {
  53. ProtocolMetakomDecoder* metakom = &proto->decoder;
  54. metakom->period_sample_index = 0;
  55. metakom->period_time = 0;
  56. metakom->tmp_counter = 0;
  57. metakom->tmp_data = 0;
  58. for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) {
  59. metakom->period_sample_data[i] = 0;
  60. };
  61. metakom->state = METAKOM_WAIT_PERIOD_SYNC;
  62. metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW;
  63. metakom->key_data_index = 0;
  64. metakom->low_time_storage = 0;
  65. proto->data = 0;
  66. }
  67. static bool metakom_parity_check(uint8_t data) {
  68. uint8_t ones_count = 0;
  69. bool result;
  70. for(uint8_t i = 0; i < 8; i++) {
  71. if((data >> i) & 0b00000001) {
  72. ones_count++;
  73. }
  74. }
  75. result = (ones_count % 2 == 0);
  76. return result;
  77. }
  78. static bool metakom_process_bit(
  79. ProtocolMetakomDecoder* metakom,
  80. bool polarity,
  81. uint32_t time,
  82. uint32_t* high_time,
  83. uint32_t* low_time) {
  84. bool result = false;
  85. switch(metakom->bit_state) {
  86. case METAKOM_BIT_WAIT_FRONT_LOW:
  87. if(polarity == false) {
  88. *low_time = metakom->low_time_storage;
  89. *high_time = time;
  90. result = true;
  91. metakom->bit_state = METAKOM_BIT_WAIT_FRONT_HIGH;
  92. }
  93. break;
  94. case METAKOM_BIT_WAIT_FRONT_HIGH:
  95. if(polarity == true) {
  96. metakom->low_time_storage = time;
  97. metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW;
  98. }
  99. break;
  100. }
  101. return result;
  102. }
  103. static bool protocol_metakom_decoder_feed(ProtocolMetakom* proto, bool level, uint32_t duration) {
  104. ProtocolMetakomDecoder* metakom = &proto->decoder;
  105. bool ready = false;
  106. uint32_t high_time = 0;
  107. uint32_t low_time = 0;
  108. switch(metakom->state) {
  109. case METAKOM_WAIT_PERIOD_SYNC:
  110. if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
  111. metakom->period_sample_data[metakom->period_sample_index] = high_time + low_time;
  112. metakom->period_sample_index++;
  113. if(metakom->period_sample_index == METAKOM_PERIOD_SAMPLE_COUNT) {
  114. for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) {
  115. metakom->period_time += metakom->period_sample_data[i];
  116. };
  117. metakom->period_time /= METAKOM_PERIOD_SAMPLE_COUNT;
  118. metakom->state = METAKOM_WAIT_START_BIT;
  119. }
  120. }
  121. break;
  122. case METAKOM_WAIT_START_BIT:
  123. if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
  124. metakom->tmp_counter++;
  125. if(high_time > metakom->period_time) {
  126. metakom->tmp_counter = 0;
  127. metakom->state = METAKOM_WAIT_START_WORD;
  128. }
  129. if(metakom->tmp_counter > 40) {
  130. protocol_metakom_decoder_start(proto);
  131. }
  132. }
  133. break;
  134. case METAKOM_WAIT_START_WORD:
  135. if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
  136. if(low_time < (metakom->period_time / 2)) {
  137. metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
  138. } else {
  139. metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
  140. }
  141. metakom->tmp_counter++;
  142. if(metakom->tmp_counter == 3) {
  143. if(metakom->tmp_data == 0b010) {
  144. metakom->tmp_counter = 0;
  145. metakom->tmp_data = 0;
  146. metakom->state = METAKOM_READ_WORD;
  147. } else {
  148. protocol_metakom_decoder_start(proto);
  149. }
  150. }
  151. }
  152. break;
  153. case METAKOM_READ_WORD:
  154. if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
  155. if(low_time < (metakom->period_time / 2)) {
  156. metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
  157. } else {
  158. metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
  159. }
  160. metakom->tmp_counter++;
  161. if(metakom->tmp_counter == 8) {
  162. if(metakom_parity_check(metakom->tmp_data)) {
  163. proto->data = (proto->data << 8) | metakom->tmp_data;
  164. metakom->key_data_index++;
  165. metakom->tmp_data = 0;
  166. metakom->tmp_counter = 0;
  167. if(metakom->key_data_index == 4) {
  168. // check for stop bit
  169. if(high_time > metakom->period_time) {
  170. metakom->state = METAKOM_READ_STOP_WORD;
  171. } else {
  172. protocol_metakom_decoder_start(proto);
  173. }
  174. }
  175. } else {
  176. protocol_metakom_decoder_start(proto);
  177. }
  178. }
  179. }
  180. break;
  181. case METAKOM_READ_STOP_WORD:
  182. if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
  183. if(low_time < (metakom->period_time / 2)) {
  184. metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
  185. } else {
  186. metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
  187. }
  188. metakom->tmp_counter++;
  189. if(metakom->tmp_counter == 3) {
  190. if(metakom->tmp_data == 0b010) {
  191. ready = true;
  192. } else {
  193. protocol_metakom_decoder_start(proto);
  194. }
  195. }
  196. }
  197. break;
  198. }
  199. return ready;
  200. }
  201. static bool protocol_metakom_encoder_start(ProtocolMetakom* proto) {
  202. proto->encoder.index = 0;
  203. return true;
  204. }
  205. static LevelDuration protocol_metakom_encoder_yield(ProtocolMetakom* proto) {
  206. LevelDuration result;
  207. if(proto->encoder.index == 0) {
  208. // sync bit
  209. result = level_duration_make(false, METAKOM_PERIOD);
  210. } else if(proto->encoder.index <= 6) {
  211. // start word (0b010)
  212. switch(proto->encoder.index) {
  213. case 1:
  214. result = level_duration_make(true, METAKOM_0_LOW); //-V1037
  215. break;
  216. case 2:
  217. result = level_duration_make(false, METAKOM_0_HI); //-V1037
  218. break;
  219. case 3:
  220. result = level_duration_make(true, METAKOM_1_LOW);
  221. break;
  222. case 4:
  223. result = level_duration_make(false, METAKOM_1_HI);
  224. break;
  225. case 5:
  226. result = level_duration_make(true, METAKOM_0_LOW);
  227. break;
  228. case 6:
  229. result = level_duration_make(false, METAKOM_0_HI);
  230. break;
  231. }
  232. } else {
  233. // data
  234. uint8_t data_start_index = proto->encoder.index - 7;
  235. bool clock_polarity = (data_start_index) % 2;
  236. uint8_t bit_index = (data_start_index) / 2;
  237. bool bit_value = (proto->data >> (32 - 1 - bit_index)) & 1;
  238. if(!clock_polarity) {
  239. if(bit_value) {
  240. result = level_duration_make(true, METAKOM_1_LOW);
  241. } else {
  242. result = level_duration_make(true, METAKOM_0_LOW);
  243. }
  244. } else {
  245. if(bit_value) {
  246. result = level_duration_make(false, METAKOM_1_HI);
  247. } else {
  248. result = level_duration_make(false, METAKOM_0_HI);
  249. }
  250. }
  251. }
  252. proto->encoder.index++;
  253. if(proto->encoder.index >= (1 + 3 * 2 + 32 * 2)) {
  254. proto->encoder.index = 0;
  255. }
  256. return result;
  257. }
  258. static void protocol_metakom_render_brief_data(ProtocolMetakom* proto, FuriString* result) {
  259. for(size_t i = 0; i < METAKOM_DATA_SIZE; ++i) {
  260. furi_string_cat_printf(result, "%02X ", ((uint8_t*)&proto->data)[i]);
  261. }
  262. }
  263. const ProtocolBase ibutton_protocol_misc_metakom = {
  264. .name = "Metakom",
  265. .manufacturer = "Metakom",
  266. .data_size = METAKOM_DATA_SIZE,
  267. .alloc = (ProtocolAlloc)protocol_metakom_alloc,
  268. .free = (ProtocolFree)protocol_metakom_free,
  269. .get_data = (ProtocolGetData)protocol_metakom_get_data,
  270. .decoder =
  271. {
  272. .start = (ProtocolDecoderStart)protocol_metakom_decoder_start,
  273. .feed = (ProtocolDecoderFeed)protocol_metakom_decoder_feed,
  274. },
  275. .encoder =
  276. {
  277. .start = (ProtocolEncoderStart)protocol_metakom_encoder_start,
  278. .yield = (ProtocolEncoderYield)protocol_metakom_encoder_yield,
  279. },
  280. .render_brief_data = (ProtocolRenderData)protocol_metakom_render_brief_data,
  281. };