new iButton app (#328)
* rename old ibutton app to ibutton-test * more renames * updated onewire library compilation condition * add submenu_clean subroutine * add index for submenu callback * c++ guard for gui modules * add released ibutton app * fix the position of the submenu window if there are too few items * iButton app basis * negative icon position info * fix submenu_clean subroutine * add ibutton app to applications makefile * add onewire key read routine to read mode * rename mode to scene * rename files and folder (mode to scene) * rename ibutton view to view manager * rename get_view to get_view_manager * cpp guards * key read, store and notify features * syntax fix * make iButtonScene functions pure virtual * fix syntax * add text store, add new scene (crc error) * not a key scene * syntax fix * read success scene * app, switching to the previous scene with the number of scenes to be skipped * scene whith menu when key is readed * fix font height calculation, fix offsets * add key write scene * view_dispatcher_remove_view subroutine * generic pause/resume os methods * fix furi_assert usage * key store, worker * fix pointer comparsion * saved keys, saved key action scenes * key delete/confirm delete scenes and routines * use last input subsystem changes * fix syntax * fix new model usage in submenu * fix includes * use vibro pin * use stored key name if valid * emulate scene * random name generator * name and save readed key scenes, new icon * fix icon position * fix text scene exit * fix naming, fix text placement, new info scene * state-driven cyfral decoder * better cyfral decoder * better cyfral decoder * one wire: search command set * metakom decoder * more key types * add next scene to error scenes * universal key reader * use new key reader * syntax fix * warning fix * byte input module template * new thread and insomnia api usage * New element: slightly rounded frame * Use elements_slightly_rounded_frame in text input * Gui test app: byte input usage * Byte input module: data drawing and selection * Byte input: comment currently unused fns * remove volatile qualifier * base byte input realisation * App gui test: remove internal fns visibility * Byne input, final version * test install gcc-arm-none-eabi-10-2020-q4-major * test install gcc-arm-none-eabi-10-2020-q4-major * App iButton: byte input view managment * App iButton: add key manually scenes * App iButton: rename scenes, add popup timeout * App iButton: use new scenes, new fn for rollback to specific prevous scene. * App iButton: remove byte input view on app exit * App iButton: edit key scene * Module byte input: reduce swintch value to uint8_t * Module byte input: switch from switch-case to if, unfortunately we need compile-time constants to use with switch * Icons: new small arrows * Module byte input: new arrangement of elements * OneWire slave lib: fix deattach sequence * App iButton: pulse sequencer * App iButton: add more keys to store * App iButton: split key worker to separate read/write/emulate entitys * App iButton: use new read/emulate entities * fix callback pointer saving * App iButton: use KeyReader error enum instead of KeyWorker error list handling * App iButton: do not use insomnia fns in pulse sequencer * App iButton: use KeyReader error enum in read scene * OneWire slave lib: more READ ROM command variants, call callback only if positive result * GPIO resources: add external gpio * App SD/NFC: removed application * App iButton-test: update to new light api * App iButton: update to new light-api * Outdated apps: add api-light-usage * Gpio: update SD card CS pin settings * API-power: added fns to disable/enable external 3v3 dc-dc * API-gpio: separated SD card detect routines * Resources: removed sd cs pin * SD card: low level init now resets card power supply * App SD-filesystem: use new card detect fns * SD card: fix low level init headers * SD card: more realilable low level init, power reset, exit from command read cycle conditionally * App SD-filesystem: led notifiers, init cycling * SD card: backport to F4 * Api PWM: add c++ guards * App iButton: yellow blink in emulate scene, vibro on * App iButton: one wire keys command set * App iButton: successful write scene * App iButton: key writer * App iButton: syntax fix * App iButton: notify write success * App iButton: fix double scene change * SD card: handle eject in init sequence * SD card: api to set level on detect gpio * SPI: api to set state on bus pins * SD card: set low state on bus pins while power reset * File select: init * File select: fix input consuming * SD Card: fixed dir open api error * SD-card: replace strncpy by strlcpy. Fix buffer overflow error. * API HAL OS: replace CMP based ticks with ARR based one, hard reset lptimer on reconfiguration. * GUI: More stack size for (temporary, wee need to implement sd card api in separate thread) * GUI: File select module. * App iButton-test: remove obsolete app Co-authored-by: rusdacent <rusdacentx0x08@gmail.com> Co-authored-by: coreglitch <mail@s3f.ru> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							
								
								
									
										193
									
								
								applications/ibutton/helpers/cyfral-decoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								applications/ibutton/helpers/cyfral-decoder.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| #include "cyfral-decoder.h" | ||||
| #include <furi.h> | ||||
|  | ||||
| void CyfralDecoder::reset_state() { | ||||
|     state = State::WAIT_START_NIBBLE; | ||||
|     bit_state = BitState::WAIT_FRONT_LOW; | ||||
|  | ||||
|     period_time = 0; | ||||
|     bit_index = 0; | ||||
|     ready = false; | ||||
|     index = 0; | ||||
|  | ||||
|     key_data = 0; | ||||
|     readed_nibble = 0; | ||||
|     data_valid = true; | ||||
| } | ||||
|  | ||||
| bool CyfralDecoder::nibble_valid(uint8_t data) { | ||||
|     uint8_t data_value = data & 0x0F; | ||||
|  | ||||
|     switch(data_value) { | ||||
|     case 0b1110: | ||||
|     case 0b1101: | ||||
|     case 0b1011: | ||||
|     case 0b0111: | ||||
|         return true; | ||||
|         break; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| CyfralDecoder::CyfralDecoder() { | ||||
|     reset_state(); | ||||
|     max_period = 0; | ||||
| } | ||||
|  | ||||
| void CyfralDecoder::process_front(bool polarity, uint32_t time) { | ||||
|     bool readed; | ||||
|     bool value; | ||||
|  | ||||
|     if(max_period == 0) { | ||||
|         max_period = 230 * (SystemCoreClock / 1000000.0f); | ||||
|     } | ||||
|  | ||||
|     if(ready) return; | ||||
|  | ||||
|     switch(state) { | ||||
|     case State::WAIT_START_NIBBLE: | ||||
|         // wait for start word | ||||
|         if(process_bit(polarity, time, &readed, &value)) { | ||||
|             if(readed) { | ||||
|                 readed_nibble = ((readed_nibble << 1) | value) & 0x0F; | ||||
|                 if(readed_nibble == 0b0001) { | ||||
|                     readed_nibble = 0; | ||||
|                     state = State::READ_NIBBLE; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             reset_state(); | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|     case State::READ_NIBBLE: | ||||
|         // read nibbles | ||||
|         if(process_bit(polarity, time, &readed, &value)) { | ||||
|             if(readed) { | ||||
|                 readed_nibble = (readed_nibble << 1) | value; | ||||
|  | ||||
|                 bit_index++; | ||||
|  | ||||
|                 //convert every nibble to 2-bit index | ||||
|                 if(bit_index == 4) { | ||||
|                     switch(readed_nibble) { | ||||
|                     case 0b1110: | ||||
|                         key_data = (key_data << 2) | 0b11; | ||||
|                         break; | ||||
|                     case 0b1101: | ||||
|                         key_data = (key_data << 2) | 0b10; | ||||
|                         break; | ||||
|                     case 0b1011: | ||||
|                         key_data = (key_data << 2) | 0b01; | ||||
|                         break; | ||||
|                     case 0b0111: | ||||
|                         key_data = (key_data << 2) | 0b00; | ||||
|                         break; | ||||
|                     default: | ||||
|                         data_valid = false; | ||||
|                         break; | ||||
|                     } | ||||
|  | ||||
|                     readed_nibble = 0; | ||||
|                     bit_index = 0; | ||||
|                     index++; | ||||
|                 } | ||||
|  | ||||
|                 // succefully read 8 nibbles | ||||
|                 if(index == 8) { | ||||
|                     state = State::READ_STOP_NIBBLE; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             reset_state(); | ||||
|         } | ||||
|         break; | ||||
|     case State::READ_STOP_NIBBLE: | ||||
|         // read stop nibble | ||||
|         if(process_bit(polarity, time, &readed, &value)) { | ||||
|             if(readed) { | ||||
|                 readed_nibble = ((readed_nibble << 1) | value) & 0x0F; | ||||
|                 bit_index++; | ||||
|  | ||||
|                 switch(bit_index) { | ||||
|                 case 0: | ||||
|                 case 1: | ||||
|                 case 2: | ||||
|                 case 3: | ||||
|                     break; | ||||
|                 case 4: | ||||
|                     if(readed_nibble == 0b0001) { | ||||
|                         // validate data | ||||
|                         if(data_valid) { | ||||
|                             ready = true; | ||||
|                         } else { | ||||
|                             reset_state(); | ||||
|                         } | ||||
|                     } else { | ||||
|                         reset_state(); | ||||
|                     } | ||||
|                     break; | ||||
|                 default: | ||||
|                     reset_state(); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             reset_state(); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool CyfralDecoder::process_bit(bool polarity, uint32_t time, bool* readed, bool* readed_value) { | ||||
|     bool result = true; | ||||
|     *readed = false; | ||||
|  | ||||
|     // bit start from low | ||||
|     switch(bit_state) { | ||||
|     case BitState::WAIT_FRONT_LOW: | ||||
|         if(polarity == true) { | ||||
|             period_time += time; | ||||
|  | ||||
|             *readed = true; | ||||
|             if(period_time <= max_period) { | ||||
|                 if((period_time / 2) > time) { | ||||
|                     *readed_value = false; | ||||
|                 } else { | ||||
|                     *readed_value = true; | ||||
|                 } | ||||
|             } else { | ||||
|                 result = false; | ||||
|             } | ||||
|  | ||||
|             bit_state = BitState::WAIT_FRONT_HIGH; | ||||
|         } else { | ||||
|             result = false; | ||||
|         } | ||||
|         break; | ||||
|     case BitState::WAIT_FRONT_HIGH: | ||||
|         if(polarity == false) { | ||||
|             period_time = time; | ||||
|             bit_state = BitState::WAIT_FRONT_LOW; | ||||
|         } else { | ||||
|             result = false; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool CyfralDecoder::read(uint8_t* _data, uint8_t data_size) { | ||||
|     furi_check(data_size <= 2); | ||||
|     bool result = false; | ||||
|  | ||||
|     if(ready) { | ||||
|         memcpy(_data, &key_data, data_size); | ||||
|         reset_state(); | ||||
|         result = true; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										55
									
								
								applications/ibutton/helpers/cyfral-decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								applications/ibutton/helpers/cyfral-decoder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <atomic> | ||||
|  | ||||
| class CyfralDecoder { | ||||
| public: | ||||
|     bool read(uint8_t* data, uint8_t data_size); | ||||
|     void process_front(bool polarity, uint32_t time); | ||||
|  | ||||
|     CyfralDecoder(); | ||||
|  | ||||
| private: | ||||
|     enum class BitState : uint8_t { | ||||
|         WAIT_FRONT_HIGH, | ||||
|         WAIT_FRONT_LOW, | ||||
|     }; | ||||
|  | ||||
|     enum class State : uint8_t { | ||||
|         WAIT_START_NIBBLE, | ||||
|         READ_NIBBLE, | ||||
|         READ_STOP_NIBBLE, | ||||
|     }; | ||||
|  | ||||
|     State state; | ||||
|     BitState bit_state; | ||||
|  | ||||
|     bool process_bit(bool polarity, uint32_t time, bool* readed, bool* readed_value); | ||||
|     void reset_state(); | ||||
|     bool nibble_valid(uint8_t data); | ||||
|  | ||||
|     // high + low period time | ||||
|     uint32_t period_time; | ||||
|  | ||||
|     // ready flag, key is readed and valid | ||||
|     std::atomic<bool> ready; | ||||
|  | ||||
|     // key data storage | ||||
|     uint16_t key_data; | ||||
|  | ||||
|     // temporary nibble storage | ||||
|     uint8_t readed_nibble; | ||||
|  | ||||
|     // data valid flag | ||||
|     // MUST be checked only in READ_STOP_NIBBLE state | ||||
|     bool data_valid; | ||||
|  | ||||
|     // nibble index, we expect 8 nibbles | ||||
|     uint8_t index; | ||||
|  | ||||
|     // bit index in nibble, 4 bit per nibble | ||||
|     uint8_t bit_index; | ||||
|  | ||||
|     // max period, 230us x clock per us | ||||
|     uint32_t max_period; | ||||
| }; | ||||
							
								
								
									
										39
									
								
								applications/ibutton/helpers/key-commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								applications/ibutton/helpers/key-commands.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
|  | ||||
| class RW1990_1 { | ||||
| public: | ||||
|     constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xD1; | ||||
|     constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0xB5; | ||||
|     constexpr static const uint8_t CMD_WRITE_ROM = 0xD5; | ||||
| }; | ||||
|  | ||||
| class RW1990_2 { | ||||
| public: | ||||
|     constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0x1D; | ||||
|     constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0x1E; | ||||
|     constexpr static const uint8_t CMD_WRITE_ROM = 0xD5; | ||||
| }; | ||||
|  | ||||
| class TM2004 { | ||||
| public: | ||||
|     constexpr static const uint8_t CMD_READ_STATUS = 0xAA; | ||||
|     constexpr static const uint8_t CMD_READ_MEMORY = 0xF0; | ||||
|     constexpr static const uint8_t CMD_WRITE_ROM = 0x3C; | ||||
|     constexpr static const uint8_t CMD_FINALIZATION = 0x35; | ||||
|  | ||||
|     constexpr static const uint8_t ANSWER_READ_MEMORY = 0xF5; | ||||
| }; | ||||
|  | ||||
| class TM01 { | ||||
| public: | ||||
|     constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xC1; | ||||
|     constexpr static const uint8_t CMD_WRITE_ROM = 0xC5; | ||||
|     constexpr static const uint8_t CMD_SWITCH_TO_CYFRAL = 0xCA; | ||||
|     constexpr static const uint8_t CMD_SWITCH_TO_METAKOM = 0xCB; | ||||
| }; | ||||
|  | ||||
| class DS1990 { | ||||
| public: | ||||
|     constexpr static const uint8_t CMD_READ_ROM = 0x33; | ||||
| }; | ||||
							
								
								
									
										204
									
								
								applications/ibutton/helpers/key-emulator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								applications/ibutton/helpers/key-emulator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| #include "key-emulator.h" | ||||
| #include <callback-connector.h> | ||||
|  | ||||
| KeyEmulator::~KeyEmulator() { | ||||
|     onewire_slave->stop(); | ||||
| } | ||||
|  | ||||
| KeyEmulator::KeyEmulator(OneWireSlave* _onewire_slave) | ||||
|     : dallas_key{0, 0, 0, 0, 0, 0, 0} { | ||||
|     onewire_slave = _onewire_slave; | ||||
|  | ||||
|     auto cb = cbc::obtain_connector(this, &KeyEmulator::result_callback); | ||||
|     onewire_slave->set_result_callback(cb, this); | ||||
| } | ||||
|  | ||||
| void KeyEmulator::start(iButtonKey* key) { | ||||
|     anything_emulated = false; | ||||
|     stop(); | ||||
|  | ||||
|     switch(key->get_key_type()) { | ||||
|     case iButtonKeyType::KeyDallas: | ||||
|         start_dallas_emulate(key); | ||||
|         break; | ||||
|     case iButtonKeyType::KeyCyfral: | ||||
|         start_cyfral_emulate(key); | ||||
|         break; | ||||
|     case iButtonKeyType::KeyMetakom: | ||||
|         start_metakom_emulate(key); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool KeyEmulator::emulated() { | ||||
|     bool result = false; | ||||
|  | ||||
|     if(anything_emulated) { | ||||
|         anything_emulated = false; | ||||
|         result = true; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void KeyEmulator::stop() { | ||||
|     onewire_slave->stop(); | ||||
|     pulser.stop(); | ||||
| } | ||||
|  | ||||
| void KeyEmulator::start_cyfral_emulate(iButtonKey* key) { | ||||
|     furi_assert(key->get_key_type() == iButtonKeyType::KeyCyfral); | ||||
|     furi_assert(key->get_type_data_size() == 2); | ||||
|  | ||||
|     const uint32_t cyfral_period_full = 8000; | ||||
|     const uint32_t cyfral_period_one[2] = { | ||||
|         uint32_t(cyfral_period_full * 0.33f), uint32_t(cyfral_period_full * 0.66f)}; | ||||
|     const uint32_t cyfral_period_zero[2] = { | ||||
|         uint32_t(cyfral_period_full * 0.66f), uint32_t(cyfral_period_full * 0.33f)}; | ||||
|     uint8_t pd_index = 0; | ||||
|     uint8_t* key_data = key->get_data(); | ||||
|  | ||||
|     // start nibble | ||||
|     set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|     pd_index++; | ||||
|     set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|     pd_index++; | ||||
|     set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|     pd_index++; | ||||
|     set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|     pd_index++; | ||||
|  | ||||
|     // data nibbles x 8 | ||||
|     for(int8_t i = key->get_type_data_size() - 1; i >= 0; i--) { | ||||
|         for(int8_t j = 3; j >= 0; j--) { | ||||
|             switch((key_data[i] >> (j * 2)) & 0b00000011) { | ||||
|             case 0b11: | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|                 pd_index++; | ||||
|                 break; | ||||
|             case 0b10: | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 break; | ||||
|             case 0b01: | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 break; | ||||
|             case 0b00: | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_zero); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 set_pulse_data_cyfral(pd_index, cyfral_period_one); | ||||
|                 pd_index++; | ||||
|                 break; | ||||
|             default: | ||||
|                 // cannot be anyway | ||||
|                 furi_check(false); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 4 (nibbles) x (8 data + 1 start) = 4 x 9 = 36 | ||||
|     if(pd_index != 36) { | ||||
|         // something is very wrong | ||||
|         furi_check(false); | ||||
|     } | ||||
|  | ||||
|     pulser.set_periods(pulse_data, 72, false); | ||||
|     pulser.start(); | ||||
| } | ||||
|  | ||||
| void KeyEmulator::start_metakom_emulate(iButtonKey* key) { | ||||
|     furi_assert(key->get_key_type() == iButtonKeyType::KeyMetakom); | ||||
|     furi_assert(key->get_type_data_size() == 4); | ||||
|  | ||||
|     const uint32_t metakom_period_full = 8000; | ||||
|     const uint32_t metakom_period_zero[2] = { | ||||
|         uint32_t(metakom_period_full * 0.33f), uint32_t(metakom_period_full * 0.66f)}; | ||||
|     const uint32_t metakom_period_one[2] = { | ||||
|         uint32_t(metakom_period_full * 0.66f), uint32_t(metakom_period_full * 0.33f)}; | ||||
|     uint8_t pd_index = 0; | ||||
|  | ||||
|     uint8_t* key_data = key->get_data(); | ||||
|  | ||||
|     // start pulse | ||||
|     pulse_data[0] = metakom_period_full * 4; | ||||
|  | ||||
|     // start triplet | ||||
|     set_pulse_data_metakom(pd_index, metakom_period_zero); | ||||
|     pd_index++; | ||||
|     set_pulse_data_metakom(pd_index, metakom_period_one); | ||||
|     pd_index++; | ||||
|     set_pulse_data_metakom(pd_index, metakom_period_zero); | ||||
|     pd_index++; | ||||
|  | ||||
|     for(int8_t i = key->get_type_data_size() - 1; i >= 0; i--) { | ||||
|         for(int8_t j = 7; j >= 0; j--) { | ||||
|             if(((key_data[i] >> j) & 0b00000001) == 1) { | ||||
|                 set_pulse_data_metakom(pd_index, metakom_period_one); | ||||
|                 pd_index++; | ||||
|             } else { | ||||
|                 set_pulse_data_metakom(pd_index, metakom_period_zero); | ||||
|                 pd_index++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 4 byte x 8 bits + 3 start bits = 35 | ||||
|     if(pd_index != 35) { | ||||
|         // something is very wrong | ||||
|         furi_check(false); | ||||
|     } | ||||
|  | ||||
|     pulser.set_periods(pulse_data, 71, false); | ||||
|     pulser.start(); | ||||
| } | ||||
|  | ||||
| void KeyEmulator::start_dallas_emulate(iButtonKey* key) { | ||||
|     furi_assert(key->get_key_type() == iButtonKeyType::KeyDallas); | ||||
|     furi_assert(key->get_type_data_size() == 8); | ||||
|  | ||||
|     onewire_slave->deattach(); | ||||
|     memcpy(dallas_key.id_storage, key->get_data(), key->get_type_data_size()); | ||||
|     onewire_slave->attach(&dallas_key); | ||||
|     onewire_slave->start(); | ||||
| } | ||||
|  | ||||
| void KeyEmulator::set_pulse_data_cyfral(uint8_t index, const uint32_t* data) { | ||||
|     pulse_data[index * 2] = data[0]; | ||||
|     pulse_data[index * 2 + 1] = data[1]; | ||||
| } | ||||
|  | ||||
| void KeyEmulator::set_pulse_data_metakom(uint8_t index, const uint32_t* data) { | ||||
|     // damn start pulse | ||||
|     pulse_data[(index * 2) + 1] = data[0]; | ||||
|     pulse_data[(index * 2) + 2] = data[1]; | ||||
| } | ||||
|  | ||||
| void KeyEmulator::result_callback(bool success, void* ctx) { | ||||
|     KeyEmulator* _this = static_cast<KeyEmulator*>(ctx); | ||||
|  | ||||
|     _this->anything_emulated = true; | ||||
| } | ||||
							
								
								
									
										34
									
								
								applications/ibutton/helpers/key-emulator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								applications/ibutton/helpers/key-emulator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #pragma once | ||||
| #include "pulse-sequencer.h" | ||||
| #include "../ibutton-key.h" | ||||
| #include <one_wire_slave.h> | ||||
| #include <one_wire_device_ds_1990.h> | ||||
| #include <atomic> | ||||
|  | ||||
| class KeyEmulator { | ||||
| public: | ||||
|     KeyEmulator(OneWireSlave* onewire_slave); | ||||
|     ~KeyEmulator(); | ||||
|  | ||||
|     void start(iButtonKey* key); | ||||
|     bool emulated(); | ||||
|     void stop(); | ||||
|  | ||||
| private: | ||||
|     DS1990 dallas_key; | ||||
|     OneWireSlave* onewire_slave; | ||||
|  | ||||
|     PulseSequencer pulser; | ||||
|     uint32_t pulse_data[72]; | ||||
|  | ||||
|     std::atomic<bool> anything_emulated; | ||||
|  | ||||
|     void start_cyfral_emulate(iButtonKey* key); | ||||
|     void start_metakom_emulate(iButtonKey* key); | ||||
|     void start_dallas_emulate(iButtonKey* key); | ||||
|  | ||||
|     void set_pulse_data_cyfral(uint8_t index, const uint32_t* data); | ||||
|     void set_pulse_data_metakom(uint8_t index, const uint32_t* data); | ||||
|  | ||||
|     void result_callback(bool success, void* ctx); | ||||
| }; | ||||
							
								
								
									
										10
									
								
								applications/ibutton/helpers/key-info.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/ibutton/helpers/key-info.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
|  | ||||
| static const uint8_t IBUTTON_KEY_SIZE = 8; | ||||
|  | ||||
| enum class iButtonKeyType : uint8_t { | ||||
|     KeyDallas, | ||||
|     KeyCyfral, | ||||
|     KeyMetakom, | ||||
| }; | ||||
							
								
								
									
										192
									
								
								applications/ibutton/helpers/key-reader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								applications/ibutton/helpers/key-reader.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| #include "key-reader.h" | ||||
| #include "key-commands.h" | ||||
| #include <callback-connector.h> | ||||
| #include <maxim_crc.h> | ||||
|  | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
|  | ||||
| KeyReader::Error KeyReader::read(iButtonKey* key) { | ||||
|     uint8_t tmp_key_data[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
|     iButtonKeyType key_type; | ||||
|  | ||||
|     KeyReader::Error result = KeyReader::Error::EMPTY; | ||||
|  | ||||
|     if(read_key(&key_type, tmp_key_data, 8)) { | ||||
|         switch(key_type) { | ||||
|         case iButtonKeyType::KeyDallas: | ||||
|             if(verify_key(key_type, tmp_key_data, 8)) { | ||||
|                 if(maxim_crc8(tmp_key_data, 8) == 0) { | ||||
|                     if(tmp_key_data[0] == 0x01) { | ||||
|                         result = KeyReader::Error::OK; | ||||
|                     } else { | ||||
|                         result = KeyReader::Error::NOT_ARE_KEY; | ||||
|                     } | ||||
|                 } else { | ||||
|                     result = KeyReader::Error::CRC_ERROR; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|         case iButtonKeyType::KeyCyfral: | ||||
|             result = KeyReader::Error::OK; | ||||
|             break; | ||||
|         case iButtonKeyType::KeyMetakom: | ||||
|             result = KeyReader::Error::OK; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         if(result != KeyReader::Error::EMPTY) { | ||||
|             key->set_type(key_type); | ||||
|             key->set_data(tmp_key_data, 8); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     switch_mode_if_needed(); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| KeyReader::KeyReader(OneWireMaster* _onewire_master) { | ||||
|     onewire_master = _onewire_master; | ||||
|     read_mode_switch_time = 0; | ||||
|     read_mode = ReadMode::DALLAS; | ||||
| } | ||||
|  | ||||
| KeyReader::~KeyReader() { | ||||
|     stop(); | ||||
| } | ||||
|  | ||||
| bool KeyReader::read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_size) { | ||||
|     bool readed = false; | ||||
|  | ||||
|     switch(read_mode) { | ||||
|     case ReadMode::DALLAS: | ||||
|         if(onewire_master->search(data)) { | ||||
|             onewire_master->reset_search(); | ||||
|             readed = true; | ||||
|             *key_type = iButtonKeyType::KeyDallas; | ||||
|         } else { | ||||
|             onewire_master->reset_search(); | ||||
|         } | ||||
|         break; | ||||
|     case ReadMode::CYFRAL_METAKOM: | ||||
|         if(cyfral_decoder.read(data, 2)) { | ||||
|             readed = true; | ||||
|             *key_type = iButtonKeyType::KeyCyfral; | ||||
|         } else if(metakom_decoder.read(data, 4)) { | ||||
|             readed = true; | ||||
|             *key_type = iButtonKeyType::KeyMetakom; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return readed; | ||||
| } | ||||
|  | ||||
| bool KeyReader::verify_key(iButtonKeyType key_type, const uint8_t* const data, uint8_t data_size) { | ||||
|     bool result = true; | ||||
|  | ||||
|     switch(key_type) { | ||||
|     case iButtonKeyType::KeyDallas: | ||||
|         switch_to(ReadMode::DALLAS); | ||||
|  | ||||
|         if(onewire_master->reset()) { | ||||
|             onewire_master->write(DS1990::CMD_READ_ROM); | ||||
|             for(uint8_t i = 0; i < data_size; i++) { | ||||
|                 if(onewire_master->read() != data[i]) { | ||||
|                     result = false; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             result = false; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|  | ||||
|     default: | ||||
|         result = false; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void KeyReader::start_comaparator(void) { | ||||
|     // pulldown lf-rfid pins to prevent interference | ||||
|     // TODO open record | ||||
|     GpioPin rfid_pull_pin = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; | ||||
|     gpio_init(&rfid_pull_pin, GpioModeOutputOpenDrain); | ||||
|     gpio_write(&rfid_pull_pin, false); | ||||
|  | ||||
|     // TODO open record | ||||
|     GpioPin rfid_out_pin = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin}; | ||||
|     gpio_init(&rfid_out_pin, GpioModeOutputOpenDrain); | ||||
|     gpio_write(&rfid_out_pin, false); | ||||
|  | ||||
|     comparator_callback_pointer = | ||||
|         cbc::obtain_connector(this, &KeyReader::comparator_trigger_callback); | ||||
|     api_interrupt_add(comparator_callback_pointer, InterruptTypeComparatorTrigger, this); | ||||
|     last_dwt_value = DWT->CYCCNT; | ||||
|     HAL_COMP_Start(&hcomp1); | ||||
| } | ||||
|  | ||||
| void KeyReader::stop_comaparator(void) { | ||||
|     HAL_COMP_Stop(&hcomp1); | ||||
|     api_interrupt_remove(comparator_callback_pointer, InterruptTypeComparatorTrigger); | ||||
| } | ||||
|  | ||||
| void KeyReader::comparator_trigger_callback(void* hcomp, void* comp_ctx) { | ||||
|     COMP_HandleTypeDef* _hcomp = static_cast<COMP_HandleTypeDef*>(hcomp); | ||||
|     KeyReader* _this = static_cast<KeyReader*>(comp_ctx); | ||||
|  | ||||
|     if(hcomp == &hcomp1) { | ||||
|         _this->cyfral_decoder.process_front( | ||||
|             (HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH), | ||||
|             DWT->CYCCNT - last_dwt_value); | ||||
|  | ||||
|         _this->metakom_decoder.process_front( | ||||
|             (HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH), | ||||
|             DWT->CYCCNT - last_dwt_value); | ||||
|  | ||||
|         last_dwt_value = DWT->CYCCNT; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void KeyReader::switch_to(ReadMode mode) { | ||||
|     switch(mode) { | ||||
|     case ReadMode::DALLAS: | ||||
|         onewire_master->start(); | ||||
|         stop_comaparator(); | ||||
|         break; | ||||
|     case ReadMode::CYFRAL_METAKOM: | ||||
|         onewire_master->stop(); | ||||
|         start_comaparator(); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     read_mode = mode; | ||||
| } | ||||
|  | ||||
| void KeyReader::switch_mode_if_needed() { | ||||
|     if(osKernelGetTickCount() - read_mode_switch_time > (osKernelGetTickFreq() / 5)) { | ||||
|         read_mode_switch_time = osKernelGetTickCount(); | ||||
|         switch(read_mode) { | ||||
|         case ReadMode::DALLAS: | ||||
|             switch_to(ReadMode::CYFRAL_METAKOM); | ||||
|             break; | ||||
|         case ReadMode::CYFRAL_METAKOM: | ||||
|             switch_to(ReadMode::DALLAS); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void KeyReader::start() { | ||||
|     switch_to(ReadMode::CYFRAL_METAKOM); | ||||
| } | ||||
|  | ||||
| void KeyReader::stop() { | ||||
|     onewire_master->stop(); | ||||
|     stop_comaparator(); | ||||
| } | ||||
							
								
								
									
										54
									
								
								applications/ibutton/helpers/key-reader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/ibutton/helpers/key-reader.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <furi.h> | ||||
| #include "cyfral-decoder.h" | ||||
| #pragma once | ||||
| #include "metakom-decoder.h" | ||||
| #include "../ibutton-key.h" | ||||
| #include <one_wire_master.h> | ||||
| #include <one_wire_slave.h> | ||||
|  | ||||
| class KeyReader { | ||||
| public: | ||||
|     enum class Error : uint8_t { | ||||
|         EMPTY, | ||||
|         CRC_ERROR, | ||||
|         NOT_ARE_KEY, | ||||
|         OK, | ||||
|     }; | ||||
|  | ||||
|     void start(); | ||||
|     void stop(); | ||||
|     KeyReader::Error read(iButtonKey* key); | ||||
|     KeyReader(OneWireMaster* onewire_master); | ||||
|     ~KeyReader(); | ||||
|  | ||||
| private: | ||||
|     bool read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_size); | ||||
|     bool verify_key(iButtonKeyType key_type, const uint8_t* const data, uint8_t data_size); | ||||
|  | ||||
|     // cyfral and metakom readers data | ||||
|     void comparator_trigger_callback(void* hcomp, void* comp_ctx); | ||||
|     void (*comparator_callback_pointer)(void* hcomp, void* comp_ctx); | ||||
|  | ||||
|     void start_comaparator(void); | ||||
|     void stop_comaparator(void); | ||||
|     uint32_t last_dwt_value; | ||||
|  | ||||
|     CyfralDecoder cyfral_decoder; | ||||
|     MetakomDecoder metakom_decoder; | ||||
|  | ||||
|     // mode | ||||
|     uint32_t read_mode_switch_time; | ||||
|     enum class ReadMode : uint8_t { | ||||
|         CYFRAL_METAKOM, | ||||
|         DALLAS, | ||||
|     }; | ||||
|     ReadMode read_mode; | ||||
|  | ||||
|     // one wire | ||||
|     OneWireMaster* onewire_master; | ||||
|  | ||||
|     void switch_to(ReadMode mode); | ||||
|     void switch_mode_if_needed(); | ||||
| }; | ||||
							
								
								
									
										69
									
								
								applications/ibutton/helpers/key-store.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								applications/ibutton/helpers/key-store.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #include "key-store.h" | ||||
| #include <furi.h> | ||||
|  | ||||
| uint16_t KeyStore::get_key_count() { | ||||
|     return store.size(); | ||||
| } | ||||
|  | ||||
| uint8_t KeyStore::add_key() { | ||||
|     store.push_back(iButtonKey()); | ||||
|     return get_key_count() - 1; | ||||
| } | ||||
|  | ||||
| void KeyStore::set_key_type(uint8_t index, iButtonKeyType type) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     key->set_type(type); | ||||
| } | ||||
|  | ||||
| void KeyStore::set_key_name(uint8_t index, char* name) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     char* orphan = strdup(name); | ||||
|     key->set_name(orphan); | ||||
| } | ||||
|  | ||||
| void KeyStore::set_key_data(uint8_t index, uint8_t* data, uint8_t data_size) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     key->set_data(data, data_size); | ||||
| } | ||||
|  | ||||
| iButtonKeyType KeyStore::get_key_type(uint8_t index) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     return key->get_key_type(); | ||||
| } | ||||
|  | ||||
| const char* KeyStore::get_key_name(uint8_t index) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     return key->get_name(); | ||||
| } | ||||
|  | ||||
| uint8_t* KeyStore::get_key_data(uint8_t index) { | ||||
|     iButtonKey* key = get_key(index); | ||||
|     return key->get_data(); | ||||
| } | ||||
|  | ||||
| void KeyStore::remove_key(uint8_t index) { | ||||
|     furi_check(index >= 0); | ||||
|     furi_check(index < get_key_count()); | ||||
|     auto item = std::next(store.begin(), index); | ||||
|     store.erase(item); | ||||
| } | ||||
|  | ||||
| KeyStore::KeyStore() { | ||||
|     store.push_back(iButtonKey( | ||||
|         iButtonKeyType::KeyDallas, "Dallas_1", 0x01, 0x41, 0xCE, 0x67, 0x0F, 0x00, 0x00, 0xB6)); | ||||
|     store.push_back(iButtonKey( | ||||
|         iButtonKeyType::KeyDallas, "Dallas_2", 0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB)); | ||||
|     store.push_back(iButtonKey( | ||||
|         iButtonKeyType::KeyCyfral, "Cyfral_1", 0xA6, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); | ||||
|     store.push_back(iButtonKey( | ||||
|         iButtonKeyType::KeyMetakom, "Metakom_1", 0xB1, 0x2E, 0x47, 0xB2, 0x00, 0x00, 0x00, 0x00)); | ||||
| } | ||||
|  | ||||
| KeyStore::~KeyStore() { | ||||
| } | ||||
|  | ||||
| iButtonKey* KeyStore::get_key(uint8_t index) { | ||||
|     furi_check(index >= 0); | ||||
|     furi_check(index < get_key_count()); | ||||
|     return &(*std::next(store.begin(), index)); | ||||
| } | ||||
							
								
								
									
										29
									
								
								applications/ibutton/helpers/key-store.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								applications/ibutton/helpers/key-store.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <list> | ||||
| #include "key-info.h" | ||||
| #include "../ibutton-key.h" | ||||
|  | ||||
| class KeyStore { | ||||
| public: | ||||
|     uint16_t get_key_count(); | ||||
|  | ||||
|     uint8_t add_key(); | ||||
|  | ||||
|     void set_key_type(uint8_t index, iButtonKeyType type); | ||||
|     void set_key_name(uint8_t index, char* name); | ||||
|     void set_key_data(uint8_t index, uint8_t* data, uint8_t data_size); | ||||
|  | ||||
|     iButtonKeyType get_key_type(uint8_t index); | ||||
|     const char* get_key_name(uint8_t index); | ||||
|     uint8_t* get_key_data(uint8_t index); | ||||
|  | ||||
|     void remove_key(uint8_t index); | ||||
|  | ||||
|     KeyStore(); | ||||
|     ~KeyStore(); | ||||
|  | ||||
| private: | ||||
|     std::list<iButtonKey> store; | ||||
|     iButtonKey* get_key(uint8_t index); | ||||
| }; | ||||
							
								
								
									
										51
									
								
								applications/ibutton/helpers/key-worker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								applications/ibutton/helpers/key-worker.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| #include "key-worker.h" | ||||
| #include <callback-connector.h> | ||||
| #include <maxim_crc.h> | ||||
|  | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
|  | ||||
| KeyReader::Error KeyWorker::read(iButtonKey* key) { | ||||
|     KeyReader::Error result = key_reader.read(key); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void KeyWorker::start_read() { | ||||
|     key_reader.start(); | ||||
| } | ||||
|  | ||||
| void KeyWorker::stop_read() { | ||||
|     key_reader.stop(); | ||||
| } | ||||
|  | ||||
| bool KeyWorker::emulated() { | ||||
|     return key_emulator.emulated(); | ||||
| } | ||||
|  | ||||
| void KeyWorker::start_emulate(iButtonKey* key) { | ||||
|     key_emulator.start(key); | ||||
| } | ||||
|  | ||||
| void KeyWorker::stop_emulate() { | ||||
|     key_emulator.stop(); | ||||
| } | ||||
|  | ||||
| KeyWriter::Error KeyWorker::write(iButtonKey* key) { | ||||
|     return key_writer.write(key); | ||||
| } | ||||
|  | ||||
| void KeyWorker::start_write() { | ||||
|     key_writer.start(); | ||||
| } | ||||
|  | ||||
| void KeyWorker::stop_write() { | ||||
|     key_writer.stop(); | ||||
| } | ||||
|  | ||||
| KeyWorker::KeyWorker(const GpioPin* one_wire_gpio) | ||||
|     : onewire_master{one_wire_gpio} | ||||
|     , onewire_slave{one_wire_gpio} | ||||
|     , key_reader{&onewire_master} | ||||
|     , key_emulator{&onewire_slave} | ||||
|     , key_writer{&onewire_master} { | ||||
| } | ||||
							
								
								
									
										34
									
								
								applications/ibutton/helpers/key-worker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								applications/ibutton/helpers/key-worker.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #pragma once | ||||
| #include <furi.h> | ||||
| #include "key-info.h" | ||||
| #include "key-reader.h" | ||||
| #include "key-emulator.h" | ||||
| #include "key-writer.h" | ||||
| #include "../ibutton-key.h" | ||||
| #include <one_wire_master.h> | ||||
| #include <one_wire_slave.h> | ||||
|  | ||||
| class KeyWorker { | ||||
| public: | ||||
|     KeyReader::Error read(iButtonKey* key); | ||||
|     void start_read(); | ||||
|     void stop_read(); | ||||
|  | ||||
|     bool emulated(); | ||||
|     void start_emulate(iButtonKey* key); | ||||
|     void stop_emulate(); | ||||
|  | ||||
|     KeyWriter::Error write(iButtonKey* key); | ||||
|     void start_write(); | ||||
|     void stop_write(); | ||||
|  | ||||
|     KeyWorker(const GpioPin* one_wire_gpio); | ||||
|  | ||||
| private: | ||||
|     // one wire | ||||
|     OneWireMaster onewire_master; | ||||
|     OneWireSlave onewire_slave; | ||||
|     KeyReader key_reader; | ||||
|     KeyEmulator key_emulator; | ||||
|     KeyWriter key_writer; | ||||
| }; | ||||
							
								
								
									
										272
									
								
								applications/ibutton/helpers/key-writer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								applications/ibutton/helpers/key-writer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,272 @@ | ||||
| #include "key-writer.h" | ||||
| #include "key-commands.h" | ||||
|  | ||||
| KeyWriter::KeyWriter(OneWireMaster* _onewire_master) { | ||||
|     onewire_master = _onewire_master; | ||||
| } | ||||
|  | ||||
| KeyWriter::Error KeyWriter::write(iButtonKey* key) { | ||||
|     return write_internal(key); | ||||
| } | ||||
|  | ||||
| void KeyWriter::start() { | ||||
|     onewire_master->start(); | ||||
| } | ||||
|  | ||||
| void KeyWriter::stop() { | ||||
|     onewire_master->stop(); | ||||
| } | ||||
|  | ||||
| KeyWriter::Error KeyWriter::write_internal(iButtonKey* key) { | ||||
|     Error result = Error::NO_DETECT; | ||||
|     bool same_key = false; | ||||
|  | ||||
|     osKernelLock(); | ||||
|     bool presence = onewire_master->reset(); | ||||
|     osKernelUnlock(); | ||||
|  | ||||
|     if(presence) { | ||||
|         switch(key->get_key_type()) { | ||||
|         case iButtonKeyType::KeyDallas: | ||||
|             same_key = compare_key_ds1990(key); | ||||
|  | ||||
|             if(!same_key) { | ||||
|                 bool write_result = false; | ||||
|                 // currently we can write: | ||||
|                 // RW1990, TM08v2, TM08vi-2 by write_1990_1() | ||||
|                 // RW2004, RW2004 with EEPROM by write_TM2004(); | ||||
|  | ||||
|                 if(!write_result) { | ||||
|                     write_result = write_1990_1(key); | ||||
|                 } | ||||
|                 if(!write_result) { | ||||
|                     write_result = write_1990_2(key); | ||||
|                 } | ||||
|                 if(!write_result) { | ||||
|                     write_result = write_TM2004(key); | ||||
|                 } | ||||
|  | ||||
|                 if(write_result) { | ||||
|                     result = Error::OK; | ||||
|                 } else { | ||||
|                     result = Error::CANNOT_WRITE; | ||||
|                 } | ||||
|             } else { | ||||
|                 result = Error::SAME_KEY; | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool KeyWriter::compare_key_ds1990(iButtonKey* key) { | ||||
|     bool result = false; | ||||
|  | ||||
|     if(key->get_key_type() == iButtonKeyType::KeyDallas) { | ||||
|         __disable_irq(); | ||||
|         bool presence = onewire_master->reset(); | ||||
|  | ||||
|         if(presence) { | ||||
|             onewire_master->write(DS1990::CMD_READ_ROM); | ||||
|  | ||||
|             result = true; | ||||
|             for(uint8_t i = 0; i < key->get_type_data_size(); i++) { | ||||
|                 if(key->get_data()[i] != onewire_master->read()) { | ||||
|                     result = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         __enable_irq(); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool KeyWriter::write_1990_1(iButtonKey* key) { | ||||
|     bool result = false; | ||||
|  | ||||
|     if(key->get_key_type() == iButtonKeyType::KeyDallas) { | ||||
|         __disable_irq(); | ||||
|  | ||||
|         // unlock | ||||
|         onewire_master->reset(); | ||||
|         onewire_master->write(RW1990_1::CMD_WRITE_RECORD_FLAG); | ||||
|         delay_us(10); | ||||
|         onewire_write_one_bit(0, 5000); | ||||
|  | ||||
|         // write key | ||||
|         onewire_master->reset(); | ||||
|         onewire_master->write(RW1990_1::CMD_WRITE_ROM); | ||||
|         for(uint8_t i = 0; i < key->get_type_data_size(); i++) { | ||||
|             // inverted key for RW1990.1 | ||||
|             write_byte_ds1990(~key->get_data()[i]); | ||||
|             delay_us(30000); | ||||
|         } | ||||
|  | ||||
|         // lock | ||||
|         onewire_master->write(RW1990_1::CMD_WRITE_RECORD_FLAG); | ||||
|         onewire_write_one_bit(1); | ||||
|  | ||||
|         __enable_irq(); | ||||
|  | ||||
|         if(compare_key_ds1990(key)) { | ||||
|             result = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool KeyWriter::write_1990_2(iButtonKey* key) { | ||||
|     bool result = false; | ||||
|  | ||||
|     if(key->get_key_type() == iButtonKeyType::KeyDallas) { | ||||
|         __disable_irq(); | ||||
|  | ||||
|         // unlock | ||||
|         onewire_master->reset(); | ||||
|         onewire_master->write(RW1990_2::CMD_WRITE_RECORD_FLAG); | ||||
|         delay_us(10); | ||||
|         onewire_write_one_bit(1, 5000); | ||||
|  | ||||
|         // write key | ||||
|         onewire_master->reset(); | ||||
|         onewire_master->write(RW1990_2::CMD_WRITE_ROM); | ||||
|         for(uint8_t i = 0; i < key->get_type_data_size(); i++) { | ||||
|             write_byte_ds1990(key->get_data()[i]); | ||||
|             delay_us(30000); | ||||
|         } | ||||
|  | ||||
|         // lock | ||||
|         onewire_master->write(RW1990_2::CMD_WRITE_RECORD_FLAG); | ||||
|         onewire_write_one_bit(0); | ||||
|  | ||||
|         __enable_irq(); | ||||
|  | ||||
|         if(compare_key_ds1990(key)) { | ||||
|             result = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool KeyWriter::write_TM2004(iButtonKey* key) { | ||||
|     uint8_t answer; | ||||
|     bool result = true; | ||||
|  | ||||
|     if(key->get_key_type() == iButtonKeyType::KeyDallas) { | ||||
|         __disable_irq(); | ||||
|  | ||||
|         // write rom, addr is 0x0000 | ||||
|         onewire_master->reset(); | ||||
|         onewire_master->write(TM2004::CMD_WRITE_ROM); | ||||
|         onewire_master->write(0x00); | ||||
|         onewire_master->write(0x00); | ||||
|  | ||||
|         // write key | ||||
|         for(uint8_t i = 0; i < key->get_type_data_size(); i++) { | ||||
|             // write key byte | ||||
|             onewire_master->write(key->get_data()[i]); | ||||
|             answer = onewire_master->read(); | ||||
|             // TODO: check answer CRC | ||||
|  | ||||
|             // pulse indicating that data is correct | ||||
|             delay_us(600); | ||||
|             onewire_write_one_bit(1, 50000); | ||||
|  | ||||
|             // read writed key byte | ||||
|             answer = onewire_master->read(); | ||||
|  | ||||
|             // check that writed and readed are same | ||||
|             if(key->get_data()[i] != answer) { | ||||
|                 result = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(!compare_key_ds1990(key)) { | ||||
|             result = false; | ||||
|         } | ||||
|  | ||||
|         onewire_master->reset(); | ||||
|  | ||||
|         __enable_irq(); | ||||
|     } else { | ||||
|         result = false; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool KeyWriter::write_TM01(iButtonKey* key) { | ||||
|     /*bool result = true; | ||||
|  | ||||
|     // TODO test and encoding | ||||
|     __disable_irq(); | ||||
|  | ||||
|     // unlock | ||||
|     onewire_master->reset(); | ||||
|     onewire_master->write(TM01::CMD_WRITE_RECORD_FLAG); | ||||
|     onewire_write_one_bit(1, 10000); | ||||
|  | ||||
|     // write key | ||||
|     onewire_master->reset(); | ||||
|     onewire_master->write(TM01::CMD_WRITE_ROM); | ||||
|  | ||||
|     // TODO: key types | ||||
|     //if(type == KEY_METAKOM || type == KEY_CYFRAL) { | ||||
|     //} else { | ||||
|     for(uint8_t i = 0; i < key->get_type_data_size(); i++) { | ||||
|         write_byte_ds1990(key->get_data()[i]); | ||||
|         delay_us(10000); | ||||
|     } | ||||
|     //} | ||||
|  | ||||
|     // lock | ||||
|     onewire_master->write(TM01::CMD_WRITE_RECORD_FLAG); | ||||
|     onewire_write_one_bit(0, 10000); | ||||
|  | ||||
|     __enable_irq(); | ||||
|  | ||||
|     if(!compare_key_ds1990(key)) { | ||||
|         result = false; | ||||
|     } | ||||
|  | ||||
|     __disable_irq(); | ||||
|  | ||||
|     if(key->get_key_type() == iButtonKeyType::KeyMetakom || | ||||
|        key->get_key_type() == iButtonKeyType::KeyCyfral) { | ||||
|         onewire_master->reset(); | ||||
|         if(key->get_key_type() == iButtonKeyType::KeyCyfral) | ||||
|             onewire_master->write(TM01::CMD_SWITCH_TO_CYFRAL); | ||||
|         else | ||||
|             onewire_master->write(TM01::CMD_SWITCH_TO_METAKOM); | ||||
|         onewire_write_one_bit(1); | ||||
|     } | ||||
|  | ||||
|     __enable_irq(); | ||||
|  | ||||
|     return result;*/ | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| void KeyWriter::onewire_write_one_bit(bool value, uint32_t delay) { | ||||
|     onewire_master->write_bit(value); | ||||
|     delay_us(delay); | ||||
| } | ||||
|  | ||||
| void KeyWriter::write_byte_ds1990(uint8_t data) { | ||||
|     for(uint8_t n_bit = 0; n_bit < 8; n_bit++) { | ||||
|         onewire_master->write_bit(data & 1); | ||||
|         delay_us(5000); | ||||
|         data = data >> 1; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								applications/ibutton/helpers/key-writer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								applications/ibutton/helpers/key-writer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #pragma once | ||||
| #include "../ibutton-key.h" | ||||
| #include <one_wire_master.h> | ||||
|  | ||||
| class KeyWriter { | ||||
| public: | ||||
|     enum class Error : uint8_t { | ||||
|         OK, | ||||
|         SAME_KEY, | ||||
|         NO_DETECT, | ||||
|         CANNOT_WRITE, | ||||
|     }; | ||||
|  | ||||
|     KeyWriter(OneWireMaster* onewire_master); | ||||
|     ~KeyWriter(); | ||||
|  | ||||
|     KeyWriter::Error write(iButtonKey* key); | ||||
|     void start(); | ||||
|     void stop(); | ||||
|  | ||||
| private: | ||||
|     OneWireMaster* onewire_master; | ||||
|  | ||||
|     KeyWriter::Error write_internal(iButtonKey* key); | ||||
|     bool compare_key_ds1990(iButtonKey* key); | ||||
|  | ||||
|     // write strategy | ||||
|     bool write_1990_1(iButtonKey* key); | ||||
|     bool write_1990_2(iButtonKey* key); | ||||
|     bool write_TM2004(iButtonKey* key); | ||||
|     bool write_TM01(iButtonKey* key); | ||||
|  | ||||
|     void onewire_write_one_bit(bool value, uint32_t delay = 10000); | ||||
|     void write_byte_ds1990(uint8_t data); | ||||
| }; | ||||
							
								
								
									
										191
									
								
								applications/ibutton/helpers/metakom-decoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								applications/ibutton/helpers/metakom-decoder.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| #include "metakom-decoder.h" | ||||
| #include <furi.h> | ||||
|  | ||||
| bool MetakomDecoder::read(uint8_t* _data, uint8_t data_size) { | ||||
|     bool result = false; | ||||
|  | ||||
|     if(ready) { | ||||
|         memcpy(_data, &key_data, 4); | ||||
|         reset_state(); | ||||
|         result = true; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void MetakomDecoder::process_front(bool polarity, uint32_t time) { | ||||
|     if(max_period == 0) { | ||||
|         max_period = 230 * (SystemCoreClock / 1000000.0f); | ||||
|     } | ||||
|  | ||||
|     if(ready) return; | ||||
|  | ||||
|     uint32_t high_time = 0; | ||||
|     uint32_t low_time = 0; | ||||
|  | ||||
|     switch(state) { | ||||
|     case State::WAIT_PERIOD_SYNC: | ||||
|         if(process_bit(polarity, time, &high_time, &low_time)) { | ||||
|             period_sample_data[period_sample_index] = high_time + low_time; | ||||
|             period_sample_index++; | ||||
|  | ||||
|             if(period_sample_index == period_sample_count) { | ||||
|                 for(uint8_t i = 0; i < period_sample_count; i++) { | ||||
|                     period_time += period_sample_data[i]; | ||||
|                 }; | ||||
|                 period_time /= period_sample_count; | ||||
|  | ||||
|                 state = State::WAIT_START_BIT; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|     case State::WAIT_START_BIT: | ||||
|         if(process_bit(polarity, time, &high_time, &low_time)) { | ||||
|             tmp_counter++; | ||||
|             if(high_time > period_time) { | ||||
|                 tmp_counter = 0; | ||||
|                 state = State::WAIT_START_WORD; | ||||
|             } | ||||
|  | ||||
|             if(tmp_counter > 40) { | ||||
|                 reset_state(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|     case State::WAIT_START_WORD: | ||||
|         if(process_bit(polarity, time, &high_time, &low_time)) { | ||||
|             if(low_time < (period_time / 2)) { | ||||
|                 tmp_data = (tmp_data << 1) | 0b0; | ||||
|             } else { | ||||
|                 tmp_data = (tmp_data << 1) | 0b1; | ||||
|             } | ||||
|             tmp_counter++; | ||||
|  | ||||
|             if(tmp_counter == 3) { | ||||
|                 if(tmp_data == 0b010) { | ||||
|                     tmp_counter = 0; | ||||
|                     tmp_data = 0; | ||||
|                     state = State::READ_WORD; | ||||
|                 } else { | ||||
|                     reset_state(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case State::READ_WORD: | ||||
|         if(process_bit(polarity, time, &high_time, &low_time)) { | ||||
|             if(low_time < (period_time / 2)) { | ||||
|                 tmp_data = (tmp_data << 1) | 0b0; | ||||
|             } else { | ||||
|                 tmp_data = (tmp_data << 1) | 0b1; | ||||
|             } | ||||
|             tmp_counter++; | ||||
|  | ||||
|             if(tmp_counter == 8) { | ||||
|                 if(parity_check(tmp_data)) { | ||||
|                     key_data = (key_data << 8) | tmp_data; | ||||
|                     key_data_index++; | ||||
|                     tmp_data = 0; | ||||
|                     tmp_counter = 0; | ||||
|  | ||||
|                     if(key_data_index == 4) { | ||||
|                         // check for stop bit | ||||
|                         if(high_time > period_time) { | ||||
|                             state = State::READ_STOP_WORD; | ||||
|                         } else { | ||||
|                             reset_state(); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     reset_state(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case State::READ_STOP_WORD: | ||||
|         if(process_bit(polarity, time, &high_time, &low_time)) { | ||||
|             if(low_time < (period_time / 2)) { | ||||
|                 tmp_data = (tmp_data << 1) | 0b0; | ||||
|             } else { | ||||
|                 tmp_data = (tmp_data << 1) | 0b1; | ||||
|             } | ||||
|             tmp_counter++; | ||||
|  | ||||
|             if(tmp_counter == 3) { | ||||
|                 if(tmp_data == 0b010) { | ||||
|                     ready = true; | ||||
|                 } else { | ||||
|                     reset_state(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| MetakomDecoder::MetakomDecoder() { | ||||
|     reset_state(); | ||||
| } | ||||
|  | ||||
| void MetakomDecoder::reset_state() { | ||||
|     ready = false; | ||||
|     period_sample_index = 0; | ||||
|     period_time = 0; | ||||
|  | ||||
|     tmp_counter = 0; | ||||
|     tmp_data = 0; | ||||
|  | ||||
|     for(uint8_t i = 0; i < period_sample_count; i++) { | ||||
|         period_sample_data[i] = 0; | ||||
|     }; | ||||
|  | ||||
|     state = State::WAIT_PERIOD_SYNC; | ||||
|     bit_state = BitState::WAIT_FRONT_LOW; | ||||
|  | ||||
|     key_data = 0; | ||||
|     key_data_index = 0; | ||||
| } | ||||
|  | ||||
| bool MetakomDecoder::parity_check(uint8_t data) { | ||||
|     uint8_t ones_count = 0; | ||||
|     bool result; | ||||
|  | ||||
|     for(uint8_t i = 0; i < 8; i++) { | ||||
|         if((data >> i) & 0b00000001) { | ||||
|             ones_count++; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     result = (ones_count % 2 == 0); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool MetakomDecoder::process_bit( | ||||
|     bool polarity, | ||||
|     uint32_t time, | ||||
|     uint32_t* high_time, | ||||
|     uint32_t* low_time) { | ||||
|     bool result = false; | ||||
|  | ||||
|     switch(bit_state) { | ||||
|     case BitState::WAIT_FRONT_LOW: | ||||
|         if(polarity == false) { | ||||
|             *low_time = low_time_storage; | ||||
|             *high_time = time; | ||||
|             result = true; | ||||
|             bit_state = BitState::WAIT_FRONT_HIGH; | ||||
|         } | ||||
|         break; | ||||
|     case BitState::WAIT_FRONT_HIGH: | ||||
|         if(polarity == true) { | ||||
|             low_time_storage = time; | ||||
|             bit_state = BitState::WAIT_FRONT_LOW; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										54
									
								
								applications/ibutton/helpers/metakom-decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/ibutton/helpers/metakom-decoder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <atomic> | ||||
|  | ||||
| class MetakomDecoder { | ||||
| public: | ||||
|     bool read(uint8_t* data, uint8_t data_size); | ||||
|     void process_front(bool polarity, uint32_t time); | ||||
|  | ||||
|     MetakomDecoder(); | ||||
|  | ||||
| private: | ||||
|     enum class BitState : uint8_t { | ||||
|         WAIT_FRONT_HIGH, | ||||
|         WAIT_FRONT_LOW, | ||||
|     }; | ||||
|  | ||||
|     BitState bit_state; | ||||
|  | ||||
|     enum class State : uint8_t { | ||||
|         WAIT_PERIOD_SYNC, | ||||
|         WAIT_START_BIT, | ||||
|         WAIT_START_WORD, | ||||
|         READ_WORD, | ||||
|         READ_STOP_WORD, | ||||
|     }; | ||||
|  | ||||
|     State state; | ||||
|  | ||||
|     // high + low period time | ||||
|     uint32_t period_time; | ||||
|     uint32_t low_time_storage; | ||||
|  | ||||
|     static const uint8_t period_sample_count = 10; | ||||
|     uint8_t period_sample_index; | ||||
|     uint32_t period_sample_data[period_sample_count]; | ||||
|  | ||||
|     // ready flag, key is readed and valid | ||||
|     std::atomic<bool> ready; | ||||
|  | ||||
|     // max period, 230us x clock per us | ||||
|     uint32_t max_period; | ||||
|  | ||||
|     uint8_t tmp_data; | ||||
|     uint8_t tmp_counter; | ||||
|  | ||||
|     uint32_t key_data; | ||||
|     uint8_t key_data_index; | ||||
|  | ||||
|     void reset_state(); | ||||
|     bool parity_check(uint8_t data); | ||||
|  | ||||
|     bool process_bit(bool polarity, uint32_t time, uint32_t* high_time, uint32_t* low_time); | ||||
| }; | ||||
							
								
								
									
										87
									
								
								applications/ibutton/helpers/pulse-sequencer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								applications/ibutton/helpers/pulse-sequencer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| #include "pulse-sequencer.h" | ||||
| #include <furi.h> | ||||
| #include <callback-connector.h> | ||||
| #include <api-hal-resources.h> | ||||
|  | ||||
| void PulseSequencer::set_periods( | ||||
|     uint32_t* _periods, | ||||
|     uint16_t _periods_count, | ||||
|     bool _pin_start_state) { | ||||
|     periods = _periods; | ||||
|     periods_count = _periods_count; | ||||
|     pin_start_state = _pin_start_state; | ||||
| } | ||||
|  | ||||
| void PulseSequencer::start() { | ||||
|     callback_pointer = cbc::obtain_connector(this, &PulseSequencer::timer_elapsed_callback); | ||||
|     api_interrupt_add(callback_pointer, InterruptTypeTimerUpdate, this); | ||||
|  | ||||
|     init_timer(periods[period_index]); | ||||
|     pin_state = pin_start_state; | ||||
|     gpio_write(&ibutton_gpio, pin_state); | ||||
|     pin_state = !pin_state; | ||||
|     period_index = 1; | ||||
|  | ||||
|     HAL_TIM_Base_Start_IT(&htim1); | ||||
| } | ||||
|  | ||||
| void PulseSequencer::stop() { | ||||
|     HAL_TIM_Base_Stop_IT(&htim1); | ||||
|  | ||||
|     api_interrupt_remove(callback_pointer, InterruptTypeTimerUpdate); | ||||
|     deinit_timer(); | ||||
| } | ||||
|  | ||||
| PulseSequencer::~PulseSequencer() { | ||||
|     stop(); | ||||
| } | ||||
|  | ||||
| void PulseSequencer::init_timer(uint32_t period) { | ||||
|     TIM_ClockConfigTypeDef sClockSourceConfig = {0}; | ||||
|  | ||||
|     htim1.Instance = TIM1; | ||||
|     htim1.Init.Prescaler = 0; | ||||
|     htim1.Init.CounterMode = TIM_COUNTERMODE_UP; | ||||
|     htim1.Init.Period = period; | ||||
|     htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; | ||||
|     htim1.Init.RepetitionCounter = 0; | ||||
|     htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; | ||||
|     if(HAL_TIM_Base_Init(&htim1) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; | ||||
|     if(HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|  | ||||
|     HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0); | ||||
|     HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); | ||||
|  | ||||
|     gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain); | ||||
| } | ||||
|  | ||||
| void PulseSequencer::deinit_timer() { | ||||
| } | ||||
|  | ||||
| void PulseSequencer::timer_elapsed_callback(void* hw, void* context) { | ||||
|     PulseSequencer* _this = static_cast<PulseSequencer*>(context); | ||||
|     TIM_HandleTypeDef* htim = static_cast<TIM_HandleTypeDef*>(hw); | ||||
|  | ||||
|     if(htim->Instance == TIM1) { | ||||
|         htim->Instance->ARR = _this->periods[_this->period_index]; | ||||
|  | ||||
|         if(_this->period_index == 0) { | ||||
|             _this->pin_state = _this->pin_start_state; | ||||
|         } else { | ||||
|             _this->pin_state = !_this->pin_state; | ||||
|         } | ||||
|  | ||||
|         gpio_write(&ibutton_gpio, _this->pin_state); | ||||
|  | ||||
|         _this->period_index++; | ||||
|  | ||||
|         if(_this->period_index == _this->periods_count) { | ||||
|             _this->period_index = 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										26
									
								
								applications/ibutton/helpers/pulse-sequencer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								applications/ibutton/helpers/pulse-sequencer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
|  | ||||
| class PulseSequencer { | ||||
| public: | ||||
|     void set_periods(uint32_t* periods, uint16_t periods_count, bool pin_start_state); | ||||
|     void start(); | ||||
|     void stop(); | ||||
|  | ||||
|     ~PulseSequencer(); | ||||
|  | ||||
| private: | ||||
|     uint16_t period_index; | ||||
|     uint16_t periods_count; | ||||
|     uint32_t* periods; | ||||
|     bool pin_start_state; | ||||
|     bool pin_state; | ||||
|  | ||||
|     void init_timer(uint32_t period); | ||||
|     void deinit_timer(); | ||||
|  | ||||
|     void reset_period_index(PulseSequencer* _this); | ||||
|  | ||||
|     void (*callback_pointer)(void*, void*); | ||||
|     void timer_elapsed_callback(void* hcomp, void* comp_ctx); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user