From bdba15b36642981d23141b58eb8c1686a8905797 Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 29 Mar 2022 23:01:56 +1000 Subject: [PATCH] [FL-2393][FL-2381] iButton, OneWire: move to plain C (#1068) * iButton: getting started on the worker concept * Hal delay: added global instructions_per_us variable * iButton: one wire slave * iButton: ibutton key setter * iButton: one wire host, use ibutton_hal * iButton\RFID: common pulse decoder concept * iButton: cyfral decoder * iButton: worker thread concept * iButton: metakom decoder * iButton: write key through worker * iButton: worker mode holder * iButton: worker improvements * iButton: Cyfral encoder * iButton: Metakom encoder * lib: pulse protocol helpers * iButton: Metakom decoder * iButton: Cyfral decoder * iButton worker: separate modes * iButton: libs documentation * HAL: iButton gpio modes * iButton worker: rename modes file * iButton worker, hal: move to LL * iButton CLI: worker for reading and emulation commands * iButton HAL: correct init and emulation sequence * iButton cli: moved to plain C * iButton: move to worker, small step to plain C * Libs, one wire: move to plain C * Libs: added forgotten files to compilation * iButton writer: get rid of manual disable/enable irq --- applications/accessor/accessor_app.cpp | 13 +- applications/accessor/accessor_app.h | 10 +- .../accessor/scene/accessor_scene_start.cpp | 8 +- .../ibutton/helpers/cyfral_decoder.cpp | 193 ---------- applications/ibutton/helpers/cyfral_decoder.h | 55 --- applications/ibutton/helpers/key_commands.h | 39 --- applications/ibutton/helpers/key_emulator.cpp | 208 ----------- applications/ibutton/helpers/key_emulator.h | 34 -- applications/ibutton/helpers/key_info.h | 11 - applications/ibutton/helpers/key_reader.cpp | 181 ---------- applications/ibutton/helpers/key_reader.h | 54 --- applications/ibutton/helpers/key_worker.cpp | 52 --- applications/ibutton/helpers/key_worker.h | 35 -- applications/ibutton/helpers/key_writer.cpp | 278 --------------- applications/ibutton/helpers/key_writer.h | 35 -- .../ibutton/helpers/metakom_decoder.cpp | 191 ---------- .../ibutton/helpers/metakom_decoder.h | 54 --- .../ibutton/helpers/pulse_sequencer.cpp | 52 --- .../ibutton/helpers/pulse_sequencer.h | 26 -- applications/ibutton/ibutton_app.cpp | 47 +-- applications/ibutton/ibutton_app.h | 16 +- applications/ibutton/ibutton_cli.c | 308 ++++++++++++++++ applications/ibutton/ibutton_cli.cpp | 292 ---------------- applications/ibutton/ibutton_event.h | 5 + applications/ibutton/ibutton_key.cpp | 95 ----- applications/ibutton/ibutton_key.h | 31 -- .../ibutton/scene/ibutton_scene_add_type.cpp | 41 ++- .../ibutton/scene/ibutton_scene_add_type.h | 1 - .../ibutton/scene/ibutton_scene_add_value.cpp | 37 +- .../ibutton/scene/ibutton_scene_add_value.h | 3 +- .../scene/ibutton_scene_delete_confirm.cpp | 47 +-- .../scene/ibutton_scene_delete_confirm.h | 3 - .../scene/ibutton_scene_delete_success.cpp | 21 +- .../scene/ibutton_scene_delete_success.h | 3 - .../ibutton/scene/ibutton_scene_emulate.cpp | 43 +-- .../ibutton/scene/ibutton_scene_emulate.h | 1 - .../ibutton/scene/ibutton_scene_info.cpp | 42 +-- .../ibutton/scene/ibutton_scene_info.h | 3 - .../ibutton/scene/ibutton_scene_read.cpp | 50 +-- .../ibutton/scene/ibutton_scene_read.h | 2 - .../scene/ibutton_scene_read_crc_error.cpp | 33 +- .../scene/ibutton_scene_read_crc_error.h | 4 - .../ibutton_scene_read_not_key_error.cpp | 33 +- .../scene/ibutton_scene_read_not_key_error.h | 4 - .../scene/ibutton_scene_read_success.cpp | 39 +-- .../scene/ibutton_scene_read_success.h | 4 - .../scene/ibutton_scene_readed_key_menu.cpp | 36 +- .../scene/ibutton_scene_readed_key_menu.h | 1 - .../ibutton/scene/ibutton_scene_save_name.cpp | 33 +- .../ibutton/scene/ibutton_scene_save_name.h | 3 - .../scene/ibutton_scene_save_success.cpp | 23 +- .../scene/ibutton_scene_save_success.h | 3 - .../scene/ibutton_scene_saved_key_menu.cpp | 35 +- .../scene/ibutton_scene_saved_key_menu.h | 1 - .../scene/ibutton_scene_select_key.cpp | 2 - .../ibutton/scene/ibutton_scene_start.cpp | 30 +- .../ibutton/scene/ibutton_scene_start.h | 1 - .../ibutton/scene/ibutton_scene_write.cpp | 56 +-- .../ibutton/scene/ibutton_scene_write.h | 1 + .../scene/ibutton_scene_write_success.cpp | 23 +- .../scene/ibutton_scene_write_success.h | 3 - firmware/targets/f7/furi_hal/furi_hal_delay.c | 7 +- .../targets/f7/furi_hal/furi_hal_ibutton.c | 26 +- firmware/targets/f7/furi_hal/furi_hal_rfid.c | 11 +- .../targets/furi_hal_include/furi_hal_delay.h | 2 + .../furi_hal_include/furi_hal_ibutton.h | 49 ++- lib/lib.mk | 15 +- lib/one_wire/ibutton/encoder/encoder_cyfral.c | 126 +++++++ lib/one_wire/ibutton/encoder/encoder_cyfral.h | 54 +++ .../ibutton/encoder/encoder_metakom.c | 93 +++++ .../ibutton/encoder/encoder_metakom.h | 54 +++ lib/one_wire/ibutton/ibutton_key.c | 121 +++++++ lib/one_wire/ibutton/ibutton_key.h | 145 ++++++++ lib/one_wire/ibutton/ibutton_key_command.h | 28 ++ lib/one_wire/ibutton/ibutton_worker.c | 197 +++++++++++ lib/one_wire/ibutton/ibutton_worker.h | 113 ++++++ lib/one_wire/ibutton/ibutton_worker_i.h | 79 +++++ lib/one_wire/ibutton/ibutton_worker_modes.c | 330 ++++++++++++++++++ lib/one_wire/ibutton/ibutton_writer.c | 298 ++++++++++++++++ lib/one_wire/ibutton/ibutton_writer.h | 60 ++++ .../ibutton/pulse_protocols/protocol_cyfral.c | 256 ++++++++++++++ .../ibutton/pulse_protocols/protocol_cyfral.h | 38 ++ .../pulse_protocols/protocol_metakom.c | 262 ++++++++++++++ .../pulse_protocols/protocol_metakom.h | 38 ++ lib/one_wire/maxim_crc.c | 16 + lib/one_wire/maxim_crc.h | 14 + lib/one_wire/one_wire_device.c | 59 ++++ lib/one_wire/one_wire_device.h | 74 ++++ lib/one_wire/one_wire_host.c | 261 ++++++++++++++ lib/one_wire/one_wire_host.h | 121 +++++++ lib/one_wire/one_wire_host_timing.h | 30 ++ lib/one_wire/one_wire_slave.c | 317 +++++++++++++++++ lib/one_wire/one_wire_slave.h | 71 ++++ lib/one_wire/one_wire_slave_i.h | 38 ++ lib/one_wire/pulse_protocols/pulse_decoder.c | 66 ++++ lib/one_wire/pulse_protocols/pulse_decoder.h | 70 ++++ lib/one_wire/pulse_protocols/pulse_glue.c | 55 +++ lib/one_wire/pulse_protocols/pulse_glue.h | 26 ++ lib/one_wire/pulse_protocols/pulse_protocol.c | 67 ++++ lib/one_wire/pulse_protocols/pulse_protocol.h | 122 +++++++ lib/onewire/maxim_crc.cpp | 48 --- lib/onewire/maxim_crc.h | 6 - lib/onewire/one_wire_device.cpp | 39 --- lib/onewire/one_wire_device.h | 26 -- lib/onewire/one_wire_device_ds_1990.cpp | 12 - lib/onewire/one_wire_device_ds_1990.h | 16 - lib/onewire/one_wire_master.cpp | 247 ------------- lib/onewire/one_wire_master.h | 32 -- lib/onewire/one_wire_slave.cpp | 308 ---------------- lib/onewire/one_wire_slave.h | 75 ---- lib/onewire/one_wire_timings.cpp | 16 - lib/onewire/one_wire_timings.h | 53 --- 112 files changed, 4444 insertions(+), 3231 deletions(-) delete mode 100644 applications/ibutton/helpers/cyfral_decoder.cpp delete mode 100644 applications/ibutton/helpers/cyfral_decoder.h delete mode 100644 applications/ibutton/helpers/key_commands.h delete mode 100644 applications/ibutton/helpers/key_emulator.cpp delete mode 100644 applications/ibutton/helpers/key_emulator.h delete mode 100644 applications/ibutton/helpers/key_info.h delete mode 100644 applications/ibutton/helpers/key_reader.cpp delete mode 100644 applications/ibutton/helpers/key_reader.h delete mode 100644 applications/ibutton/helpers/key_worker.cpp delete mode 100644 applications/ibutton/helpers/key_worker.h delete mode 100644 applications/ibutton/helpers/key_writer.cpp delete mode 100644 applications/ibutton/helpers/key_writer.h delete mode 100644 applications/ibutton/helpers/metakom_decoder.cpp delete mode 100644 applications/ibutton/helpers/metakom_decoder.h delete mode 100644 applications/ibutton/helpers/pulse_sequencer.cpp delete mode 100644 applications/ibutton/helpers/pulse_sequencer.h create mode 100644 applications/ibutton/ibutton_cli.c delete mode 100644 applications/ibutton/ibutton_cli.cpp delete mode 100644 applications/ibutton/ibutton_key.cpp delete mode 100644 applications/ibutton/ibutton_key.h create mode 100644 lib/one_wire/ibutton/encoder/encoder_cyfral.c create mode 100644 lib/one_wire/ibutton/encoder/encoder_cyfral.h create mode 100644 lib/one_wire/ibutton/encoder/encoder_metakom.c create mode 100644 lib/one_wire/ibutton/encoder/encoder_metakom.h create mode 100644 lib/one_wire/ibutton/ibutton_key.c create mode 100644 lib/one_wire/ibutton/ibutton_key.h create mode 100644 lib/one_wire/ibutton/ibutton_key_command.h create mode 100644 lib/one_wire/ibutton/ibutton_worker.c create mode 100644 lib/one_wire/ibutton/ibutton_worker.h create mode 100644 lib/one_wire/ibutton/ibutton_worker_i.h create mode 100644 lib/one_wire/ibutton/ibutton_worker_modes.c create mode 100644 lib/one_wire/ibutton/ibutton_writer.c create mode 100644 lib/one_wire/ibutton/ibutton_writer.h create mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c create mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h create mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c create mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h create mode 100644 lib/one_wire/maxim_crc.c create mode 100644 lib/one_wire/maxim_crc.h create mode 100644 lib/one_wire/one_wire_device.c create mode 100644 lib/one_wire/one_wire_device.h create mode 100644 lib/one_wire/one_wire_host.c create mode 100644 lib/one_wire/one_wire_host.h create mode 100644 lib/one_wire/one_wire_host_timing.h create mode 100644 lib/one_wire/one_wire_slave.c create mode 100644 lib/one_wire/one_wire_slave.h create mode 100644 lib/one_wire/one_wire_slave_i.h create mode 100644 lib/one_wire/pulse_protocols/pulse_decoder.c create mode 100644 lib/one_wire/pulse_protocols/pulse_decoder.h create mode 100644 lib/one_wire/pulse_protocols/pulse_glue.c create mode 100644 lib/one_wire/pulse_protocols/pulse_glue.h create mode 100644 lib/one_wire/pulse_protocols/pulse_protocol.c create mode 100644 lib/one_wire/pulse_protocols/pulse_protocol.h delete mode 100644 lib/onewire/maxim_crc.cpp delete mode 100644 lib/onewire/maxim_crc.h delete mode 100644 lib/onewire/one_wire_device.cpp delete mode 100644 lib/onewire/one_wire_device.h delete mode 100644 lib/onewire/one_wire_device_ds_1990.cpp delete mode 100644 lib/onewire/one_wire_device_ds_1990.h delete mode 100644 lib/onewire/one_wire_master.cpp delete mode 100644 lib/onewire/one_wire_master.h delete mode 100644 lib/onewire/one_wire_slave.cpp delete mode 100644 lib/onewire/one_wire_slave.h delete mode 100644 lib/onewire/one_wire_timings.cpp delete mode 100644 lib/onewire/one_wire_timings.h diff --git a/applications/accessor/accessor_app.cpp b/applications/accessor/accessor_app.cpp index 064c0f10..21b2e258 100644 --- a/applications/accessor/accessor_app.cpp +++ b/applications/accessor/accessor_app.cpp @@ -9,7 +9,7 @@ void AccessorApp::run(void) { bool exit = false; wiegand.begin(); - onewire_master.start(); + onewire_host_start(onewire_host); scenes[current_scene]->on_enter(this); @@ -28,19 +28,20 @@ void AccessorApp::run(void) { scenes[current_scene]->on_exit(this); wiegand.end(); - onewire_master.stop(); + onewire_host_stop(onewire_host); } -AccessorApp::AccessorApp() - : onewire_master{&ibutton_gpio} { +AccessorApp::AccessorApp() { furi_hal_power_insomnia_enter(); notification = static_cast(furi_record_open("notification")); + onewire_host = onewire_host_alloc(); furi_hal_power_enable_otg(); } AccessorApp::~AccessorApp() { furi_hal_power_disable_otg(); furi_record_close("notification"); + onewire_host_free(onewire_host); furi_hal_power_insomnia_exit(); } @@ -136,6 +137,6 @@ WIEGAND* AccessorApp::get_wiegand() { return &wiegand; } -OneWireMaster* AccessorApp::get_one_wire() { - return &onewire_master; +OneWireHost* AccessorApp::get_one_wire() { + return onewire_host; } \ No newline at end of file diff --git a/applications/accessor/accessor_app.h b/applications/accessor/accessor_app.h index 9af62e1c..ce18c177 100644 --- a/applications/accessor/accessor_app.h +++ b/applications/accessor/accessor_app.h @@ -2,13 +2,9 @@ #include #include #include "accessor_view_manager.h" - #include "scene/accessor_scene_start.h" - #include "helpers/wiegand.h" - -#include - +#include #include class AccessorApp { @@ -37,7 +33,7 @@ public: void set_text_store(const char* text...); WIEGAND* get_wiegand(); - OneWireMaster* get_one_wire(); + OneWireHost* get_one_wire(); private: std::list previous_scenes_list = {Scene::Exit}; @@ -52,7 +48,7 @@ private: char text_store[text_store_size + 1]; WIEGAND wiegand; - OneWireMaster onewire_master; + OneWireHost* onewire_host; NotificationApp* notification; }; \ No newline at end of file diff --git a/applications/accessor/scene/accessor_scene_start.cpp b/applications/accessor/scene/accessor_scene_start.cpp index a82fc275..6f5a4d11 100644 --- a/applications/accessor/scene/accessor_scene_start.cpp +++ b/applications/accessor/scene/accessor_scene_start.cpp @@ -21,7 +21,7 @@ bool AccessorSceneStart::on_event(AccessorApp* app, AccessorEvent* event) { if(event->type == AccessorEvent::Type::Tick) { WIEGAND* wiegand = app->get_wiegand(); Popup* popup = app->get_view_manager()->get_popup(); - OneWireMaster* onewire = app->get_one_wire(); + OneWireHost* onewire_host = app->get_one_wire(); uint8_t data[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t type = 0; @@ -38,11 +38,11 @@ bool AccessorSceneStart::on_event(AccessorApp* app, AccessorEvent* event) { } } else { FURI_CRITICAL_ENTER(); - if(onewire->reset()) { + if(onewire_host_reset(onewire_host)) { type = 255; - onewire->write(0x33); + onewire_host_write(onewire_host, 0x33); for(uint8_t i = 0; i < 8; i++) { - data[i] = onewire->read(); + data[i] = onewire_host_read(onewire_host); } for(uint8_t i = 0; i < 7; i++) { diff --git a/applications/ibutton/helpers/cyfral_decoder.cpp b/applications/ibutton/helpers/cyfral_decoder.cpp deleted file mode 100644 index b782deea..00000000 --- a/applications/ibutton/helpers/cyfral_decoder.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "cyfral_decoder.h" -#include - -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; -} diff --git a/applications/ibutton/helpers/cyfral_decoder.h b/applications/ibutton/helpers/cyfral_decoder.h deleted file mode 100644 index efddbd7f..00000000 --- a/applications/ibutton/helpers/cyfral_decoder.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include -#include - -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 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; -}; diff --git a/applications/ibutton/helpers/key_commands.h b/applications/ibutton/helpers/key_commands.h deleted file mode 100644 index 39c32df0..00000000 --- a/applications/ibutton/helpers/key_commands.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include - -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; -}; \ No newline at end of file diff --git a/applications/ibutton/helpers/key_emulator.cpp b/applications/ibutton/helpers/key_emulator.cpp deleted file mode 100644 index b8f0b864..00000000 --- a/applications/ibutton/helpers/key_emulator.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "key_emulator.h" -#include - -KeyEmulator::~KeyEmulator() { - 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(); - - // pulldown pull pin, to prevent low-pass filtering by the RFID part of the schematic - furi_hal_rfid_pin_pull_pulldown(); - - 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(); - furi_hal_rfid_pins_reset(); -} - -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; - - // 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(ctx); - - _this->anything_emulated = true; -} \ No newline at end of file diff --git a/applications/ibutton/helpers/key_emulator.h b/applications/ibutton/helpers/key_emulator.h deleted file mode 100644 index 11edbe46..00000000 --- a/applications/ibutton/helpers/key_emulator.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "pulse_sequencer.h" -#include "../ibutton_key.h" -#include -#include -#include - -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 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); -}; diff --git a/applications/ibutton/helpers/key_info.h b/applications/ibutton/helpers/key_info.h deleted file mode 100644 index 20ee7e1d..00000000 --- a/applications/ibutton/helpers/key_info.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include - -static const uint8_t IBUTTON_KEY_DATA_SIZE = 8; -static const uint8_t IBUTTON_KEY_NAME_SIZE = 22; - -enum class iButtonKeyType : uint8_t { - KeyDallas, - KeyCyfral, - KeyMetakom, -}; \ No newline at end of file diff --git a/applications/ibutton/helpers/key_reader.cpp b/applications/ibutton/helpers/key_reader.cpp deleted file mode 100644 index cf6fc4a3..00000000 --- a/applications/ibutton/helpers/key_reader.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "key_reader.h" -#include "key_commands.h" -#include -#include - -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; - - if(read_mode == ReadMode::DALLAS) { - FURI_CRITICAL_ENTER(); - if(onewire_master->search(data)) { - onewire_master->reset_search(); - readed = true; - *key_type = iButtonKeyType::KeyDallas; - } else { - onewire_master->reset_search(); - } - FURI_CRITICAL_EXIT(); - } else if(read_mode == 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; - } - } - - return readed; -} - -bool KeyReader::verify_key(iButtonKeyType key_type, const uint8_t* const data, uint8_t data_size) { - bool result = true; - - if(key_type == iButtonKeyType::KeyDallas) { - switch_to(ReadMode::DALLAS); - - FURI_CRITICAL_ENTER(); - 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; - } - FURI_CRITICAL_EXIT(); - - } else { - result = false; - } - - return result; -} - -void KeyReader::start_comaparator(void) { - furi_hal_rfid_pins_reset(); - - // pulldown pull pin, we sense the signal through the analog part of the RFID schematic - furi_hal_rfid_pin_pull_pulldown(); - - comparator_callback_pointer = - cbc::obtain_connector(this, &KeyReader::comparator_trigger_callback); - furi_hal_rfid_comp_set_callback(comparator_callback_pointer, this); - last_dwt_value = DWT->CYCCNT; - furi_hal_rfid_comp_start(); -} - -void KeyReader::stop_comaparator(void) { - furi_hal_rfid_pins_reset(); - - // rfid_pins_reset will disable ibutton pin - furi_hal_ibutton_start(); - - furi_hal_rfid_comp_stop(); - furi_hal_rfid_comp_set_callback(NULL, NULL); -} - -void KeyReader::comparator_trigger_callback(bool level, void* comp_ctx) { - KeyReader* _this = static_cast(comp_ctx); - - uint32_t current_dwt_value = DWT->CYCCNT; - - _this->cyfral_decoder.process_front(level, current_dwt_value - last_dwt_value); - _this->metakom_decoder.process_front(level, current_dwt_value - last_dwt_value); - - last_dwt_value = current_dwt_value; -} - -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() { - furi_hal_power_enable_otg(); - switch_to(ReadMode::CYFRAL_METAKOM); -} - -void KeyReader::stop() { - furi_hal_power_disable_otg(); - onewire_master->stop(); - stop_comaparator(); -} diff --git a/applications/ibutton/helpers/key_reader.h b/applications/ibutton/helpers/key_reader.h deleted file mode 100644 index 2eb8dcd1..00000000 --- a/applications/ibutton/helpers/key_reader.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include -#include "cyfral_decoder.h" -#pragma once -#include "metakom_decoder.h" -#include "../ibutton_key.h" -#include -#include - -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(bool level, void* comp_ctx); - void (*comparator_callback_pointer)(bool level, 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(); -}; diff --git a/applications/ibutton/helpers/key_worker.cpp b/applications/ibutton/helpers/key_worker.cpp deleted file mode 100644 index 885dc595..00000000 --- a/applications/ibutton/helpers/key_worker.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "key_worker.h" -#include -#include - -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} { -} - -KeyWorker::~KeyWorker() { -} diff --git a/applications/ibutton/helpers/key_worker.h b/applications/ibutton/helpers/key_worker.h deleted file mode 100644 index efe141b0..00000000 --- a/applications/ibutton/helpers/key_worker.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include -#include "key_info.h" -#include "key_reader.h" -#include "key_emulator.h" -#include "key_writer.h" -#include "../ibutton_key.h" -#include -#include - -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); - ~KeyWorker(); - -private: - // one wire - OneWireMaster onewire_master; - OneWireSlave onewire_slave; - KeyReader key_reader; - KeyEmulator key_emulator; - KeyWriter key_writer; -}; \ No newline at end of file diff --git a/applications/ibutton/helpers/key_writer.cpp b/applications/ibutton/helpers/key_writer.cpp deleted file mode 100644 index 39637b3a..00000000 --- a/applications/ibutton/helpers/key_writer.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "key_writer.h" -#include "key_commands.h" - -KeyWriter::KeyWriter(OneWireMaster* _onewire_master) { - onewire_master = _onewire_master; -} - -KeyWriter::~KeyWriter() { - stop(); -} - -KeyWriter::Error KeyWriter::write(iButtonKey* key) { - return write_internal(key); -} - -void KeyWriter::start() { - furi_hal_power_enable_otg(); - onewire_master->start(); -} - -void KeyWriter::stop() { - furi_hal_power_disable_otg(); - 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) { - FURI_CRITICAL_ENTER(); - 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; - } - } - } - - FURI_CRITICAL_EXIT(); - } - - return result; -} - -bool KeyWriter::write_1990_1(iButtonKey* key) { - bool result = false; - - if(key->get_key_type() == iButtonKeyType::KeyDallas) { - FURI_CRITICAL_ENTER(); - - // 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); - - FURI_CRITICAL_EXIT(); - - 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) { - FURI_CRITICAL_ENTER(); - - // 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); - - FURI_CRITICAL_EXIT(); - - 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) { - FURI_CRITICAL_ENTER(); - - // 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(); - - FURI_CRITICAL_EXIT(); - } else { - result = false; - } - - return result; -} - -bool KeyWriter::write_TM01(iButtonKey* key) { - /*bool result = true; - - // TODO test and encoding - FURI_CRITICAL_ENTER(); - - // 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); - - FURI_CRITICAL_EXIT(); - - if(!compare_key_ds1990(key)) { - result = false; - } - - FURI_CRITICAL_ENTER(); - - 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); - } - - FURI_CRITICAL_EXIT(); - - 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; - } -} diff --git a/applications/ibutton/helpers/key_writer.h b/applications/ibutton/helpers/key_writer.h deleted file mode 100644 index e4aac7d2..00000000 --- a/applications/ibutton/helpers/key_writer.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "../ibutton_key.h" -#include - -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); -}; diff --git a/applications/ibutton/helpers/metakom_decoder.cpp b/applications/ibutton/helpers/metakom_decoder.cpp deleted file mode 100644 index 9c8ec30a..00000000 --- a/applications/ibutton/helpers/metakom_decoder.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "metakom_decoder.h" -#include - -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; -} \ No newline at end of file diff --git a/applications/ibutton/helpers/metakom_decoder.h b/applications/ibutton/helpers/metakom_decoder.h deleted file mode 100644 index 4a309935..00000000 --- a/applications/ibutton/helpers/metakom_decoder.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include - -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 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); -}; diff --git a/applications/ibutton/helpers/pulse_sequencer.cpp b/applications/ibutton/helpers/pulse_sequencer.cpp deleted file mode 100644 index 9453653a..00000000 --- a/applications/ibutton/helpers/pulse_sequencer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "pulse_sequencer.h" - -#include -#include - -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() { - period_index = 1; - pin_state = pin_start_state; - hal_gpio_write(&ibutton_gpio, pin_state); - pin_state = !pin_state; - - hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedVeryHigh); - furi_hal_ibutton_emulate_start( - periods[period_index], PulseSequencer::timer_elapsed_callback, this); -} - -void PulseSequencer::stop() { - furi_hal_ibutton_emulate_stop(); -} - -PulseSequencer::~PulseSequencer() { - stop(); -} - -void PulseSequencer::timer_elapsed_callback(void* context) { - PulseSequencer* self = static_cast(context); - - furi_hal_ibutton_emulate_set_next(self->periods[self->period_index]); - - if(self->period_index == 0) { - self->pin_state = self->pin_start_state; - } else { - self->pin_state = !self->pin_state; - } - - hal_gpio_write(&ibutton_gpio, self->pin_state); - - self->period_index++; - - if(self->period_index == self->periods_count) { - self->period_index = 0; - } -} diff --git a/applications/ibutton/helpers/pulse_sequencer.h b/applications/ibutton/helpers/pulse_sequencer.h deleted file mode 100644 index 20d9e50f..00000000 --- a/applications/ibutton/helpers/pulse_sequencer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include - -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 reset_period_index(PulseSequencer* _this); - - void (*callback_pointer)(void*, void*); - - static void timer_elapsed_callback(void* comp_ctx); -}; diff --git a/applications/ibutton/ibutton_app.cpp b/applications/ibutton/ibutton_app.cpp index d69f0097..61bbcffc 100644 --- a/applications/ibutton/ibutton_app.cpp +++ b/applications/ibutton/ibutton_app.cpp @@ -1,6 +1,6 @@ #include "ibutton_app.h" #include -#include +#include #include #include #include @@ -42,7 +42,9 @@ iButtonApp::iButtonApp() , storage{"storage"} , dialogs{"dialogs"} { furi_hal_power_insomnia_enter(); - key_worker = new KeyWorker(&ibutton_gpio); + key = ibutton_key_alloc(); + key_worker = ibutton_worker_alloc(); + ibutton_worker_start_thread(key_worker); } iButtonApp::~iButtonApp() { @@ -50,7 +52,10 @@ iButtonApp::~iButtonApp() { delete it->second; } scenes.clear(); - delete key_worker; + + ibutton_worker_stop_thread(key_worker); + ibutton_worker_free(key_worker); + ibutton_key_free(key); furi_hal_power_insomnia_exit(); } @@ -112,17 +117,12 @@ iButtonApp::Scene iButtonApp::get_previous_scene() { return scene; } -const GpioPin* iButtonApp::get_ibutton_pin() { - // TODO open record - return &ibutton_gpio; -} - -KeyWorker* iButtonApp::get_key_worker() { +iButtonWorker* iButtonApp::get_key_worker() { return key_worker; } iButtonKey* iButtonApp::get_key() { - return &key; + return key; } char* iButtonApp::get_file_name() { @@ -201,10 +201,11 @@ bool iButtonApp::save_key(const char* key_name) { if(!delete_key()) break; // Save the key - key.set_name(key_name); + ibutton_key_set_name(key, key_name); // Set full file name, for new key - string_printf(key_file_name, "%s/%s%s", app_folder, key.get_name(), app_extension); + string_printf( + key_file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension); // Open file for write if(!flipper_format_file_open_always(file, string_get_cstr(key_file_name))) break; @@ -215,7 +216,7 @@ bool iButtonApp::save_key(const char* key_name) { // Write key type if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom")) break; - const char* key_type = key.get_key_type_string_by_type(key.get_key_type()); + const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key)); if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break; // Write data @@ -223,7 +224,8 @@ bool iButtonApp::save_key(const char* key_name) { file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8")) break; - if(!flipper_format_write_hex(file, "Data", key.get_data(), key.get_type_data_size())) + if(!flipper_format_write_hex( + file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key))) break; result = true; @@ -258,15 +260,15 @@ bool iButtonApp::load_key_data(string_t key_path) { // key type iButtonKeyType type; if(!flipper_format_read_string(file, "Key type", data)) break; - if(!key.get_key_type_by_type_string(string_get_cstr(data), &type)) break; + if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break; // key data uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; - if(!flipper_format_read_hex(file, "Data", key_data, key.get_type_data_size_by_type(type))) + if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type))) break; - key.set_type(type); - key.set_data(key_data, IBUTTON_KEY_DATA_SIZE); + ibutton_key_set_type(key, type); + ibutton_key_set_data(key, key_data, IBUTTON_KEY_DATA_SIZE); result = true; } while(false); @@ -290,7 +292,7 @@ bool iButtonApp::load_key(const char* key_name) { result = load_key_data(key_path); if(result) { path_extract_filename_no_ext(key_name, key_path); - get_key()->set_name(string_get_cstr(key_path)); + ibutton_key_set_name(key, string_get_cstr(key_path)); } string_clear(key_path); return result; @@ -306,7 +308,7 @@ bool iButtonApp::load_key() { app_extension, get_file_name(), get_file_name_size(), - get_key()->get_name()); + ibutton_key_get_name_p(key)); if(res) { string_t key_str; @@ -316,7 +318,7 @@ bool iButtonApp::load_key() { result = load_key_data(key_str); if(result) { - get_key()->set_name(get_file_name()); + ibutton_key_set_name(key, get_file_name()); } string_clear(key_str); } @@ -328,7 +330,8 @@ bool iButtonApp::delete_key() { string_t file_name; bool result = false; - string_init_printf(file_name, "%s/%s%s", app_folder, get_key()->get_name(), app_extension); + string_init_printf( + file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension); result = storage_simply_remove(storage, string_get_cstr(file_name)); string_clear(file_name); diff --git a/applications/ibutton/ibutton_app.h b/applications/ibutton/ibutton_app.h index fc2a32e7..ddaadfcd 100644 --- a/applications/ibutton/ibutton_app.h +++ b/applications/ibutton/ibutton_app.h @@ -22,17 +22,10 @@ #include "scene/ibutton_scene_select_key.h" #include "scene/ibutton_scene_add_type.h" #include "scene/ibutton_scene_add_value.h" - -#include "helpers/key_worker.h" - -#include "one_wire_master.h" -#include "maxim_crc.h" -#include "ibutton_key.h" - +#include #include #include #include - #include class iButtonApp { @@ -75,7 +68,7 @@ public: Scene get_previous_scene(); const GpioPin* get_ibutton_pin(); - KeyWorker* get_key_worker(); + iButtonWorker* get_key_worker(); iButtonKey* get_key(); void notify_green_blink(); @@ -127,9 +120,8 @@ private: {Scene::SceneAddValue, new iButtonSceneAddValue()}, }; - KeyWorker* key_worker; - - iButtonKey key; + iButtonWorker* key_worker; + iButtonKey* key; RecordController notification; RecordController storage; diff --git a/applications/ibutton/ibutton_cli.c b/applications/ibutton/ibutton_cli.c new file mode 100644 index 00000000..1c281dc2 --- /dev/null +++ b/applications/ibutton/ibutton_cli.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include + +void ibutton_cli(Cli* cli, string_t args, void* context); +void onewire_cli(Cli* cli, string_t args, void* context); + +// app cli function +void ibutton_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open("cli"); + cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli); + cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli); + furi_record_close("cli"); +#endif +} + +void ibutton_cli_print_usage() { + printf("Usage:\r\n"); + printf("ikey read\r\n"); + printf("ikey emulate \r\n"); + printf("ikey write Dallas \r\n"); + printf("\t choose from:\r\n"); + printf("\tDallas (8 bytes key_data)\r\n"); + printf("\tCyfral (2 bytes key_data)\r\n"); + printf("\tMetakom (4 bytes key_data)\r\n"); + printf("\t are hex-formatted\r\n"); +}; + +bool ibutton_cli_get_key_type(string_t data, iButtonKeyType* type) { + bool result = false; + + if(string_cmp_str(data, "Dallas") == 0 || string_cmp_str(data, "dallas") == 0) { + result = true; + *type = iButtonKeyDS1990; + } else if(string_cmp_str(data, "Cyfral") == 0 || string_cmp_str(data, "cyfral") == 0) { + result = true; + *type = iButtonKeyCyfral; + } else if(string_cmp_str(data, "Metakom") == 0 || string_cmp_str(data, "metakom") == 0) { + result = true; + *type = iButtonKeyMetakom; + } + + return result; +} + +void ibutton_cli_print_key_data(iButtonKey* key) { + const uint8_t* key_data = ibutton_key_get_data_p(key); + iButtonKeyType type = ibutton_key_get_type(key); + + printf("%s ", ibutton_key_get_string_by_type(type)); + for(size_t i = 0; i < ibutton_key_get_size_by_type(type); i++) { + printf("%02X", key_data[i]); + } + + printf("\r\n"); +} + +#define EVENT_FLAG_IBUTTON_COMPLETE (1 << 0) + +static void ibutton_cli_worker_read_cb(void* context) { + osEventFlagsId_t event = context; + osEventFlagsSet(event, EVENT_FLAG_IBUTTON_COMPLETE); +} + +void ibutton_cli_read(Cli* cli) { + iButtonKey* key = ibutton_key_alloc(); + iButtonWorker* worker = ibutton_worker_alloc(); + osEventFlagsId_t event = osEventFlagsNew(NULL); + + ibutton_worker_start_thread(worker); + ibutton_worker_read_set_callback(worker, ibutton_cli_worker_read_cb, event); + + ibutton_worker_read_start(worker, key); + while(true) { + uint32_t flags = osEventFlagsWait(event, EVENT_FLAG_IBUTTON_COMPLETE, osFlagsWaitAny, 100); + + if(flags & EVENT_FLAG_IBUTTON_COMPLETE) { + ibutton_cli_print_key_data(key); + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + if(!ibutton_key_dallas_crc_is_valid(key)) { + printf("Warning: invalid CRC\r\n"); + } + + if(!ibutton_key_dallas_is_1990_key(key)) { + printf("Warning: not a key\r\n"); + } + } + break; + } + + if(cli_cmd_interrupt_received(cli)) break; + } + ibutton_worker_stop(worker); + + ibutton_worker_stop_thread(worker); + ibutton_worker_free(worker); + ibutton_key_free(key); + + osEventFlagsDelete(event); +}; + +typedef struct { + osEventFlagsId_t event; + iButtonWorkerWriteResult result; +} iButtonWriteContext; + +static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult result) { + iButtonWriteContext* write_context = (iButtonWriteContext*)context; + write_context->result = result; + osEventFlagsSet(write_context->event, EVENT_FLAG_IBUTTON_COMPLETE); +} + +void ibutton_cli_write(Cli* cli, string_t args) { + iButtonKey* key = ibutton_key_alloc(); + iButtonWorker* worker = ibutton_worker_alloc(); + iButtonKeyType type; + iButtonWriteContext write_context; + uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; + string_t data; + + write_context.event = osEventFlagsNew(NULL); + + string_init(data); + ibutton_worker_start_thread(worker); + ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context); + + do { + if(!args_read_string_and_trim(args, data)) { + ibutton_cli_print_usage(); + break; + } + + if(!ibutton_cli_get_key_type(data, &type)) { + ibutton_cli_print_usage(); + break; + } + + if(type != iButtonKeyDS1990) { + ibutton_cli_print_usage(); + break; + } + + if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) { + ibutton_cli_print_usage(); + break; + } + + ibutton_key_set_type(key, type); + ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type)); + + printf("Writing key "); + ibutton_cli_print_key_data(key); + printf("Press Ctrl+C to abort\r\n"); + + ibutton_worker_write_start(worker, key); + while(true) { + uint32_t flags = osEventFlagsWait( + write_context.event, EVENT_FLAG_IBUTTON_COMPLETE, osFlagsWaitAny, 100); + + if(flags & EVENT_FLAG_IBUTTON_COMPLETE) { + if(write_context.result == iButtonWorkerWriteSameKey || + write_context.result == iButtonWorkerWriteOK) { + printf("Write success\r\n"); + break; + } else if(write_context.result == iButtonWorkerWriteCannotWrite) { + printf("Write fail\r\n"); + break; + } + } + + if(cli_cmd_interrupt_received(cli)) break; + } + ibutton_worker_stop(worker); + } while(false); + + string_clear(data); + ibutton_worker_stop_thread(worker); + ibutton_worker_free(worker); + ibutton_key_free(key); + + osEventFlagsDelete(write_context.event); +}; + +void ibutton_cli_emulate(Cli* cli, string_t args) { + iButtonKey* key = ibutton_key_alloc(); + iButtonWorker* worker = ibutton_worker_alloc(); + iButtonKeyType type; + uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; + string_t data; + + string_init(data); + ibutton_worker_start_thread(worker); + + do { + if(!args_read_string_and_trim(args, data)) { + ibutton_cli_print_usage(); + break; + } + + if(!ibutton_cli_get_key_type(data, &type)) { + ibutton_cli_print_usage(); + break; + } + + if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) { + ibutton_cli_print_usage(); + break; + } + + ibutton_key_set_type(key, type); + ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type)); + + printf("Emulating key "); + ibutton_cli_print_key_data(key); + printf("Press Ctrl+C to abort\r\n"); + + ibutton_worker_emulate_start(worker, key); + while(!cli_cmd_interrupt_received(cli)) { + delay(100); + }; + ibutton_worker_stop(worker); + } while(false); + + string_clear(data); + ibutton_worker_stop_thread(worker); + ibutton_worker_free(worker); + ibutton_key_free(key); +}; + +void ibutton_cli(Cli* cli, string_t args, void* context) { + string_t cmd; + string_init(cmd); + + if(!args_read_string_and_trim(args, cmd)) { + string_clear(cmd); + ibutton_cli_print_usage(); + return; + } + + if(string_cmp_str(cmd, "read") == 0) { + ibutton_cli_read(cli); + } else if(string_cmp_str(cmd, "write") == 0) { + ibutton_cli_write(cli, args); + } else if(string_cmp_str(cmd, "emulate") == 0) { + ibutton_cli_emulate(cli, args); + } else { + ibutton_cli_print_usage(); + } + + string_clear(cmd); +} + +void onewire_cli_print_usage() { + printf("Usage:\r\n"); + printf("onewire search\r\n"); +}; + +void onewire_cli_search(Cli* cli) { + OneWireHost* onewire = onewire_host_alloc(); + uint8_t address[8]; + bool done = false; + + printf("Search started\r\n"); + + onewire_host_start(onewire); + furi_hal_power_enable_otg(); + + while(!done) { + if(onewire_host_search(onewire, address, NORMAL_SEARCH) != 1) { + printf("Search finished\r\n"); + onewire_host_reset_search(onewire); + done = true; + } else { + printf("Found: "); + for(uint8_t i = 0; i < 8; i++) { + printf("%02X", address[i]); + } + printf("\r\n"); + } + delay(100); + } + + furi_hal_power_disable_otg(); + onewire_host_free(onewire); +} + +void onewire_cli(Cli* cli, string_t args, void* context) { + string_t cmd; + string_init(cmd); + + if(!args_read_string_and_trim(args, cmd)) { + string_clear(cmd); + onewire_cli_print_usage(); + return; + } + + if(string_cmp_str(cmd, "search") == 0) { + onewire_cli_search(cli); + } + + string_clear(cmd); +} diff --git a/applications/ibutton/ibutton_cli.cpp b/applications/ibutton/ibutton_cli.cpp deleted file mode 100644 index 3e41befa..00000000 --- a/applications/ibutton/ibutton_cli.cpp +++ /dev/null @@ -1,292 +0,0 @@ -#include -#include -#include -#include -#include - -#include "helpers/key_info.h" -#include "helpers/key_worker.h" - -#include - -void ibutton_cli(Cli* cli, string_t args, void* context); -void onewire_cli(Cli* cli, string_t args, void* context); - -// app cli function -extern "C" void ibutton_on_system_start() { -#ifdef SRV_CLI - Cli* cli = static_cast(furi_record_open("cli")); - cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli); - cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli); - furi_record_close("cli"); -#endif -} - -void ibutton_cli_print_usage() { - printf("Usage:\r\n"); - printf("ikey read\r\n"); - printf("ikey \r\n"); - printf("\t choose from:\r\n"); - printf("\tDallas (8 bytes key_data)\r\n"); - printf("\tCyfral (2 bytes key_data)\r\n"); - printf("\tMetakom (4 bytes key_data)\r\n"); - printf("\t are hex-formatted\r\n"); -}; - -bool ibutton_cli_get_key_type(string_t data, iButtonKeyType* type) { - bool result = false; - - if(string_cmp_str(data, "Dallas") == 0 || string_cmp_str(data, "dallas") == 0) { - result = true; - *type = iButtonKeyType::KeyDallas; - } else if(string_cmp_str(data, "Cyfral") == 0 || string_cmp_str(data, "cyfral") == 0) { - result = true; - *type = iButtonKeyType::KeyCyfral; - } else if(string_cmp_str(data, "Metakom") == 0 || string_cmp_str(data, "metakom") == 0) { - result = true; - *type = iButtonKeyType::KeyMetakom; - } - - return result; -} - -void ibutton_cli_print_key_data(iButtonKey* key) { - uint8_t* key_data = key->get_data(); - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: - printf( - "Dallas %02X%02X%02X%02X%02X%02X%02X%02X\r\n", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7]); - break; - case iButtonKeyType::KeyCyfral: - printf("Cyfral %02X%02X\r\n", key_data[0], key_data[1]); - break; - case iButtonKeyType::KeyMetakom: - printf("Metakom %02X%02X%02X%02X\r\n", key_data[0], key_data[1], key_data[2], key_data[3]); - break; - } -} - -void ibutton_cli_read(Cli* cli) { - iButtonKey key; - std::unique_ptr worker(new KeyWorker(&ibutton_gpio)); - - bool exit = false; - - worker->start_read(); - printf("Reading iButton...\r\nPress Ctrl+C to abort\r\n"); - - while(!exit) { - exit = cli_cmd_interrupt_received(cli); - - switch(worker->read(&key)) { - case KeyReader::Error::EMPTY: - break; - case KeyReader::Error::CRC_ERROR: - ibutton_cli_print_key_data(&key); - printf("Warning: invalid CRC\r\n"); - exit = true; - break; - case KeyReader::Error::OK: - ibutton_cli_print_key_data(&key); - exit = true; - break; - case KeyReader::Error::NOT_ARE_KEY: - ibutton_cli_print_key_data(&key); - printf("Warning: not a key\r\n"); - exit = true; - break; - } - - delay(100); - } - - worker->stop_read(); -}; - -void ibutton_cli_write(Cli* cli, string_t args) { - iButtonKey key; - iButtonKeyType type; - std::unique_ptr worker(new KeyWorker(&ibutton_gpio)); - - bool exit = false; - string_t data; - string_init(data); - - if(!args_read_string_and_trim(args, data)) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - if(!ibutton_cli_get_key_type(data, &type)) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - key.set_type(type); - - if(!args_read_hex_bytes(args, key.get_data(), key.get_type_data_size())) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - printf("Writing key "); - ibutton_cli_print_key_data(&key); - printf("Press Ctrl+C to abort\r\n"); - - worker->start_write(); - - while(!exit) { - exit = cli_cmd_interrupt_received(cli); - - KeyWriter::Error result = worker->write(&key); - - switch(result) { - case KeyWriter::Error::SAME_KEY: - case KeyWriter::Error::OK: - printf("Write success\r\n"); - exit = true; - break; - case KeyWriter::Error::NO_DETECT: - break; - case KeyWriter::Error::CANNOT_WRITE: - printf("Write fail\r\n"); - exit = true; - break; - } - - delay(100); - }; - - worker->stop_write(); - - string_clear(data); -}; - -void ibutton_cli_emulate(Cli* cli, string_t args) { - iButtonKey key; - iButtonKeyType type; - std::unique_ptr worker(new KeyWorker(&ibutton_gpio)); - bool exit = false; - string_t data; - string_init(data); - - if(!args_read_string_and_trim(args, data)) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - if(!ibutton_cli_get_key_type(data, &type)) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - key.set_type(type); - - if(!args_read_hex_bytes(args, key.get_data(), key.get_type_data_size())) { - ibutton_cli_print_usage(); - string_clear(data); - return; - } - - printf("Emulating key "); - ibutton_cli_print_key_data(&key); - printf("Press Ctrl+C to abort\r\n"); - - worker->start_emulate(&key); - - while(!exit) { - exit = cli_cmd_interrupt_received(cli); - delay(100); - }; - - worker->stop_emulate(); - - string_clear(data); -}; - -void ibutton_cli(Cli* cli, string_t args, void* context) { - string_t cmd; - string_init(cmd); - - if(!args_read_string_and_trim(args, cmd)) { - string_clear(cmd); - ibutton_cli_print_usage(); - return; - } - - if(string_cmp_str(cmd, "read") == 0) { - ibutton_cli_read(cli); - } else if(string_cmp_str(cmd, "write") == 0) { - ibutton_cli_write(cli, args); - } else if(string_cmp_str(cmd, "emulate") == 0) { - ibutton_cli_emulate(cli, args); - } else { - ibutton_cli_print_usage(); - } - - string_clear(cmd); -} - -void onewire_cli_print_usage() { - printf("Usage:\r\n"); - printf("onewire search\r\n"); -}; - -void onewire_cli_search(Cli* cli) { - OneWireMaster onewire(&ibutton_gpio); - uint8_t address[8]; - bool done = false; - - printf("Search started\r\n"); - - onewire.start(); - furi_hal_power_enable_otg(); - - while(!done) { - if(onewire.search(address, true) != 1) { - printf("Search finished\r\n"); - onewire.reset_search(); - done = true; - } else { - printf("Found: "); - for(uint8_t i = 0; i < 8; i++) { - printf("%02X", address[i]); - } - printf("\r\n"); - } - delay(100); - } - - furi_hal_power_disable_otg(); - onewire.stop(); -} - -void onewire_cli(Cli* cli, string_t args, void* context) { - string_t cmd; - string_init(cmd); - - if(!args_read_string_and_trim(args, cmd)) { - string_clear(cmd); - onewire_cli_print_usage(); - return; - } - - if(string_cmp_str(cmd, "search") == 0) { - onewire_cli_search(cli); - } - - string_clear(cmd); -} diff --git a/applications/ibutton/ibutton_event.h b/applications/ibutton/ibutton_event.h index 0d6f4d90..b4dac2f4 100644 --- a/applications/ibutton/ibutton_event.h +++ b/applications/ibutton/ibutton_event.h @@ -2,6 +2,7 @@ #include #include #include +#include class iButtonApp; @@ -16,6 +17,9 @@ public: EventTypeTextEditResult, EventTypeByteEditResult, EventTypeWidgetButtonResult, + EventTypeWorkerEmulated, + EventTypeWorkerRead, + EventTypeWorkerWrite, }; // payload @@ -23,6 +27,7 @@ public: uint32_t menu_index; DialogExResult dialog_result; GuiButtonType widget_button_result; + iButtonWorkerWriteResult worker_write_result; } payload; // event type diff --git a/applications/ibutton/ibutton_key.cpp b/applications/ibutton/ibutton_key.cpp deleted file mode 100644 index cb65a239..00000000 --- a/applications/ibutton/ibutton_key.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "ibutton_key.h" -#include - -uint8_t iButtonKey::get_size() { - return IBUTTON_KEY_DATA_SIZE; -} - -void iButtonKey::set_data(uint8_t* _data, uint8_t _data_count) { - furi_check(_data_count > 0); - furi_check(_data_count <= get_size()); - - memset(data, 0, get_size()); - memcpy(data, _data, _data_count); -} - -void iButtonKey::clear_data() { - memset(data, 0, get_size()); -} - -uint8_t* iButtonKey::get_data() { - return data; -} - -uint8_t iButtonKey::get_type_data_size() { - return get_type_data_size_by_type(type); -} - -void iButtonKey::set_name(const char* _name) { - strlcpy(name, _name, IBUTTON_KEY_NAME_SIZE); -} - -char* iButtonKey::get_name() { - return name; -} - -void iButtonKey::set_type(iButtonKeyType _key_type) { - type = _key_type; -} - -iButtonKeyType iButtonKey::get_key_type() { - return type; -} - -const char* iButtonKey::get_key_type_string_by_type(iButtonKeyType key_type) { - switch(key_type) { - case iButtonKeyType::KeyCyfral: - return "Cyfral"; - break; - case iButtonKeyType::KeyMetakom: - return "Metakom"; - break; - case iButtonKeyType::KeyDallas: - return "Dallas"; - break; - default: - furi_crash("Invalid iButton type"); - return ""; - break; - } -} - -bool iButtonKey::get_key_type_by_type_string(const char* type_string, iButtonKeyType* key_type) { - if(strcmp(type_string, get_key_type_string_by_type(iButtonKeyType::KeyCyfral)) == 0) { - *key_type = iButtonKeyType::KeyCyfral; - } else if(strcmp(type_string, get_key_type_string_by_type(iButtonKeyType::KeyMetakom)) == 0) { - *key_type = iButtonKeyType::KeyMetakom; - } else if(strcmp(type_string, get_key_type_string_by_type(iButtonKeyType::KeyDallas)) == 0) { - *key_type = iButtonKeyType::KeyDallas; - } else { - return false; - } - - return true; -} - -uint8_t iButtonKey::get_type_data_size_by_type(iButtonKeyType key_type) { - uint8_t size = 0; - - switch(key_type) { - case iButtonKeyType::KeyCyfral: - size = 2; - break; - case iButtonKeyType::KeyMetakom: - size = 4; - break; - case iButtonKeyType::KeyDallas: - size = 8; - break; - } - - return size; -} - -iButtonKey::iButtonKey() { -} diff --git a/applications/ibutton/ibutton_key.h b/applications/ibutton/ibutton_key.h deleted file mode 100644 index 506182fe..00000000 --- a/applications/ibutton/ibutton_key.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include "helpers/key_info.h" - -class iButtonKey { -public: - uint8_t get_size(); - - void set_data(uint8_t* data, uint8_t data_count); - void clear_data(); - uint8_t* get_data(); - uint8_t get_type_data_size(); - - void set_name(const char* name); - char* get_name(); - - void set_type(iButtonKeyType key_type); - iButtonKeyType get_key_type(); - - const char* get_key_type_string_by_type(iButtonKeyType key_type); - bool get_key_type_by_type_string(const char* type_string, iButtonKeyType* key_type); - uint8_t get_type_data_size_by_type(iButtonKeyType key_type); - - iButtonKey(); - -private: - uint8_t data[IBUTTON_KEY_DATA_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0}; - char name[IBUTTON_KEY_NAME_SIZE] = {0}; - - iButtonKeyType type = iButtonKeyType::KeyDallas; -}; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_add_type.cpp b/applications/ibutton/scene/ibutton_scene_add_type.cpp index 0c573f41..aa76d3c0 100644 --- a/applications/ibutton/scene/ibutton_scene_add_type.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_type.cpp @@ -1,7 +1,5 @@ #include "ibutton_scene_add_type.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" #include typedef enum { @@ -10,14 +8,23 @@ typedef enum { SubmenuIndexMetakom, } SubmenuIndex; +static void submenu_callback(void* context, uint32_t index) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeMenuSelected; + event.payload.menu_index = index; + + app->get_view_manager()->send_event(&event); +} + void iButtonSceneAddType::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - auto callback = cbc::obtain_connector(this, &iButtonSceneAddType::submenu_callback); - submenu_add_item(submenu, "Cyfral", SubmenuIndexCyfral, callback, app); - submenu_add_item(submenu, "Dallas", SubmenuIndexDallas, callback, app); - submenu_add_item(submenu, "Metakom", SubmenuIndexMetakom, callback, app); + submenu_add_item(submenu, "Cyfral", SubmenuIndexCyfral, submenu_callback, app); + submenu_add_item(submenu, "Dallas", SubmenuIndexDallas, submenu_callback, app); + submenu_add_item(submenu, "Metakom", SubmenuIndexMetakom, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); @@ -28,19 +35,21 @@ bool iButtonSceneAddType::on_event(iButtonApp* app, iButtonEvent* event) { if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { submenu_item_selected = event->payload.menu_index; + iButtonKey* key = app->get_key(); + switch(event->payload.menu_index) { case SubmenuIndexCyfral: - app->get_key()->set_type(iButtonKeyType::KeyCyfral); + ibutton_key_set_type(key, iButtonKeyCyfral); break; case SubmenuIndexDallas: - app->get_key()->set_type(iButtonKeyType::KeyDallas); + ibutton_key_set_type(key, iButtonKeyDS1990); break; case SubmenuIndexMetakom: - app->get_key()->set_type(iButtonKeyType::KeyMetakom); + ibutton_key_set_type(key, iButtonKeyMetakom); break; } - app->get_key()->set_name(""); - app->get_key()->clear_data(); + ibutton_key_set_name(key, ""); + ibutton_key_clear_data(key); app->switch_to_next_scene(iButtonApp::Scene::SceneAddValue); consumed = true; } @@ -54,13 +63,3 @@ void iButtonSceneAddType::on_exit(iButtonApp* app) { submenu_reset(submenu); } - -void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_add_type.h b/applications/ibutton/scene/ibutton_scene_add_type.h index fd0eb6c1..d49ac128 100644 --- a/applications/ibutton/scene/ibutton_scene_add_type.h +++ b/applications/ibutton/scene/ibutton_scene_add_type.h @@ -8,6 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: - void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_add_value.cpp b/applications/ibutton/scene/ibutton_scene_add_value.cpp index d91408b6..95d5f82f 100755 --- a/applications/ibutton/scene/ibutton_scene_add_value.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_value.cpp @@ -1,17 +1,30 @@ #include "ibutton_scene_add_value.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include #include +static void byte_input_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeByteEditResult; + app->get_view_manager()->send_event(&event); +} + void iButtonSceneAddValue::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); ByteInput* byte_input = view_manager->get_byte_input(); - auto callback = cbc::obtain_connector(this, &iButtonSceneAddValue::byte_input_callback); - memcpy(this->new_key_data, app->get_key()->get_data(), app->get_key()->get_type_data_size()); + iButtonKey* key = app->get_key(); + + memcpy(this->new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)); + byte_input_set_result_callback( - byte_input, callback, NULL, app, this->new_key_data, app->get_key()->get_type_data_size()); + byte_input, + byte_input_callback, + NULL, + app, + this->new_key_data, + ibutton_key_get_data_size(key)); + byte_input_set_header_text(byte_input, "Enter the key"); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewByteInput); @@ -21,6 +34,7 @@ bool iButtonSceneAddValue::on_event(iButtonApp* app, iButtonEvent* event) { bool consumed = false; if(event->type == iButtonEvent::Type::EventTypeByteEditResult) { + ibutton_key_set_data(app->get_key(), this->new_key_data, IBUTTON_KEY_DATA_SIZE); DOLPHIN_DEED(DolphinDeedIbuttonAdd); app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); consumed = true; @@ -35,13 +49,4 @@ void iButtonSceneAddValue::on_exit(iButtonApp* app) { byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_header_text(byte_input, {0}); -} - -void iButtonSceneAddValue::byte_input_callback(void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeByteEditResult; - memcpy(app->get_key()->get_data(), this->new_key_data, app->get_key()->get_type_data_size()); - app->get_view_manager()->send_event(&event); -} +} \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_add_value.h b/applications/ibutton/scene/ibutton_scene_add_value.h index 60efd31e..ff6de577 100644 --- a/applications/ibutton/scene/ibutton_scene_add_value.h +++ b/applications/ibutton/scene/ibutton_scene_add_value.h @@ -1,6 +1,6 @@ #pragma once #include "ibutton_scene_generic.h" -#include "../ibutton_key.h" +#include class iButtonSceneAddValue : public iButtonScene { public: @@ -9,6 +9,5 @@ public: void on_exit(iButtonApp* app) final; private: - void byte_input_callback(void* context); uint8_t new_key_data[IBUTTON_KEY_DATA_SIZE] = {}; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp index e5303d04..91e471df 100755 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp +++ b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp @@ -1,25 +1,31 @@ #include "ibutton_scene_delete_confirm.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include + +static void widget_callback(GuiButtonType result, InputType type, void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + if(type == InputTypeShort) { + event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; + event.payload.widget_button_result = result; + app->get_view_manager()->send_event(&event); + } +} void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Widget* widget = view_manager->get_widget(); - auto callback = cbc::obtain_connector(this, &iButtonSceneDeleteConfirm::widget_callback); - iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); + const uint8_t* key_data = ibutton_key_get_data_p(key); - app->set_text_store("\e#Delete %s?\e#", key->get_name()); + app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); widget_add_text_box_element( widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store()); - widget_add_button_element(widget, GuiButtonTypeLeft, "Back", callback, app); - widget_add_button_element(widget, GuiButtonTypeRight, "Delete", callback, app); + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: app->set_text_store( "%02X %02X %02X %02X %02X %02X %02X %02X", key_data[0], @@ -33,12 +39,12 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) { widget_add_string_element( widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas"); break; - case iButtonKeyType::KeyCyfral: + case iButtonKeyCyfral: app->set_text_store("%02X %02X", key_data[0], key_data[1]); widget_add_string_element( widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); break; - case iButtonKeyType::KeyMetakom: + case iButtonKeyMetakom: app->set_text_store( "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); widget_add_string_element( @@ -77,18 +83,3 @@ void iButtonSceneDeleteConfirm::on_exit(iButtonApp* app) { widget_reset(widget); } - -void iButtonSceneDeleteConfirm::widget_callback( - GuiButtonType result, - InputType type, - void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - if(type == InputTypeShort) { - event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; - event.payload.widget_button_result = result; - } - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.h b/applications/ibutton/scene/ibutton_scene_delete_confirm.h index 017acc53..d82c376d 100644 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.h +++ b/applications/ibutton/scene/ibutton_scene_delete_confirm.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void widget_callback(GuiButtonType result, InputType type, void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_delete_success.cpp b/applications/ibutton/scene/ibutton_scene_delete_success.cpp index b38aa653..e2b64999 100644 --- a/applications/ibutton/scene/ibutton_scene_delete_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_delete_success.cpp @@ -1,19 +1,21 @@ #include "ibutton_scene_delete_success.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" -#include + +static void popup_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + event.type = iButtonEvent::Type::EventTypeBack; + app->get_view_manager()->send_event(&event); +} void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); - auto callback = cbc::obtain_connector(this, &iButtonSceneDeleteSuccess::popup_callback); popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); popup_set_text(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - popup_set_callback(popup, callback); + popup_set_callback(popup, popup_callback); popup_set_context(popup, app); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -41,11 +43,4 @@ void iButtonSceneDeleteSuccess::on_exit(iButtonApp* app) { popup_disable_timeout(popup); popup_set_context(popup, NULL); popup_set_callback(popup, NULL); -} - -void iButtonSceneDeleteSuccess::popup_callback(void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); } \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_delete_success.h b/applications/ibutton/scene/ibutton_scene_delete_success.h index 42be6705..0c17c7ed 100644 --- a/applications/ibutton/scene/ibutton_scene_delete_success.h +++ b/applications/ibutton/scene/ibutton_scene_delete_success.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void popup_callback(void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_emulate.cpp b/applications/ibutton/scene/ibutton_scene_emulate.cpp index 7fe6df28..8f517c78 100644 --- a/applications/ibutton/scene/ibutton_scene_emulate.cpp +++ b/applications/ibutton/scene/ibutton_scene_emulate.cpp @@ -1,17 +1,21 @@ #include "ibutton_scene_emulate.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" #include -#include + +static void emulate_callback(void* context, bool emulated) { + if(emulated) { + iButtonApp* app = static_cast(context); + iButtonEvent event = {.type = iButtonEvent::Type::EventTypeWorkerEmulated}; + app->get_view_manager()->send_event(&event); + } +} void iButtonSceneEmulate::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); - const char* key_name = key->get_name(); + const uint8_t* key_data = ibutton_key_get_data_p(key); + const char* key_name = ibutton_key_get_name_p(key); uint8_t line_count = 2; DOLPHIN_DEED(DolphinDeedIbuttonEmulate); @@ -21,8 +25,8 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { line_count = 2; } else { // if not, show key data - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: app->set_text_store( "emulating\n%02X %02X %02X %02X\n%02X %02X %02X %02X", key_data[0], @@ -35,11 +39,11 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { key_data[7]); line_count = 3; break; - case iButtonKeyType::KeyCyfral: + case iButtonKeyCyfral: app->set_text_store("emulating\n%02X %02X", key_data[0], key_data[1]); line_count = 2; break; - case iButtonKeyType::KeyMetakom: + case iButtonKeyMetakom: app->set_text_store( "emulating\n%02X %02X %02X %02X", key_data[0], @@ -66,29 +70,28 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - app->get_key_worker()->start_emulate(app->get_key()); + + ibutton_worker_emulate_set_callback(app->get_key_worker(), emulate_callback, app); + ibutton_worker_emulate_start(app->get_key_worker(), key); } bool iButtonSceneEmulate::on_event(iButtonApp* app, iButtonEvent* event) { bool consumed = false; - if(event->type == iButtonEvent::Type::EventTypeTick) { + if(event->type == iButtonEvent::Type::EventTypeWorkerEmulated) { + app->notify_yellow_blink(); + consumed = true; + } else if(event->type == iButtonEvent::Type::EventTypeTick) { + app->notify_red_blink(); consumed = true; - if(app->get_key_worker()->emulated()) { - app->notify_yellow_blink(); - } else { - app->notify_red_blink(); - } } return consumed; } void iButtonSceneEmulate::on_exit(iButtonApp* app) { - app->get_key_worker()->stop_emulate(); - Popup* popup = app->get_view_manager()->get_popup(); - + ibutton_worker_stop(app->get_key_worker()); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); diff --git a/applications/ibutton/scene/ibutton_scene_emulate.h b/applications/ibutton/scene/ibutton_scene_emulate.h index 112c13f5..c2bedcc5 100644 --- a/applications/ibutton/scene/ibutton_scene_emulate.h +++ b/applications/ibutton/scene/ibutton_scene_emulate.h @@ -1,6 +1,5 @@ #pragma once #include "ibutton_scene_generic.h" -#include "../helpers/key_emulator.h" class iButtonSceneEmulate : public iButtonScene { public: diff --git a/applications/ibutton/scene/ibutton_scene_info.cpp b/applications/ibutton/scene/ibutton_scene_info.cpp index a05d013f..f4cbd809 100755 --- a/applications/ibutton/scene/ibutton_scene_info.cpp +++ b/applications/ibutton/scene/ibutton_scene_info.cpp @@ -1,24 +1,30 @@ #include "ibutton_scene_info.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include + +static void widget_callback(GuiButtonType result, InputType type, void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + if(type == InputTypeShort) { + event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; + event.payload.widget_button_result = result; + app->get_view_manager()->send_event(&event); + } +} void iButtonSceneInfo::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Widget* widget = view_manager->get_widget(); - auto callback = cbc::obtain_connector(this, &iButtonSceneInfo::widget_callback); - iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); + const uint8_t* key_data = ibutton_key_get_data_p(key); - app->set_text_store("%s", key->get_name()); + app->set_text_store("%s", ibutton_key_get_name_p(key)); widget_add_text_box_element( widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store()); - widget_add_button_element(widget, GuiButtonTypeLeft, "Back", callback, app); + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", widget_callback, app); - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: app->set_text_store( "%02X %02X %02X %02X %02X %02X %02X %02X", key_data[0], @@ -32,13 +38,13 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) { widget_add_string_element( widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas"); break; - case iButtonKeyType::KeyMetakom: + case iButtonKeyMetakom: app->set_text_store( "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); widget_add_string_element( widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom"); break; - case iButtonKeyType::KeyCyfral: + case iButtonKeyCyfral: app->set_text_store("%02X %02X", key_data[0], key_data[1]); widget_add_string_element( widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); @@ -71,15 +77,3 @@ void iButtonSceneInfo::on_exit(iButtonApp* app) { widget_reset(widget); } - -void iButtonSceneInfo::widget_callback(GuiButtonType result, InputType type, void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - if(type == InputTypeShort) { - event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; - event.payload.widget_button_result = result; - } - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_info.h b/applications/ibutton/scene/ibutton_scene_info.h index 6869c1c7..e2c6b2cf 100644 --- a/applications/ibutton/scene/ibutton_scene_info.h +++ b/applications/ibutton/scene/ibutton_scene_info.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void widget_callback(GuiButtonType result, InputType type, void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read.cpp b/applications/ibutton/scene/ibutton_scene_read.cpp index a16cb23d..b5c7ac8f 100644 --- a/applications/ibutton/scene/ibutton_scene_read.cpp +++ b/applications/ibutton/scene/ibutton_scene_read.cpp @@ -1,12 +1,18 @@ #include "ibutton_scene_read.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" #include +static void read_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event = {.type = iButtonEvent::Type::EventTypeWorkerRead}; + app->get_view_manager()->send_event(&event); +} + void iButtonSceneRead::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); + iButtonKey* key = app->get_key(); + iButtonWorker* worker = app->get_key_worker(); DOLPHIN_DEED(DolphinDeedIbuttonRead); popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); @@ -14,41 +20,41 @@ void iButtonSceneRead::on_enter(iButtonApp* app) { popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - app->get_key()->set_name(""); + ibutton_key_set_name(key, ""); - app->get_key_worker()->start_read(); + ibutton_worker_read_set_callback(worker, read_callback, app); + ibutton_worker_read_start(worker, key); } bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) { bool consumed = false; - if(event->type == iButtonEvent::Type::EventTypeTick) { + if(event->type == iButtonEvent::Type::EventTypeWorkerRead) { + consumed = true; + + iButtonKey* key = app->get_key(); + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + if(!ibutton_key_dallas_crc_is_valid(key)) { + app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError); + } else if(!ibutton_key_dallas_is_1990_key(key)) { + app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError); + } else { + app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); + } + } else { + app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); + } + } else if(event->type == iButtonEvent::Type::EventTypeTick) { consumed = true; app->notify_red_blink(); - - switch(app->get_key_worker()->read(app->get_key())) { - case KeyReader::Error::EMPTY: - break; - case KeyReader::Error::OK: - app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); - break; - case KeyReader::Error::CRC_ERROR: - app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError); - break; - case KeyReader::Error::NOT_ARE_KEY: - app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError); - break; - } } return consumed; } void iButtonSceneRead::on_exit(iButtonApp* app) { - app->get_key_worker()->stop_read(); - Popup* popup = app->get_view_manager()->get_popup(); - + ibutton_worker_stop(app->get_key_worker()); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); diff --git a/applications/ibutton/scene/ibutton_scene_read.h b/applications/ibutton/scene/ibutton_scene_read.h index 0b9e9e80..b9fefb0c 100644 --- a/applications/ibutton/scene/ibutton_scene_read.h +++ b/applications/ibutton/scene/ibutton_scene_read.h @@ -6,6 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp b/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp index a52495ea..9d67e442 100644 --- a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp @@ -1,16 +1,21 @@ #include "ibutton_scene_read_crc_error.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include +#include + +static void dialog_ex_callback(DialogExResult result, void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeDialogResult; + event.payload.dialog_result = result; + + app->get_view_manager()->send_event(&event); +} void iButtonSceneReadCRCError::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); - auto callback = cbc::obtain_connector(this, &iButtonSceneReadCRCError::dialog_ex_callback); - - iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); + const uint8_t* key_data = ibutton_key_get_data_p(app->get_key()); app->set_text_store( "%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X", @@ -22,13 +27,13 @@ void iButtonSceneReadCRCError::on_enter(iButtonApp* app) { key_data[5], key_data[6], key_data[7], - maxim_crc8(key_data, 7)); + maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_text(dialog_ex, app->get_text_store(), 64, 19, AlignCenter, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_result_callback(dialog_ex, callback); + dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); dialog_ex_set_context(dialog_ex, app); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); @@ -65,14 +70,4 @@ void iButtonSceneReadCRCError::on_exit(iButtonApp* app) { dialog_ex_set_context(dialog_ex, NULL); app->notify_red_off(); -} - -void iButtonSceneReadCRCError::dialog_ex_callback(DialogExResult result, void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); } \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read_crc_error.h b/applications/ibutton/scene/ibutton_scene_read_crc_error.h index f64adc2c..43a4dfac 100644 --- a/applications/ibutton/scene/ibutton_scene_read_crc_error.h +++ b/applications/ibutton/scene/ibutton_scene_read_crc_error.h @@ -1,13 +1,9 @@ #pragma once #include "ibutton_scene_generic.h" -#include class iButtonSceneReadCRCError : public iButtonScene { public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void dialog_ex_callback(DialogExResult result, void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp b/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp index b9704bed..fab3c3f2 100644 --- a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp @@ -1,16 +1,21 @@ #include "ibutton_scene_read_not_key_error.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include +#include + +static void dialog_ex_callback(DialogExResult result, void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeDialogResult; + event.payload.dialog_result = result; + + app->get_view_manager()->send_event(&event); +} void iButtonSceneReadNotKeyError::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); - auto callback = cbc::obtain_connector(this, &iButtonSceneReadNotKeyError::dialog_ex_callback); - - iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); + const uint8_t* key_data = ibutton_key_get_data_p(app->get_key()); app->set_text_store( "THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X", @@ -22,13 +27,13 @@ void iButtonSceneReadNotKeyError::on_enter(iButtonApp* app) { key_data[5], key_data[6], key_data[7], - maxim_crc8(key_data, 7)); + maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); dialog_ex_set_header(dialog_ex, "ERROR:", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_text(dialog_ex, app->get_text_store(), 64, 19, AlignCenter, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_result_callback(dialog_ex, callback); + dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); dialog_ex_set_context(dialog_ex, app); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); @@ -65,14 +70,4 @@ void iButtonSceneReadNotKeyError::on_exit(iButtonApp* app) { dialog_ex_set_context(dialog_ex, NULL); app->notify_red_off(); -} - -void iButtonSceneReadNotKeyError::dialog_ex_callback(DialogExResult result, void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); } \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read_not_key_error.h b/applications/ibutton/scene/ibutton_scene_read_not_key_error.h index a9a0112a..6643a206 100644 --- a/applications/ibutton/scene/ibutton_scene_read_not_key_error.h +++ b/applications/ibutton/scene/ibutton_scene_read_not_key_error.h @@ -1,13 +1,9 @@ #pragma once #include "ibutton_scene_generic.h" -#include class iButtonSceneReadNotKeyError : public iButtonScene { public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void dialog_ex_callback(DialogExResult result, void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_read_success.cpp b/applications/ibutton/scene/ibutton_scene_read_success.cpp index afeb154f..818f7e38 100644 --- a/applications/ibutton/scene/ibutton_scene_read_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_success.cpp @@ -1,21 +1,26 @@ #include "ibutton_scene_read_success.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" #include -#include + +static void dialog_ex_callback(DialogExResult result, void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeDialogResult; + event.payload.dialog_result = result; + + app->get_view_manager()->send_event(&event); +} void iButtonSceneReadSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); - auto callback = cbc::obtain_connector(this, &iButtonSceneReadSuccess::dialog_ex_callback); + iButtonKey* key = app->get_key(); + const uint8_t* key_data = ibutton_key_get_data_p(key); DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); - iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); - - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: app->set_text_store( "Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X", key_data[0], @@ -27,10 +32,10 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) { key_data[6], key_data[7]); break; - case iButtonKeyType::KeyCyfral: + case iButtonKeyCyfral: app->set_text_store("Cyfral\n%02X %02X", key_data[0], key_data[1]); break; - case iButtonKeyType::KeyMetakom: + case iButtonKeyMetakom: app->set_text_store( "Metakom\n%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); break; @@ -40,7 +45,7 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) { dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinExcited_64x63); - dialog_ex_set_result_callback(dialog_ex, callback); + dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); dialog_ex_set_context(dialog_ex, app); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); @@ -80,13 +85,3 @@ void iButtonSceneReadSuccess::on_exit(iButtonApp* app) { app->notify_green_off(); } - -void iButtonSceneReadSuccess::dialog_ex_callback(DialogExResult result, void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_read_success.h b/applications/ibutton/scene/ibutton_scene_read_success.h index d60dba40..9548d6b4 100644 --- a/applications/ibutton/scene/ibutton_scene_read_success.h +++ b/applications/ibutton/scene/ibutton_scene_read_success.h @@ -1,13 +1,9 @@ #pragma once #include "ibutton_scene_generic.h" -#include class iButtonSceneReadSuccess : public iButtonScene { public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void dialog_ex_callback(DialogExResult result, void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp index c2a9ff0a..63af10ad 100644 --- a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp @@ -1,8 +1,5 @@ #include "ibutton_scene_readed_key_menu.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include typedef enum { SubmenuIndexWrite, @@ -11,17 +8,26 @@ typedef enum { SubmenuIndexReadNewKey, } SubmenuIndex; +static void submenu_callback(void* context, uint32_t index) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeMenuSelected; + event.payload.menu_index = index; + + app->get_view_manager()->send_event(&event); +} + void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - auto callback = cbc::obtain_connector(this, &iButtonSceneReadedKeyMenu::submenu_callback); - if(app->get_key()->get_key_type() == iButtonKeyType::KeyDallas) { - submenu_add_item(submenu, "Write", SubmenuIndexWrite, callback, app); + if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { + submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); } - submenu_add_item(submenu, "Name and save", SubmenuIndexNameAndSave, callback, app); - submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, callback, app); - submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, callback, app); + submenu_add_item(submenu, "Name and save", SubmenuIndexNameAndSave, submenu_callback, app); + submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); + submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); @@ -60,14 +66,4 @@ void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) { Submenu* submenu = view->get_submenu(); submenu_reset(submenu); -} - -void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} +} \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_readed_key_menu.h b/applications/ibutton/scene/ibutton_scene_readed_key_menu.h index fb00111d..caa9ad43 100644 --- a/applications/ibutton/scene/ibutton_scene_readed_key_menu.h +++ b/applications/ibutton/scene/ibutton_scene_readed_key_menu.h @@ -8,6 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: - void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp index 0d5c5900..bde6133d 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_name.cpp @@ -1,18 +1,21 @@ #include "ibutton_scene_save_name.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" -#include #include +static void text_input_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeTextEditResult; + + app->get_view_manager()->send_event(&event); +} + void iButtonSceneSaveName::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); TextInput* text_input = view_manager->get_text_input(); - auto callback = cbc::obtain_connector(this, &iButtonSceneSaveName::text_input_callback); - iButtonKey* key = app->get_key(); - const char* key_name = key->get_name(); + const char* key_name = ibutton_key_get_name_p(app->get_key()); bool key_name_empty = !strcmp(key_name, ""); if(key_name_empty) { @@ -23,7 +26,12 @@ void iButtonSceneSaveName::on_enter(iButtonApp* app) { text_input_set_header_text(text_input, "Name the key"); text_input_set_result_callback( - text_input, callback, app, app->get_text_store(), IBUTTON_KEY_NAME_SIZE, key_name_empty); + text_input, + text_input_callback, + app, + app->get_text_store(), + IBUTTON_KEY_NAME_SIZE, + key_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(app->app_folder, app->app_extension); @@ -59,12 +67,3 @@ void iButtonSceneSaveName::on_exit(iButtonApp* app) { text_input_reset(text_input); } - -void iButtonSceneSaveName::text_input_callback(void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeTextEditResult; - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_save_name.h b/applications/ibutton/scene/ibutton_scene_save_name.h index f0dafb2e..8be593da 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.h +++ b/applications/ibutton/scene/ibutton_scene_save_name.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void text_input_callback(void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_save_success.cpp b/applications/ibutton/scene/ibutton_scene_save_success.cpp index c652e5d1..891b020a 100644 --- a/applications/ibutton/scene/ibutton_scene_save_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_success.cpp @@ -1,21 +1,23 @@ #include "ibutton_scene_save_success.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" #include -#include + +static void popup_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + event.type = iButtonEvent::Type::EventTypeBack; + app->get_view_manager()->send_event(&event); +} void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); - auto callback = cbc::obtain_connector(this, &iButtonSceneSaveSuccess::popup_callback); DOLPHIN_DEED(DolphinDeedIbuttonSave); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_text(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); - popup_set_callback(popup, callback); + popup_set_callback(popup, popup_callback); popup_set_context(popup, app); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -46,11 +48,4 @@ void iButtonSceneSaveSuccess::on_exit(iButtonApp* app) { popup_disable_timeout(popup); popup_set_context(popup, NULL); popup_set_callback(popup, NULL); -} - -void iButtonSceneSaveSuccess::popup_callback(void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); -} +} \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_save_success.h b/applications/ibutton/scene/ibutton_scene_save_success.h index 3f784696..95742bda 100644 --- a/applications/ibutton/scene/ibutton_scene_save_success.h +++ b/applications/ibutton/scene/ibutton_scene_save_success.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void popup_callback(void* context); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp index ee92284f..1d87e85f 100644 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp @@ -1,7 +1,5 @@ #include "ibutton_scene_saved_key_menu.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" #include typedef enum { @@ -12,18 +10,27 @@ typedef enum { SubmenuIndexInfo, } SubmenuIndex; +static void submenu_callback(void* context, uint32_t index) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeMenuSelected; + event.payload.menu_index = index; + + app->get_view_manager()->send_event(&event); +} + void iButtonSceneSavedKeyMenu::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - auto callback = cbc::obtain_connector(this, &iButtonSceneSavedKeyMenu::submenu_callback); - submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, callback, app); - if(app->get_key()->get_key_type() == iButtonKeyType::KeyDallas) { - submenu_add_item(submenu, "Write", SubmenuIndexWrite, callback, app); + submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); + if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { + submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); } - submenu_add_item(submenu, "Edit", SubmenuIndexEdit, callback, app); - submenu_add_item(submenu, "Delete", SubmenuIndexDelete, callback, app); - submenu_add_item(submenu, "Info", SubmenuIndexInfo, callback, app); + submenu_add_item(submenu, "Edit", SubmenuIndexEdit, submenu_callback, app); + submenu_add_item(submenu, "Delete", SubmenuIndexDelete, submenu_callback, app); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); @@ -63,13 +70,3 @@ void iButtonSceneSavedKeyMenu::on_exit(iButtonApp* app) { submenu_reset(submenu); } - -void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.h b/applications/ibutton/scene/ibutton_scene_saved_key_menu.h index 461030d1..399ed1ce 100644 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.h +++ b/applications/ibutton/scene/ibutton_scene_saved_key_menu.h @@ -8,6 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: - void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_select_key.cpp b/applications/ibutton/scene/ibutton_scene_select_key.cpp index a4739852..1f1ece35 100644 --- a/applications/ibutton/scene/ibutton_scene_select_key.cpp +++ b/applications/ibutton/scene/ibutton_scene_select_key.cpp @@ -1,7 +1,5 @@ #include "ibutton_scene_select_key.h" #include "../ibutton_app.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" void iButtonSceneSelectKey::on_enter(iButtonApp* app) { // Process file_select return diff --git a/applications/ibutton/scene/ibutton_scene_start.cpp b/applications/ibutton/scene/ibutton_scene_start.cpp index 9d064aad..2dbe9878 100644 --- a/applications/ibutton/scene/ibutton_scene_start.cpp +++ b/applications/ibutton/scene/ibutton_scene_start.cpp @@ -1,8 +1,5 @@ #include "ibutton_scene_start.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include typedef enum { SubmenuIndexRead, @@ -10,14 +7,23 @@ typedef enum { SubmenuIndexAdd, } SubmenuIndex; +static void submenu_callback(void* context, uint32_t index) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + + event.type = iButtonEvent::Type::EventTypeMenuSelected; + event.payload.menu_index = index; + + app->get_view_manager()->send_event(&event); +} + void iButtonSceneStart::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - auto callback = cbc::obtain_connector(this, &iButtonSceneStart::submenu_callback); - submenu_add_item(submenu, "Read", SubmenuIndexRead, callback, app); - submenu_add_item(submenu, "Saved", SubmenuIndexSaved, callback, app); - submenu_add_item(submenu, "Add manually", SubmenuIndexAdd, callback, app); + submenu_add_item(submenu, "Read", SubmenuIndexRead, submenu_callback, app); + submenu_add_item(submenu, "Saved", SubmenuIndexSaved, submenu_callback, app); + submenu_add_item(submenu, "Add manually", SubmenuIndexAdd, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); @@ -51,13 +57,3 @@ void iButtonSceneStart::on_exit(iButtonApp* app) { submenu_reset(submenu); } - -void iButtonSceneStart::submenu_callback(void* context, uint32_t index) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} diff --git a/applications/ibutton/scene/ibutton_scene_start.h b/applications/ibutton/scene/ibutton_scene_start.h index 2ce9bb43..be1ce79f 100644 --- a/applications/ibutton/scene/ibutton_scene_start.h +++ b/applications/ibutton/scene/ibutton_scene_start.h @@ -8,6 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: - void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_write.cpp b/applications/ibutton/scene/ibutton_scene_write.cpp index 6afb034e..af86a148 100644 --- a/applications/ibutton/scene/ibutton_scene_write.cpp +++ b/applications/ibutton/scene/ibutton_scene_write.cpp @@ -1,15 +1,22 @@ #include "ibutton_scene_write.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" + +static void ibutton_worker_write_cb(void* context, iButtonWorkerWriteResult result) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + event.type = iButtonEvent::Type::EventTypeWorkerWrite; + event.payload.worker_write_result = result; + + app->get_view_manager()->send_event(&event); +} void iButtonSceneWrite::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); iButtonKey* key = app->get_key(); - uint8_t* key_data = key->get_data(); - const char* key_name = key->get_name(); + iButtonWorker* worker = app->get_key_worker(); + const uint8_t* key_data = ibutton_key_get_data_p(key); + const char* key_name = ibutton_key_get_name_p(key); uint8_t line_count = 2; // check that stored key has name @@ -18,8 +25,8 @@ void iButtonSceneWrite::on_enter(iButtonApp* app) { line_count = 2; } else { // if not, show key data - switch(key->get_key_type()) { - case iButtonKeyType::KeyDallas: + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: app->set_text_store( "writing\n%02X %02X %02X %02X\n%02X %02X %02X %02X", key_data[0], @@ -32,11 +39,11 @@ void iButtonSceneWrite::on_enter(iButtonApp* app) { key_data[7]); line_count = 3; break; - case iButtonKeyType::KeyCyfral: + case iButtonKeyCyfral: app->set_text_store("writing\n%02X %02X", key_data[0], key_data[1]); line_count = 2; break; - case iButtonKeyType::KeyMetakom: + case iButtonKeyMetakom: app->set_text_store( "writing\n%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); line_count = 2; @@ -60,27 +67,34 @@ void iButtonSceneWrite::on_enter(iButtonApp* app) { view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - app->get_key_worker()->start_write(); + blink_yellow = false; + ibutton_worker_write_set_callback(worker, ibutton_worker_write_cb, app); + ibutton_worker_write_start(worker, key); } bool iButtonSceneWrite::on_event(iButtonApp* app, iButtonEvent* event) { bool consumed = false; - if(event->type == iButtonEvent::Type::EventTypeTick) { + if(event->type == iButtonEvent::Type::EventTypeWorkerWrite) { consumed = true; - KeyWriter::Error result = app->get_key_worker()->write(app->get_key()); - switch(result) { - case KeyWriter::Error::SAME_KEY: - case KeyWriter::Error::OK: + switch(event->payload.worker_write_result) { + case iButtonWorkerWriteOK: + case iButtonWorkerWriteSameKey: app->switch_to_next_scene(iButtonApp::Scene::SceneWriteSuccess); break; - case KeyWriter::Error::NO_DETECT: - app->notify_red_blink(); + case iButtonWorkerWriteNoDetect: + blink_yellow = false; break; - case KeyWriter::Error::CANNOT_WRITE: + case iButtonWorkerWriteCannotWrite: + blink_yellow = true; + break; + } + } else if(event->type == iButtonEvent::Type::EventTypeTick) { + if(blink_yellow) { app->notify_yellow_blink(); - break; + } else { + app->notify_red_blink(); } } @@ -89,10 +103,8 @@ bool iButtonSceneWrite::on_event(iButtonApp* app, iButtonEvent* event) { void iButtonSceneWrite::on_exit(iButtonApp* app) { Popup* popup = app->get_view_manager()->get_popup(); - + ibutton_worker_stop(app->get_key_worker()); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); - - app->get_key_worker()->stop_write(); } \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_write.h b/applications/ibutton/scene/ibutton_scene_write.h index 98fac375..bd99b377 100644 --- a/applications/ibutton/scene/ibutton_scene_write.h +++ b/applications/ibutton/scene/ibutton_scene_write.h @@ -8,4 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: + bool blink_yellow; }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_write_success.cpp b/applications/ibutton/scene/ibutton_scene_write_success.cpp index 270ad52e..48acaaa4 100644 --- a/applications/ibutton/scene/ibutton_scene_write_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_write_success.cpp @@ -1,19 +1,22 @@ #include "ibutton_scene_write_success.h" #include "../ibutton_app.h" -#include "../ibutton_view_manager.h" -#include "../ibutton_event.h" -#include "../ibutton_key.h" -#include + +static void popup_callback(void* context) { + iButtonApp* app = static_cast(context); + iButtonEvent event; + event.type = iButtonEvent::Type::EventTypeBack; + app->get_view_manager()->send_event(&event); + app->notify_green_off(); +} void iButtonSceneWriteSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); - auto callback = cbc::obtain_connector(this, &iButtonSceneWriteSuccess::popup_callback); popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52); popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom); - popup_set_callback(popup, callback); + popup_set_callback(popup, popup_callback); popup_set_context(popup, app); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -45,12 +48,4 @@ void iButtonSceneWriteSuccess::on_exit(iButtonApp* app) { popup_disable_timeout(popup); popup_set_context(popup, NULL); popup_set_callback(popup, NULL); -} - -void iButtonSceneWriteSuccess::popup_callback(void* context) { - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); - app->notify_green_off(); } \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_write_success.h b/applications/ibutton/scene/ibutton_scene_write_success.h index 693c4353..c6e76885 100644 --- a/applications/ibutton/scene/ibutton_scene_write_success.h +++ b/applications/ibutton/scene/ibutton_scene_write_success.h @@ -6,7 +6,4 @@ public: void on_enter(iButtonApp* app) final; bool on_event(iButtonApp* app, iButtonEvent* event) final; void on_exit(iButtonApp* app) final; - -private: - void popup_callback(void* context); }; \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_delay.c b/firmware/targets/f7/furi_hal/furi_hal_delay.c index 60c9b1c4..064505e4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_delay.c +++ b/firmware/targets/f7/furi_hal/furi_hal_delay.c @@ -4,20 +4,19 @@ #include #define TAG "FuriHalDelay" - -static uint32_t clk_per_microsecond; +uint32_t instructions_per_us; void furi_hal_delay_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; - clk_per_microsecond = SystemCoreClock / 1000000.0f; + instructions_per_us = SystemCoreClock / 1000000.0f; FURI_LOG_I(TAG, "Init OK"); } void delay_us(float microseconds) { uint32_t start = DWT->CYCCNT; - uint32_t time_ticks = microseconds * clk_per_microsecond; + uint32_t time_ticks = microseconds * instructions_per_us; while((DWT->CYCCNT - start) < time_ticks) { }; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index 90ba1edc..fe4fbadc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -3,6 +3,7 @@ #include #include +#include #include @@ -91,16 +92,39 @@ void furi_hal_ibutton_emulate_stop() { } } -void furi_hal_ibutton_start() { +void furi_hal_ibutton_start_drive() { furi_hal_ibutton_pin_high(); hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); } +void furi_hal_ibutton_start_drive_in_isr() { + hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); +} + +void furi_hal_ibutton_start_interrupt() { + furi_hal_ibutton_pin_high(); + hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); +} + +void furi_hal_ibutton_start_interrupt_in_isr() { + hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); + LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); +} + void furi_hal_ibutton_stop() { furi_hal_ibutton_pin_high(); hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } +void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) { + hal_gpio_add_int_callback(&ibutton_gpio, cb, context); +} + +void furi_hal_ibutton_remove_interrupt() { + hal_gpio_remove_int_callback(&ibutton_gpio); +} + void furi_hal_ibutton_pin_low() { hal_gpio_write(&ibutton_gpio, false); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 6efd83a1..02ce7ba3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -23,6 +23,13 @@ typedef struct { FuriHalRfid* furi_hal_rfid = NULL; +#define LFRFID_LL_READ_TIM TIM1 +#define LFRFID_LL_READ_CONFIG_CHANNEL LL_TIM_CHANNEL_CH1 +#define LFRFID_LL_READ_CHANNEL LL_TIM_CHANNEL_CH1N + +#define LFRFID_LL_EMULATE_TIM TIM2 +#define LFRFID_LL_EMULATE_CHANNEL LL_TIM_CHANNEL_CH3 + void furi_hal_rfid_init() { furi_assert(furi_hal_rfid == NULL); furi_hal_rfid = malloc(sizeof(FuriHalRfid)); @@ -72,7 +79,7 @@ void furi_hal_rfid_pins_reset() { void furi_hal_rfid_pins_emulate() { // ibutton low - furi_hal_ibutton_start(); + furi_hal_ibutton_start_drive(); furi_hal_ibutton_pin_low(); // pull pin to timer out @@ -89,7 +96,7 @@ void furi_hal_rfid_pins_emulate() { void furi_hal_rfid_pins_read() { // ibutton low - furi_hal_ibutton_start(); + furi_hal_ibutton_start_drive(); furi_hal_ibutton_pin_low(); // dont pull rfid antenna diff --git a/firmware/targets/furi_hal_include/furi_hal_delay.h b/firmware/targets/furi_hal_include/furi_hal_delay.h index 733097ce..463e0624 100644 --- a/firmware/targets/furi_hal_include/furi_hal_delay.h +++ b/firmware/targets/furi_hal_include/furi_hal_delay.h @@ -11,6 +11,8 @@ extern "C" { #endif +extern uint32_t instructions_per_us; + /** Init DWT */ void furi_hal_delay_init(void); diff --git a/firmware/targets/furi_hal_include/furi_hal_ibutton.h b/firmware/targets/furi_hal_include/furi_hal_ibutton.h index 025fa867..84ef0cd6 100644 --- a/firmware/targets/furi_hal_include/furi_hal_ibutton.h +++ b/firmware/targets/furi_hal_include/furi_hal_ibutton.h @@ -7,6 +7,7 @@ #include #include +#include "furi_hal_gpio.h" #ifdef __cplusplus extern "C" { @@ -26,14 +27,60 @@ void furi_hal_ibutton_emulate_set_next(uint32_t period); void furi_hal_ibutton_emulate_stop(); -void furi_hal_ibutton_start(); +/** + * Sets the pin to normal mode (open collector), and sets it to float + */ +void furi_hal_ibutton_start_drive(); +/** + * Sets the pin to normal mode (open collector), and clears pin EXTI interrupt. + * Used in EXTI interrupt context. + */ +void furi_hal_ibutton_start_drive_in_isr(); + +/** + * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and sets it to float + */ +void furi_hal_ibutton_start_interrupt(); + +/** + * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and clears pin EXTI interrupt. + * Used in EXTI interrupt context. + */ +void furi_hal_ibutton_start_interrupt_in_isr(); + +/** + * Sets the pin to analog mode, and sets it to float + */ void furi_hal_ibutton_stop(); +/** + * Attach interrupt callback to iButton pin + * @param cb callback + * @param context context + */ +void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context); + +/** + * Remove interrupt callback from iButton pin + */ +void furi_hal_ibutton_remove_interrupt(); + +/** + * Sets the pin to low + */ void furi_hal_ibutton_pin_low(); +/** + * Sets the pin to high (float in iButton pin modes) + */ void furi_hal_ibutton_pin_high(); +/** + * Get pin level + * @return true if level is high + * @return false if level is low + */ bool furi_hal_ibutton_pin_get_level(); #ifdef __cplusplus diff --git a/lib/lib.mk b/lib/lib.mk index 5216b0ad..7d221331 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -65,16 +65,6 @@ CFLAGS += -I$(LIB_DIR)/app_scene_template CFLAGS += -I$(LIB_DIR)/fnv1a-hash C_SOURCES += $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c -# onewire library -ONEWIRE_DIR = $(LIB_DIR)/onewire -CFLAGS += -I$(ONEWIRE_DIR) -CPP_SOURCES += $(wildcard $(ONEWIRE_DIR)/*.cpp) - -# cyfral library -CYFRAL_DIR = $(LIB_DIR)/cyfral -CFLAGS += -I$(CYFRAL_DIR) -CPP_SOURCES += $(wildcard $(CYFRAL_DIR)/*.cpp) - # common apps api CFLAGS += -I$(LIB_DIR)/common-api @@ -128,3 +118,8 @@ C_SOURCES += $(wildcard $(LIB_DIR)/flipper_format/*.c) # Micro-ECC CFLAGS += -I$(LIB_DIR)/micro-ecc C_SOURCES += $(wildcard $(LIB_DIR)/micro-ecc/*.c) + +# iButton and OneWire +C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*.c) +C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*/*.c) +C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*/*/*.c) diff --git a/lib/one_wire/ibutton/encoder/encoder_cyfral.c b/lib/one_wire/ibutton/encoder/encoder_cyfral.c new file mode 100644 index 00000000..717bf898 --- /dev/null +++ b/lib/one_wire/ibutton/encoder/encoder_cyfral.c @@ -0,0 +1,126 @@ +#include "encoder_cyfral.h" +#include + +#define CYFRAL_DATA_SIZE sizeof(uint16_t) +#define CYFRAL_PERIOD (125 * instructions_per_us) +#define CYFRAL_0_LOW (CYFRAL_PERIOD * 0.66f) +#define CYFRAL_0_HI (CYFRAL_PERIOD * 0.33f) +#define CYFRAL_1_LOW (CYFRAL_PERIOD * 0.33f) +#define CYFRAL_1_HI (CYFRAL_PERIOD * 0.66f) + +#define CYFRAL_SET_DATA(level, len) \ + *polarity = level; \ + *length = len; + +struct EncoderCyfral { + uint32_t data; + uint32_t index; +}; + +EncoderCyfral* encoder_cyfral_alloc() { + EncoderCyfral* cyfral = malloc(sizeof(EncoderCyfral)); + encoder_cyfral_reset(cyfral); + return cyfral; +} + +void encoder_cyfral_free(EncoderCyfral* cyfral) { + free(cyfral); +} + +void encoder_cyfral_reset(EncoderCyfral* cyfral) { + cyfral->data = 0; + cyfral->index = 0; +} + +uint32_t cyfral_encoder_encode(const uint16_t data) { + uint32_t value = 0; + for(int8_t i = 0; i <= 7; i++) { + switch((data >> (i * 2)) & 0b00000011) { + case 0b11: + value = value << 4; + value += 0b00000111; + break; + case 0b10: + value = value << 4; + value += 0b00001011; + break; + case 0b01: + value = value << 4; + value += 0b00001101; + break; + case 0b00: + value = value << 4; + value += 0b00001110; + break; + default: + break; + } + } + + return value; +} + +void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size) { + furi_assert(cyfral); + furi_check(data_size >= CYFRAL_DATA_SIZE); + uint16_t intermediate; + memcpy(&intermediate, data, CYFRAL_DATA_SIZE); + cyfral->data = cyfral_encoder_encode(intermediate); +} + +void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length) { + if(cyfral->index < 8) { + // start word (0b0001) + switch(cyfral->index) { + case 0: + CYFRAL_SET_DATA(false, CYFRAL_0_LOW); + break; + case 1: + CYFRAL_SET_DATA(true, CYFRAL_0_HI); + break; + case 2: + CYFRAL_SET_DATA(false, CYFRAL_0_LOW); + break; + case 3: + CYFRAL_SET_DATA(true, CYFRAL_0_HI); + break; + case 4: + CYFRAL_SET_DATA(false, CYFRAL_0_LOW); + break; + case 5: + CYFRAL_SET_DATA(true, CYFRAL_0_HI); + break; + case 6: + CYFRAL_SET_DATA(false, CYFRAL_1_LOW); + break; + case 7: + CYFRAL_SET_DATA(true, CYFRAL_1_HI); + break; + } + } else { + // data + uint8_t data_start_index = cyfral->index - 8; + bool clock_polarity = (data_start_index) % 2; + uint8_t bit_index = (data_start_index) / 2; + bool bit_value = ((cyfral->data >> bit_index) & 1); + + if(!clock_polarity) { + if(bit_value) { + CYFRAL_SET_DATA(false, CYFRAL_1_LOW); + } else { + CYFRAL_SET_DATA(false, CYFRAL_0_LOW); + } + } else { + if(bit_value) { + CYFRAL_SET_DATA(true, CYFRAL_1_HI); + } else { + CYFRAL_SET_DATA(true, CYFRAL_0_HI); + } + } + } + + cyfral->index++; + if(cyfral->index >= (9 * 4 * 2)) { + cyfral->index = 0; + } +} diff --git a/lib/one_wire/ibutton/encoder/encoder_cyfral.h b/lib/one_wire/ibutton/encoder/encoder_cyfral.h new file mode 100644 index 00000000..1b0c3e12 --- /dev/null +++ b/lib/one_wire/ibutton/encoder/encoder_cyfral.h @@ -0,0 +1,54 @@ +/** + * @file encoder_cyfral.h + * + * Cyfral pulse format encoder + */ + +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct EncoderCyfral EncoderCyfral; + +/** + * Allocate Cyfral encoder + * @return EncoderCyfral* + */ +EncoderCyfral* encoder_cyfral_alloc(); + +/** + * Deallocate Cyfral encoder + * @param cyfral + */ +void encoder_cyfral_free(EncoderCyfral* cyfral); + +/** + * Reset Cyfral encoder + * @param cyfral + */ +void encoder_cyfral_reset(EncoderCyfral* cyfral); + +/** + * Set data to be encoded to Cyfral pulse format, 2 bytes + * @param cyfral + * @param data + * @param data_size + */ +void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size); + +/** + * Pop pulse from Cyfral encoder + * @param cyfral + * @param polarity + * @param length + */ +void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/encoder/encoder_metakom.c b/lib/one_wire/ibutton/encoder/encoder_metakom.c new file mode 100644 index 00000000..ea2a28f0 --- /dev/null +++ b/lib/one_wire/ibutton/encoder/encoder_metakom.c @@ -0,0 +1,93 @@ +#include "encoder_metakom.h" +#include + +#define METAKOM_DATA_SIZE sizeof(uint32_t) +#define METAKOM_PERIOD (125 * instructions_per_us) +#define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f) +#define METAKOM_0_HI (METAKOM_PERIOD * 0.66f) +#define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f) +#define METAKOM_1_HI (METAKOM_PERIOD * 0.33f) + +#define METAKOM_SET_DATA(level, len) \ + *polarity = !level; \ + *length = len; + +struct EncoderMetakom { + uint32_t data; + uint32_t index; +}; + +EncoderMetakom* encoder_metakom_alloc() { + EncoderMetakom* metakom = malloc(sizeof(EncoderMetakom)); + encoder_metakom_reset(metakom); + return metakom; +} + +void encoder_metakom_free(EncoderMetakom* metakom) { + free(metakom); +} + +void encoder_metakom_reset(EncoderMetakom* metakom) { + metakom->data = 0; + metakom->index = 0; +} + +void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size) { + furi_assert(metakom); + furi_check(data_size >= METAKOM_DATA_SIZE); + memcpy(&metakom->data, data, METAKOM_DATA_SIZE); +} + +void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length) { + if(metakom->index == 0) { + // sync bit + METAKOM_SET_DATA(true, METAKOM_PERIOD); + } else if(metakom->index >= 1 && metakom->index <= 6) { + // start word (0b010) + switch(metakom->index) { + case 1: + METAKOM_SET_DATA(false, METAKOM_0_LOW); + break; + case 2: + METAKOM_SET_DATA(true, METAKOM_0_HI); + break; + case 3: + METAKOM_SET_DATA(false, METAKOM_1_LOW); + break; + case 4: + METAKOM_SET_DATA(true, METAKOM_1_HI); + break; + case 5: + METAKOM_SET_DATA(false, METAKOM_0_LOW); + break; + case 6: + METAKOM_SET_DATA(true, METAKOM_0_HI); + break; + } + } else { + // data + uint8_t data_start_index = metakom->index - 7; + bool clock_polarity = (data_start_index) % 2; + uint8_t bit_index = (data_start_index) / 2; + bool bit_value = (metakom->data >> (32 - 1 - bit_index)) & 1; + + if(!clock_polarity) { + if(bit_value) { + METAKOM_SET_DATA(false, METAKOM_1_LOW); + } else { + METAKOM_SET_DATA(false, METAKOM_0_LOW); + } + } else { + if(bit_value) { + METAKOM_SET_DATA(true, METAKOM_1_HI); + } else { + METAKOM_SET_DATA(true, METAKOM_0_HI); + } + } + } + + metakom->index++; + if(metakom->index >= (1 + 3 * 2 + 32 * 2)) { + metakom->index = 0; + } +} diff --git a/lib/one_wire/ibutton/encoder/encoder_metakom.h b/lib/one_wire/ibutton/encoder/encoder_metakom.h new file mode 100644 index 00000000..2812dc12 --- /dev/null +++ b/lib/one_wire/ibutton/encoder/encoder_metakom.h @@ -0,0 +1,54 @@ +/** + * @file encoder_metakom.h + * + * Metakom pulse format encoder + */ + +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct EncoderMetakom EncoderMetakom; + +/** + * Allocate Metakom encoder + * @return EncoderMetakom* + */ +EncoderMetakom* encoder_metakom_alloc(); + +/** + * Deallocate Metakom encoder + * @param metakom + */ +void encoder_metakom_free(EncoderMetakom* metakom); + +/** + * Reset Metakom encoder + * @param metakom + */ +void encoder_metakom_reset(EncoderMetakom* metakom); + +/** + * Set data to be encoded to Metakom pulse format, 4 bytes + * @param metakom + * @param data + * @param data_size + */ +void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size); + +/** + * Pop pulse from Metakom encoder + * @param cyfral + * @param polarity + * @param length + */ +void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_key.c b/lib/one_wire/ibutton/ibutton_key.c new file mode 100644 index 00000000..c90d5f4a --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_key.c @@ -0,0 +1,121 @@ +#include +#include +#include "ibutton_key.h" + +struct iButtonKey { + uint8_t data[IBUTTON_KEY_DATA_SIZE]; + char name[IBUTTON_KEY_NAME_SIZE]; + iButtonKeyType type; +}; + +iButtonKey* ibutton_key_alloc() { + iButtonKey* key = malloc(sizeof(iButtonKey)); + memset(key, 0, sizeof(iButtonKey)); + return key; +} + +void ibutton_key_free(iButtonKey* key) { + free(key); +} + +void ibutton_key_set(iButtonKey* to, const iButtonKey* from) { + memcpy(to, from, sizeof(iButtonKey)); +} + +void ibutton_key_set_data(iButtonKey* key, uint8_t* data, uint8_t data_count) { + furi_check(data_count > 0); + furi_check(data_count <= IBUTTON_KEY_DATA_SIZE); + + memset(key->data, 0, IBUTTON_KEY_DATA_SIZE); + memcpy(key->data, data, data_count); +} + +void ibutton_key_clear_data(iButtonKey* key) { + memset(key->data, 0, IBUTTON_KEY_DATA_SIZE); +} + +const uint8_t* ibutton_key_get_data_p(iButtonKey* key) { + return key->data; +} + +uint8_t ibutton_key_get_data_size(iButtonKey* key) { + return ibutton_key_get_size_by_type(key->type); +} + +void ibutton_key_set_name(iButtonKey* key, const char* name) { + strlcpy(key->name, name, IBUTTON_KEY_NAME_SIZE); +} + +const char* ibutton_key_get_name_p(iButtonKey* key) { + return key->name; +} + +void ibutton_key_set_type(iButtonKey* key, iButtonKeyType key_type) { + key->type = key_type; +} + +iButtonKeyType ibutton_key_get_type(iButtonKey* key) { + return key->type; +} + +const char* ibutton_key_get_string_by_type(iButtonKeyType key_type) { + switch(key_type) { + case iButtonKeyCyfral: + return "Cyfral"; + break; + case iButtonKeyMetakom: + return "Metakom"; + break; + case iButtonKeyDS1990: + return "Dallas"; + break; + default: + furi_crash("Invalid iButton type"); + return ""; + break; + } +} + +bool ibutton_key_get_type_by_string(const char* type_string, iButtonKeyType* key_type) { + if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyCyfral)) == 0) { + *key_type = iButtonKeyCyfral; + } else if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyMetakom)) == 0) { + *key_type = iButtonKeyMetakom; + } else if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyDS1990)) == 0) { + *key_type = iButtonKeyDS1990; + } else { + return false; + } + + return true; +} + +uint8_t ibutton_key_get_size_by_type(iButtonKeyType key_type) { + uint8_t size = 0; + + switch(key_type) { + case iButtonKeyCyfral: + size = 2; + break; + case iButtonKeyMetakom: + size = 4; + break; + case iButtonKeyDS1990: + size = 8; + break; + } + + return size; +} + +uint8_t ibutton_key_get_max_size() { + return IBUTTON_KEY_DATA_SIZE; +} + +bool ibutton_key_dallas_crc_is_valid(iButtonKey* key) { + return (maxim_crc8(key->data, 8, MAXIM_CRC8_INIT) == 0); +} + +bool ibutton_key_dallas_is_1990_key(iButtonKey* key) { + return (key->data[0] == 0x01); +} \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_key.h b/lib/one_wire/ibutton/ibutton_key.h new file mode 100644 index 00000000..f8286103 --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_key.h @@ -0,0 +1,145 @@ +/** + * @file ibutton_key.h + * + * iButton key data holder + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define IBUTTON_KEY_DATA_SIZE 8 +#define IBUTTON_KEY_NAME_SIZE 22 + +typedef enum { + iButtonKeyDS1990, + iButtonKeyCyfral, + iButtonKeyMetakom, +} iButtonKeyType; + +typedef struct iButtonKey iButtonKey; + +/** + * Allocate key + * @return iButtonKey* + */ +iButtonKey* ibutton_key_alloc(); + +/** + * Free key + * @param key + */ +void ibutton_key_free(iButtonKey* key); + +/** + * Copy key + * @param to + * @param from + */ +void ibutton_key_set(iButtonKey* to, const iButtonKey* from); + +/** + * Set key data + * @param key + * @param data + * @param data_count + */ +void ibutton_key_set_data(iButtonKey* key, uint8_t* data, uint8_t data_count); + +/** + * Clear key data + * @param key + */ +void ibutton_key_clear_data(iButtonKey* key); + +/** + * Get pointer to key data + * @param key + * @return const uint8_t* + */ +const uint8_t* ibutton_key_get_data_p(iButtonKey* key); + +/** + * Get key data size + * @param key + * @return uint8_t + */ +uint8_t ibutton_key_get_data_size(iButtonKey* key); + +/** + * Set key name + * @param key + * @param name + */ +void ibutton_key_set_name(iButtonKey* key, const char* name); + +/** + * Get pointer to key name + * @param key + * @return const char* + */ +const char* ibutton_key_get_name_p(iButtonKey* key); + +/** + * Set key type + * @param key + * @param key_type + */ +void ibutton_key_set_type(iButtonKey* key, iButtonKeyType key_type); + +/** + * Get key type + * @param key + * @return iButtonKeyType + */ +iButtonKeyType ibutton_key_get_type(iButtonKey* key); + +/** + * Get type string from key type + * @param key_type + * @return const char* + */ +const char* ibutton_key_get_string_by_type(iButtonKeyType key_type); + +/** + * Get key type from string + * @param type_string + * @param key_type + * @return bool + */ +bool ibutton_key_get_type_by_string(const char* type_string, iButtonKeyType* key_type); + +/** + * Get key data size from type + * @param key_type + * @return uint8_t + */ +uint8_t ibutton_key_get_size_by_type(iButtonKeyType key_type); + +/** + * Get max key size + * @return uint8_t + */ +uint8_t ibutton_key_get_max_size(); + +/** + * Check if CRC for onewire key is valid + * @param key + * @return true + * @return false + */ +bool ibutton_key_dallas_crc_is_valid(iButtonKey* key); + +/** + * Check if onewire key is a DS1990 key + * @param key + * @return true + * @return false + */ +bool ibutton_key_dallas_is_1990_key(iButtonKey* key); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_key_command.h b/lib/one_wire/ibutton/ibutton_key_command.h new file mode 100644 index 00000000..3978ea51 --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_key_command.h @@ -0,0 +1,28 @@ +/** + * @file ibutton_key_command.h + * + * List of misc commands for Dallas and blanks + */ + +#pragma once + +#define RW1990_1_CMD_WRITE_RECORD_FLAG 0xD1 +#define RW1990_1_CMD_READ_RECORD_FLAG 0xB5 +#define RW1990_1_CMD_WRITE_ROM 0xD5 + +#define RW1990_2_CMD_WRITE_RECORD_FLAG 0x1D +#define RW1990_2_CMD_READ_RECORD_FLAG 0x1E +#define RW1990_2_CMD_WRITE_ROM 0xD5 + +#define TM2004_CMD_READ_STATUS 0xAA +#define TM2004_CMD_READ_MEMORY 0xF0 +#define TM2004_CMD_WRITE_ROM 0x3C +#define TM2004_CMD_FINALIZATION 0x35 +#define TM2004_ANSWER_READ_MEMORY 0xF5 + +#define TM01_CMD_WRITE_RECORD_FLAG 0xC1 +#define TM01_CMD_WRITE_ROM 0xC5 +#define TM01_CMD_SWITCH_TO_CYFRAL 0xCA +#define TM01_CMD_SWITCH_TO_METAKOM 0xCB + +#define DS1990_CMD_READ_ROM 0x33 \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_worker.c b/lib/one_wire/ibutton/ibutton_worker.c new file mode 100644 index 00000000..74734e75 --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_worker.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include "ibutton_worker_i.h" + +typedef enum { + iButtonMessageEnd, + iButtonMessageStop, + iButtonMessageRead, + iButtonMessageWrite, + iButtonMessageEmulate, +} iButtonMessageType; + +typedef struct { + iButtonMessageType type; + union { + iButtonKey* key; + } data; +} iButtonMessage; + +static int32_t ibutton_worker_thread(void* thread_context); + +iButtonWorker* ibutton_worker_alloc() { + iButtonWorker* worker = malloc(sizeof(iButtonWorker)); + worker->key_p = NULL; + worker->key_data = malloc(ibutton_key_get_max_size()); + worker->host = onewire_host_alloc(); + worker->slave = onewire_slave_alloc(); + worker->writer = ibutton_writer_alloc(worker->host); + worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0); + worker->pulse_decoder = pulse_decoder_alloc(); + worker->protocol_cyfral = protocol_cyfral_alloc(); + worker->protocol_metakom = protocol_metakom_alloc(); + worker->messages = osMessageQueueNew(1, sizeof(iButtonMessage), NULL); + worker->mode_index = iButtonWorkerIdle; + worker->last_dwt_value = 0; + worker->read_cb = NULL; + worker->write_cb = NULL; + worker->emulate_cb = NULL; + worker->cb_ctx = NULL; + + worker->encoder_cyfral = encoder_cyfral_alloc(); + worker->encoder_metakom = encoder_metakom_alloc(); + + worker->thread = furi_thread_alloc(); + furi_thread_set_name(worker->thread, "ibutton_worker"); + furi_thread_set_callback(worker->thread, ibutton_worker_thread); + furi_thread_set_context(worker->thread, worker); + furi_thread_set_stack_size(worker->thread, 2048); + + pulse_decoder_add_protocol( + worker->pulse_decoder, + protocol_cyfral_get_protocol(worker->protocol_cyfral), + PulseProtocolCyfral); + pulse_decoder_add_protocol( + worker->pulse_decoder, + protocol_metakom_get_protocol(worker->protocol_metakom), + PulseProtocolMetakom); + + return worker; +} + +void ibutton_worker_read_set_callback( + iButtonWorker* worker, + iButtonWorkerReadCallback callback, + void* context) { + furi_check(worker->mode_index == iButtonWorkerIdle); + worker->read_cb = callback; + worker->cb_ctx = context; +} + +void ibutton_worker_write_set_callback( + iButtonWorker* worker, + iButtonWorkerWriteCallback callback, + void* context) { + furi_check(worker->mode_index == iButtonWorkerIdle); + worker->write_cb = callback; + worker->cb_ctx = context; +} + +void ibutton_worker_emulate_set_callback( + iButtonWorker* worker, + iButtonWorkerEmulateCallback callback, + void* context) { + furi_check(worker->mode_index == iButtonWorkerIdle); + worker->emulate_cb = callback; + worker->cb_ctx = context; +} + +void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key) { + iButtonMessage message = {.type = iButtonMessageRead, .data.key = key}; + furi_check(osMessageQueuePut(worker->messages, &message, 0, osWaitForever) == osOK); +} + +void ibutton_worker_write_start(iButtonWorker* worker, iButtonKey* key) { + iButtonMessage message = {.type = iButtonMessageWrite, .data.key = key}; + furi_check(osMessageQueuePut(worker->messages, &message, 0, osWaitForever) == osOK); +} + +void ibutton_worker_emulate_start(iButtonWorker* worker, iButtonKey* key) { + iButtonMessage message = {.type = iButtonMessageEmulate, .data.key = key}; + furi_check(osMessageQueuePut(worker->messages, &message, 0, osWaitForever) == osOK); +} + +void ibutton_worker_stop(iButtonWorker* worker) { + iButtonMessage message = {.type = iButtonMessageStop}; + furi_check(osMessageQueuePut(worker->messages, &message, 0, osWaitForever) == osOK); +} + +void ibutton_worker_free(iButtonWorker* worker) { + pulse_decoder_free(worker->pulse_decoder); + protocol_metakom_free(worker->protocol_metakom); + protocol_cyfral_free(worker->protocol_cyfral); + + ibutton_writer_free(worker->writer); + + onewire_slave_free(worker->slave); + + onewire_host_free(worker->host); + onewire_device_free(worker->device); + + encoder_cyfral_free(worker->encoder_cyfral); + encoder_metakom_free(worker->encoder_metakom); + + osMessageQueueDelete(worker->messages); + + furi_thread_free(worker->thread); + free(worker->key_data); + free(worker); +} + +void ibutton_worker_start_thread(iButtonWorker* worker) { + furi_thread_start(worker->thread); +} + +void ibutton_worker_stop_thread(iButtonWorker* worker) { + iButtonMessage message = {.type = iButtonMessageEnd}; + furi_check(osMessageQueuePut(worker->messages, &message, 0, osWaitForever) == osOK); + furi_thread_join(worker->thread); +} + +void ibutton_worker_switch_mode(iButtonWorker* worker, iButtonWorkerMode mode) { + ibutton_worker_modes[worker->mode_index].stop(worker); + worker->mode_index = mode; + ibutton_worker_modes[worker->mode_index].start(worker); +} + +void ibutton_worker_set_key_p(iButtonWorker* worker, iButtonKey* key) { + worker->key_p = key; +} + +static int32_t ibutton_worker_thread(void* thread_context) { + iButtonWorker* worker = thread_context; + bool running = true; + iButtonMessage message; + osStatus_t status; + + ibutton_worker_modes[worker->mode_index].start(worker); + + while(running) { + status = osMessageQueueGet( + worker->messages, &message, NULL, ibutton_worker_modes[worker->mode_index].quant); + if(status == osOK) { + switch(message.type) { + case iButtonMessageEnd: + ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + ibutton_worker_set_key_p(worker, NULL); + running = false; + break; + case iButtonMessageStop: + ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + ibutton_worker_set_key_p(worker, NULL); + break; + case iButtonMessageRead: + ibutton_worker_set_key_p(worker, message.data.key); + ibutton_worker_switch_mode(worker, iButtonWorkerRead); + break; + case iButtonMessageWrite: + ibutton_worker_set_key_p(worker, message.data.key); + ibutton_worker_switch_mode(worker, iButtonWorkerWrite); + break; + case iButtonMessageEmulate: + ibutton_worker_set_key_p(worker, message.data.key); + ibutton_worker_switch_mode(worker, iButtonWorkerEmulate); + break; + } + } else if(status == osErrorTimeout) { + ibutton_worker_modes[worker->mode_index].tick(worker); + } else { + furi_crash("iButton worker error"); + } + } + + ibutton_worker_modes[worker->mode_index].stop(worker); + + return 0; +} diff --git a/lib/one_wire/ibutton/ibutton_worker.h b/lib/one_wire/ibutton/ibutton_worker.h new file mode 100644 index 00000000..3350e05f --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_worker.h @@ -0,0 +1,113 @@ +/** + * @file ibutton_worker.h + * + * iButton worker + */ + +#pragma once +#include "ibutton_key.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + iButtonWorkerWriteOK, + iButtonWorkerWriteSameKey, + iButtonWorkerWriteNoDetect, + iButtonWorkerWriteCannotWrite, +} iButtonWorkerWriteResult; + +typedef void (*iButtonWorkerReadCallback)(void* context); +typedef void (*iButtonWorkerWriteCallback)(void* context, iButtonWorkerWriteResult result); +typedef void (*iButtonWorkerEmulateCallback)(void* context, bool emulated); + +typedef struct iButtonWorker iButtonWorker; + +/** + * Allocate ibutton worker + * @return iButtonWorker* + */ +iButtonWorker* ibutton_worker_alloc(); + +/** + * Free ibutton worker + * @param worker + */ +void ibutton_worker_free(iButtonWorker* worker); + +/** + * Start ibutton worker thread + * @param worker + */ +void ibutton_worker_start_thread(iButtonWorker* worker); + +/** + * Stop ibutton worker thread + * @param worker + */ +void ibutton_worker_stop_thread(iButtonWorker* worker); + +/** + * Set "read success" callback + * @param worker + * @param callback + * @param context + */ +void ibutton_worker_read_set_callback( + iButtonWorker* worker, + iButtonWorkerReadCallback callback, + void* context); + +/** + * Start read mode + * @param worker + * @param key + */ +void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key); + +/** + * Set "write event" callback + * @param worker + * @param callback + * @param context + */ +void ibutton_worker_write_set_callback( + iButtonWorker* worker, + iButtonWorkerWriteCallback callback, + void* context); + +/** + * Start write mode + * @param worker + * @param key + */ +void ibutton_worker_write_start(iButtonWorker* worker, iButtonKey* key); + +/** + * Set "emulate success" callback + * @param worker + * @param callback + * @param context + */ +void ibutton_worker_emulate_set_callback( + iButtonWorker* worker, + iButtonWorkerEmulateCallback callback, + void* context); + +/** + * Start emulate mode + * @param worker + * @param key + */ +void ibutton_worker_emulate_start(iButtonWorker* worker, iButtonKey* key); + +/** + * Stop all modes + * @param worker + */ +void ibutton_worker_stop(iButtonWorker* worker); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_worker_i.h b/lib/one_wire/ibutton/ibutton_worker_i.h new file mode 100644 index 00000000..14e5d39d --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_worker_i.h @@ -0,0 +1,79 @@ +/** + * @file ibutton_worker_i.h + * + * iButton worker, internal definitions + */ + +#pragma once +#include "ibutton_worker.h" +#include "ibutton_writer.h" +#include "../one_wire_host.h" +#include "../one_wire_slave.h" +#include "../one_wire_device.h" +#include "../pulse_protocols/pulse_decoder.h" +#include "pulse_protocols/protocol_cyfral.h" +#include "pulse_protocols/protocol_metakom.h" +#include "encoder/encoder_cyfral.h" +#include "encoder/encoder_metakom.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PulseProtocolCyfral, + PulseProtocolMetakom, +} PulseProtocols; + +typedef struct { + const uint32_t quant; + const void (*start)(iButtonWorker* worker); + const void (*tick)(iButtonWorker* worker); + const void (*stop)(iButtonWorker* worker); +} iButtonWorkerModeType; + +typedef enum { + iButtonWorkerIdle = 0, + iButtonWorkerRead = 1, + iButtonWorkerWrite = 2, + iButtonWorkerEmulate = 3, +} iButtonWorkerMode; + +typedef enum { + iButtonEmulateModeCyfral, + iButtonEmulateModeMetakom, +} iButtonEmulateMode; + +struct iButtonWorker { + iButtonKey* key_p; + uint8_t* key_data; + OneWireHost* host; + OneWireSlave* slave; + OneWireDevice* device; + iButtonWriter* writer; + iButtonWorkerMode mode_index; + osMessageQueueId_t messages; + FuriThread* thread; + + PulseDecoder* pulse_decoder; + ProtocolCyfral* protocol_cyfral; + ProtocolMetakom* protocol_metakom; + uint32_t last_dwt_value; + + iButtonWorkerReadCallback read_cb; + iButtonWorkerWriteCallback write_cb; + iButtonWorkerEmulateCallback emulate_cb; + void* cb_ctx; + + EncoderCyfral* encoder_cyfral; + EncoderMetakom* encoder_metakom; + iButtonEmulateMode emulate_mode; +}; + +extern const iButtonWorkerModeType ibutton_worker_modes[]; + +void ibutton_worker_switch_mode(iButtonWorker* worker, iButtonWorkerMode mode); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_worker_modes.c b/lib/one_wire/ibutton/ibutton_worker_modes.c new file mode 100644 index 00000000..4de1108f --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_worker_modes.c @@ -0,0 +1,330 @@ +#include +#include +#include "ibutton_worker_i.h" +#include "ibutton_key_command.h" + +void ibutton_worker_mode_idle_start(iButtonWorker* worker); +void ibutton_worker_mode_idle_tick(iButtonWorker* worker); +void ibutton_worker_mode_idle_stop(iButtonWorker* worker); + +void ibutton_worker_mode_emulate_start(iButtonWorker* worker); +void ibutton_worker_mode_emulate_tick(iButtonWorker* worker); +void ibutton_worker_mode_emulate_stop(iButtonWorker* worker); + +void ibutton_worker_mode_read_start(iButtonWorker* worker); +void ibutton_worker_mode_read_tick(iButtonWorker* worker); +void ibutton_worker_mode_read_stop(iButtonWorker* worker); + +void ibutton_worker_mode_write_start(iButtonWorker* worker); +void ibutton_worker_mode_write_tick(iButtonWorker* worker); +void ibutton_worker_mode_write_stop(iButtonWorker* worker); + +const iButtonWorkerModeType ibutton_worker_modes[] = { + { + .quant = osWaitForever, + .start = ibutton_worker_mode_idle_start, + .tick = ibutton_worker_mode_idle_tick, + .stop = ibutton_worker_mode_idle_stop, + }, + { + .quant = 100, + .start = ibutton_worker_mode_read_start, + .tick = ibutton_worker_mode_read_tick, + .stop = ibutton_worker_mode_read_stop, + }, + { + .quant = 1000, + .start = ibutton_worker_mode_write_start, + .tick = ibutton_worker_mode_write_tick, + .stop = ibutton_worker_mode_write_stop, + }, + { + .quant = 1000, + .start = ibutton_worker_mode_emulate_start, + .tick = ibutton_worker_mode_emulate_tick, + .stop = ibutton_worker_mode_emulate_stop, + }, +}; + +/*********************** IDLE ***********************/ + +void ibutton_worker_mode_idle_start(iButtonWorker* worker) { +} + +void ibutton_worker_mode_idle_tick(iButtonWorker* worker) { +} + +void ibutton_worker_mode_idle_stop(iButtonWorker* worker) { +} + +/*********************** READ ***********************/ + +void ibutton_worker_comparator_callback(bool level, void* context) { + iButtonWorker* worker = context; + + uint32_t current_dwt_value = DWT->CYCCNT; + + pulse_decoder_process_pulse( + worker->pulse_decoder, level, current_dwt_value - worker->last_dwt_value); + + worker->last_dwt_value = current_dwt_value; +} + +bool ibutton_worker_read_comparator(iButtonWorker* worker) { + bool result = false; + + pulse_decoder_reset(worker->pulse_decoder); + + furi_hal_rfid_pins_reset(); + // pulldown pull pin, we sense the signal through the analog part of the RFID schematic + furi_hal_rfid_pin_pull_pulldown(); + furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, worker); + worker->last_dwt_value = DWT->CYCCNT; + furi_hal_rfid_comp_start(); + + // TODO: rework with thread events, "pulse_decoder_get_decoded_index_with_timeout" + delay(100); + int32_t decoded_index = pulse_decoder_get_decoded_index(worker->pulse_decoder); + if(decoded_index >= 0) { + pulse_decoder_get_data( + worker->pulse_decoder, decoded_index, worker->key_data, ibutton_key_get_max_size()); + } + + switch(decoded_index) { + case PulseProtocolCyfral: + furi_check(worker->key_p != NULL); + ibutton_key_set_type(worker->key_p, iButtonKeyCyfral); + ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); + result = true; + break; + case PulseProtocolMetakom: + furi_check(worker->key_p != NULL); + ibutton_key_set_type(worker->key_p, iButtonKeyMetakom); + ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); + result = true; + break; + break; + default: + break; + } + + furi_hal_rfid_comp_stop(); + furi_hal_rfid_comp_set_callback(NULL, NULL); + furi_hal_rfid_pins_reset(); + + return result; +} + +bool ibutton_worker_read_dallas(iButtonWorker* worker) { + bool result = false; + onewire_host_start(worker->host); + delay(100); + FURI_CRITICAL_ENTER(); + if(onewire_host_search(worker->host, worker->key_data, NORMAL_SEARCH)) { + onewire_host_reset_search(worker->host); + + // key found, verify + if(onewire_host_reset(worker->host)) { + onewire_host_write(worker->host, DS1990_CMD_READ_ROM); + bool key_valid = true; + for(uint8_t i = 0; i < ibutton_key_get_max_size(); i++) { + if(onewire_host_read(worker->host) != worker->key_data[i]) { + key_valid = false; + break; + } + } + + if(key_valid) { + result = true; + + furi_check(worker->key_p != NULL); + ibutton_key_set_type(worker->key_p, iButtonKeyDS1990); + ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); + } + } + } else { + onewire_host_reset_search(worker->host); + } + onewire_host_stop(worker->host); + FURI_CRITICAL_EXIT(); + return result; +} + +void ibutton_worker_mode_read_start(iButtonWorker* worker) { + furi_hal_power_enable_otg(); +} + +void ibutton_worker_mode_read_tick(iButtonWorker* worker) { + bool valid = false; + if(ibutton_worker_read_dallas(worker)) { + valid = true; + } else if(ibutton_worker_read_comparator(worker)) { + valid = true; + } + + if(valid) { + if(worker->read_cb != NULL) { + worker->read_cb(worker->cb_ctx); + } + + ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + } +} + +void ibutton_worker_mode_read_stop(iButtonWorker* worker) { + furi_hal_power_disable_otg(); +} + +/*********************** EMULATE ***********************/ +static void onewire_slave_callback(void* context) { + furi_assert(context); + iButtonWorker* worker = context; + if(worker->emulate_cb != NULL) { + worker->emulate_cb(worker->cb_ctx, true); + } +} + +void ibutton_worker_emulate_dallas_start(iButtonWorker* worker) { + uint8_t* device_id = onewire_device_get_id_p(worker->device); + const uint8_t* key_id = ibutton_key_get_data_p(worker->key_p); + const uint8_t key_size = ibutton_key_get_max_size(); + memcpy(device_id, key_id, key_size); + + onewire_slave_attach(worker->slave, worker->device); + onewire_slave_start(worker->slave); + onewire_slave_set_result_callback(worker->slave, onewire_slave_callback, worker); +} + +void ibutton_worker_emulate_dallas_stop(iButtonWorker* worker) { + onewire_slave_stop(worker->slave); + onewire_slave_detach(worker->slave); +} + +void ibutton_worker_emulate_timer_cb(void* context) { + furi_assert(context); + iButtonWorker* worker = context; + + bool polarity; + uint32_t length; + + switch(worker->emulate_mode) { + case iButtonEmulateModeCyfral: + encoder_cyfral_get_pulse(worker->encoder_cyfral, &polarity, &length); + break; + case iButtonEmulateModeMetakom: + encoder_metakom_get_pulse(worker->encoder_metakom, &polarity, &length); + break; + } + + furi_hal_ibutton_emulate_set_next(length); + + if(polarity) { + furi_hal_ibutton_pin_high(); + } else { + furi_hal_ibutton_pin_low(); + } +} + +void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { + furi_assert(worker->key_p); + const uint8_t* key_id = ibutton_key_get_data_p(worker->key_p); + const uint8_t key_size = ibutton_key_get_max_size(); + + switch(ibutton_key_get_type(worker->key_p)) { + case iButtonKeyDS1990: + return; + break; + case iButtonKeyCyfral: + worker->emulate_mode = iButtonEmulateModeCyfral; + encoder_cyfral_reset(worker->encoder_cyfral); + encoder_cyfral_set_data(worker->encoder_cyfral, key_id, key_size); + break; + case iButtonKeyMetakom: + worker->emulate_mode = iButtonEmulateModeMetakom; + encoder_metakom_reset(worker->encoder_metakom); + encoder_metakom_set_data(worker->encoder_metakom, key_id, key_size); + break; + } + + furi_hal_ibutton_start_drive(); + furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker); +} + +void ibutton_worker_emulate_timer_stop(iButtonWorker* worker) { + furi_hal_ibutton_emulate_stop(); +} + +void ibutton_worker_mode_emulate_start(iButtonWorker* worker) { + furi_assert(worker->key_p); + + furi_hal_rfid_pins_reset(); + furi_hal_rfid_pin_pull_pulldown(); + + switch(ibutton_key_get_type(worker->key_p)) { + case iButtonKeyDS1990: + ibutton_worker_emulate_dallas_start(worker); + break; + case iButtonKeyCyfral: + case iButtonKeyMetakom: + ibutton_worker_emulate_timer_start(worker); + break; + } +} + +void ibutton_worker_mode_emulate_tick(iButtonWorker* worker) { +} + +void ibutton_worker_mode_emulate_stop(iButtonWorker* worker) { + furi_assert(worker->key_p); + + furi_hal_rfid_pins_reset(); + + switch(ibutton_key_get_type(worker->key_p)) { + case iButtonKeyDS1990: + ibutton_worker_emulate_dallas_stop(worker); + break; + case iButtonKeyCyfral: + case iButtonKeyMetakom: + ibutton_worker_emulate_timer_stop(worker); + break; + } +} + +/*********************** WRITE ***********************/ + +void ibutton_worker_mode_write_start(iButtonWorker* worker) { + furi_hal_power_enable_otg(); + onewire_host_start(worker->host); +} + +void ibutton_worker_mode_write_tick(iButtonWorker* worker) { + furi_check(worker->key_p != NULL); + iButtonWriterResult writer_result = ibutton_writer_write(worker->writer, worker->key_p); + iButtonWorkerWriteResult result; + switch(writer_result) { + case iButtonWriterOK: + result = iButtonWorkerWriteOK; + break; + case iButtonWriterSameKey: + result = iButtonWorkerWriteSameKey; + break; + case iButtonWriterNoDetect: + result = iButtonWorkerWriteNoDetect; + break; + case iButtonWriterCannotWrite: + result = iButtonWorkerWriteCannotWrite; + break; + default: + result = iButtonWorkerWriteNoDetect; + break; + } + + if(worker->write_cb != NULL) { + worker->write_cb(worker->cb_ctx, result); + } +} + +void ibutton_worker_mode_write_stop(iButtonWorker* worker) { + furi_hal_power_disable_otg(); + onewire_host_stop(worker->host); +} \ No newline at end of file diff --git a/lib/one_wire/ibutton/ibutton_writer.c b/lib/one_wire/ibutton/ibutton_writer.c new file mode 100644 index 00000000..fe59e60f --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_writer.c @@ -0,0 +1,298 @@ +#include +#include +#include "ibutton_writer.h" +#include "ibutton_key_command.h" + +/*********************** PRIVATE ***********************/ + +struct iButtonWriter { + OneWireHost* host; +}; + +static void writer_write_one_bit(iButtonWriter* writer, bool value, uint32_t delay) { + onewire_host_write_bit(writer->host, value); + delay_us(delay); +} + +static void writer_write_byte_ds1990(iButtonWriter* writer, uint8_t data) { + for(uint8_t n_bit = 0; n_bit < 8; n_bit++) { + onewire_host_write_bit(writer->host, data & 1); + delay_us(5000); + data = data >> 1; + } +} + +static bool writer_compare_key_ds1990(iButtonWriter* writer, iButtonKey* key) { + bool result = false; + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + FURI_CRITICAL_ENTER(); + bool presence = onewire_host_reset(writer->host); + + if(presence) { + onewire_host_write(writer->host, DS1990_CMD_READ_ROM); + + result = true; + for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { + if(ibutton_key_get_data_p(key)[i] != onewire_host_read(writer->host)) { + result = false; + break; + } + } + } + + FURI_CRITICAL_EXIT(); + } + + return result; +} + +static bool writer_write_TM2004(iButtonWriter* writer, iButtonKey* key) { + uint8_t answer; + bool result = true; + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + FURI_CRITICAL_ENTER(); + + // write rom, addr is 0x0000 + onewire_host_reset(writer->host); + onewire_host_write(writer->host, TM2004_CMD_WRITE_ROM); + onewire_host_write(writer->host, 0x00); + onewire_host_write(writer->host, 0x00); + + // write key + for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { + // write key byte + onewire_host_write(writer->host, ibutton_key_get_data_p(key)[i]); + answer = onewire_host_read(writer->host); + // TODO: check answer CRC + + // pulse indicating that data is correct + delay_us(600); + writer_write_one_bit(writer, 1, 50000); + + // read writed key byte + answer = onewire_host_read(writer->host); + + // check that writed and readed are same + if(ibutton_key_get_data_p(key)[i] != answer) { + result = false; + break; + } + } + + if(!writer_compare_key_ds1990(writer, key)) { + result = false; + } + + onewire_host_reset(writer->host); + + FURI_CRITICAL_EXIT(); + } else { + result = false; + } + + return result; +} + +static bool writer_write_1990_1(iButtonWriter* writer, iButtonKey* key) { + bool result = false; + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + FURI_CRITICAL_ENTER(); + + // unlock + onewire_host_reset(writer->host); + onewire_host_write(writer->host, RW1990_1_CMD_WRITE_RECORD_FLAG); + delay_us(10); + writer_write_one_bit(writer, 0, 5000); + + // write key + onewire_host_reset(writer->host); + onewire_host_write(writer->host, RW1990_1_CMD_WRITE_ROM); + for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { + // inverted key for RW1990.1 + writer_write_byte_ds1990(writer, ~ibutton_key_get_data_p(key)[i]); + delay_us(30000); + } + + // lock + onewire_host_write(writer->host, RW1990_1_CMD_WRITE_RECORD_FLAG); + writer_write_one_bit(writer, 1, 10000); + + FURI_CRITICAL_EXIT(); + + if(writer_compare_key_ds1990(writer, key)) { + result = true; + } + } + + return result; +} + +static bool writer_write_1990_2(iButtonWriter* writer, iButtonKey* key) { + bool result = false; + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + FURI_CRITICAL_ENTER(); + + // unlock + onewire_host_reset(writer->host); + onewire_host_write(writer->host, RW1990_2_CMD_WRITE_RECORD_FLAG); + delay_us(10); + writer_write_one_bit(writer, 1, 5000); + + // write key + onewire_host_reset(writer->host); + onewire_host_write(writer->host, RW1990_2_CMD_WRITE_ROM); + for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { + writer_write_byte_ds1990(writer, ibutton_key_get_data_p(key)[i]); + delay_us(30000); + } + + // lock + onewire_host_write(writer->host, RW1990_2_CMD_WRITE_RECORD_FLAG); + writer_write_one_bit(writer, 0, 10000); + + FURI_CRITICAL_EXIT(); + + if(writer_compare_key_ds1990(writer, key)) { + result = true; + } + } + + return result; +} + +/* +// TODO: adapt and test +static bool writer_write_TM01( + iButtonWriter* writer, + iButtonKey type, + const uint8_t* key, + uint8_t key_length) { + bool result = true; + + { + // TODO test and encoding + FURI_CRITICAL_ENTER(); + + // unlock + onewire_host_reset(writer->host); + onewire_host_write(writer->host, TM01::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(1, 10000); + + // write key + onewire_host_reset(writer->host); + onewire_host_write(writer->host, 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_host_write(writer->host, TM01::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(0, 10000); + + FURI_CRITICAL_EXIT(); + } + + if(!compare_key_ds1990(key)) { + result = false; + } + + { + FURI_CRITICAL_ENTER(); + + if(key->get_key_type() == iButtonKeyType::KeyMetakom || + key->get_key_type() == iButtonKeyType::KeyCyfral) { + onewire_host_reset(writer->host); + if(key->get_key_type() == iButtonKeyType::KeyCyfral) + onewire_host_write(writer->host, TM01::CMD_SWITCH_TO_CYFRAL); + else + onewire_host_write(writer->host, TM01::CMD_SWITCH_TO_METAKOM); + onewire_write_one_bit(1); + } + + FURI_CRITICAL_EXIT(); + } + + return result; +} +*/ + +static iButtonWriterResult writer_write_DS1990(iButtonWriter* writer, iButtonKey* key) { + iButtonWriterResult result = iButtonWriterNoDetect; + bool same_key = writer_compare_key_ds1990(writer, key); + + if(!same_key) { + // currently we can write: + // RW1990_1, TM08v2, TM08vi-2 by write_1990_1() + // RW1990_2 by write_1990_2() + // RW2004, RW2004, TM2004 with EEPROM by write_TM2004(); + + bool write_result = true; + do { + if(writer_write_1990_1(writer, key)) break; + if(writer_write_1990_2(writer, key)) break; + if(writer_write_TM2004(writer, key)) break; + write_result = false; + } while(false); + + if(write_result) { + result = iButtonWriterOK; + } else { + result = iButtonWriterCannotWrite; + } + } else { + result = iButtonWriterSameKey; + } + + return result; +} + +/*********************** PUBLIC ***********************/ + +iButtonWriter* ibutton_writer_alloc(OneWireHost* host) { + iButtonWriter* writer = malloc(sizeof(iButtonWriter)); + writer->host = host; + return writer; +} + +void ibutton_writer_free(iButtonWriter* writer) { + free(writer); +} + +iButtonWriterResult ibutton_writer_write(iButtonWriter* writer, iButtonKey* key) { + iButtonWriterResult result = iButtonWriterNoDetect; + + osKernelLock(); + bool blank_present = onewire_host_reset(writer->host); + osKernelUnlock(); + + if(blank_present) { + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: + result = writer_write_DS1990(writer, key); + default: + break; + } + } + + return result; +} + +void ibutton_writer_start(iButtonWriter* writer) { + furi_hal_power_enable_otg(); + onewire_host_start(writer->host); +} + +void ibutton_writer_stop(iButtonWriter* writer) { + onewire_host_stop(writer->host); + furi_hal_power_disable_otg(); +} diff --git a/lib/one_wire/ibutton/ibutton_writer.h b/lib/one_wire/ibutton/ibutton_writer.h new file mode 100644 index 00000000..8e81cfd1 --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_writer.h @@ -0,0 +1,60 @@ +/** + * @file ibutton_writer.h + * + * iButton blanks writer + */ + +#pragma once +#include +#include "ibutton_key.h" +#include "../one_wire_host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + iButtonWriterOK, + iButtonWriterSameKey, + iButtonWriterNoDetect, + iButtonWriterCannotWrite, +} iButtonWriterResult; + +typedef struct iButtonWriter iButtonWriter; + +/** + * Allocate writer + * @param host + * @return iButtonWriter* + */ +iButtonWriter* ibutton_writer_alloc(OneWireHost* host); + +/** + * Deallocate writer + * @param writer + */ +void ibutton_writer_free(iButtonWriter* writer); + +/** + * Write key to blank + * @param writer + * @param key + * @return iButtonWriterResult + */ +iButtonWriterResult ibutton_writer_write(iButtonWriter* writer, iButtonKey* key); + +/** + * Start writing. Must be called before write attempt + * @param writer + */ +void ibutton_writer_start(iButtonWriter* writer); + +/** + * Stop writing + * @param writer + */ +void ibutton_writer_stop(iButtonWriter* writer); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c new file mode 100644 index 00000000..09635edf --- /dev/null +++ b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c @@ -0,0 +1,256 @@ +#include "protocol_cyfral.h" +#include +#include +#include +#include + +#define CYFRAL_DATA_SIZE 2 +#define CYFRAL_MAX_PERIOD_US 230 + +typedef enum { + CYFRAL_BIT_WAIT_FRONT_HIGH, + CYFRAL_BIT_WAIT_FRONT_LOW, +} CyfralBitState; + +typedef enum { + CYFRAL_WAIT_START_NIBBLE, + CYFRAL_READ_NIBBLE, + CYFRAL_READ_STOP_NIBBLE, +} CyfralState; + +struct ProtocolCyfral { + PulseProtocol* protocol; + + CyfralState state; + CyfralBitState bit_state; + + // ready flag, key is read and valid + // TODO: atomic access + bool ready; + // key data storage + uint16_t key_data; + // high + low period time + uint32_t period_time; + // temporary nibble storage + uint8_t 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; +}; + +static void cyfral_pulse(void* context, bool polarity, uint32_t length); +static void cyfral_reset(void* context); +static void cyfral_get_data(void* context, uint8_t* data, size_t length); +static bool cyfral_decoded(void* context); + +ProtocolCyfral* protocol_cyfral_alloc() { + ProtocolCyfral* cyfral = malloc(sizeof(ProtocolCyfral)); + cyfral_reset(cyfral); + + cyfral->protocol = pulse_protocol_alloc(); + + pulse_protocol_set_context(cyfral->protocol, cyfral); + pulse_protocol_set_pulse_cb(cyfral->protocol, cyfral_pulse); + pulse_protocol_set_reset_cb(cyfral->protocol, cyfral_reset); + pulse_protocol_set_get_data_cb(cyfral->protocol, cyfral_get_data); + pulse_protocol_set_decoded_cb(cyfral->protocol, cyfral_decoded); + + return cyfral; +} + +void protocol_cyfral_free(ProtocolCyfral* cyfral) { + furi_assert(cyfral); + pulse_protocol_free(cyfral->protocol); + free(cyfral); +} + +PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral) { + furi_assert(cyfral); + return cyfral->protocol; +} + +static void cyfral_get_data(void* context, uint8_t* data, size_t length) { + furi_assert(context); + furi_check(length >= CYFRAL_DATA_SIZE); + ProtocolCyfral* cyfral = context; + memcpy(data, &cyfral->key_data, CYFRAL_DATA_SIZE); +} + +static bool cyfral_decoded(void* context) { + furi_assert(context); + ProtocolCyfral* cyfral = context; + bool decoded = cyfral->ready; + return decoded; +} + +static void cyfral_reset(void* context) { + furi_assert(context); + ProtocolCyfral* cyfral = context; + cyfral->state = CYFRAL_WAIT_START_NIBBLE; + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; + + cyfral->period_time = 0; + cyfral->bit_index = 0; + cyfral->ready = false; + cyfral->index = 0; + + cyfral->key_data = 0; + cyfral->nibble = 0; + cyfral->data_valid = true; + + cyfral->max_period = CYFRAL_MAX_PERIOD_US * instructions_per_us; +} + +static bool cyfral_process_bit( + ProtocolCyfral* cyfral, + bool polarity, + uint32_t length, + bool* bit_ready, + bool* bit_value) { + bool result = true; + *bit_ready = false; + + // bit start from low + switch(cyfral->bit_state) { + case CYFRAL_BIT_WAIT_FRONT_LOW: + if(polarity == true) { + cyfral->period_time += length; + + *bit_ready = true; + if(cyfral->period_time <= cyfral->max_period) { + if((cyfral->period_time / 2) > length) { + *bit_value = false; + } else { + *bit_value = true; + } + } else { + result = false; + } + + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH; + } else { + result = false; + } + break; + case CYFRAL_BIT_WAIT_FRONT_HIGH: + if(polarity == false) { + cyfral->period_time = length; + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; + } else { + result = false; + } + break; + } + + return result; +} + +static void cyfral_pulse(void* context, bool polarity, uint32_t length) { + furi_assert(context); + ProtocolCyfral* cyfral = context; + + bool bit_ready; + bool bit_value; + + if(cyfral->ready) return; + + switch(cyfral->state) { + case CYFRAL_WAIT_START_NIBBLE: + // wait for start word + if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; + if(cyfral->nibble == 0b0001) { + cyfral->nibble = 0; + cyfral->state = CYFRAL_READ_NIBBLE; + } + } + } else { + cyfral_reset(cyfral); + } + + break; + case CYFRAL_READ_NIBBLE: + // read nibbles + if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = (cyfral->nibble << 1) | bit_value; + + cyfral->bit_index++; + + //convert every nibble to 2-bit index + if(cyfral->bit_index == 4) { + switch(cyfral->nibble) { + case 0b1110: + cyfral->key_data = (cyfral->key_data << 2) | 0b11; + break; + case 0b1101: + cyfral->key_data = (cyfral->key_data << 2) | 0b10; + break; + case 0b1011: + cyfral->key_data = (cyfral->key_data << 2) | 0b01; + break; + case 0b0111: + cyfral->key_data = (cyfral->key_data << 2) | 0b00; + break; + default: + cyfral->data_valid = false; + break; + } + + cyfral->nibble = 0; + cyfral->bit_index = 0; + cyfral->index++; + } + + // succefully read 8 nibbles + if(cyfral->index == 8) { + cyfral->state = CYFRAL_READ_STOP_NIBBLE; + } + } + } else { + cyfral_reset(cyfral); + } + break; + case CYFRAL_READ_STOP_NIBBLE: + // read stop nibble + if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; + cyfral->bit_index++; + + switch(cyfral->bit_index) { + case 0: + case 1: + case 2: + case 3: + break; + case 4: + if(cyfral->nibble == 0b0001) { + // validate data + if(cyfral->data_valid) { + cyfral->ready = true; + } else { + cyfral_reset(cyfral); + } + } else { + cyfral_reset(cyfral); + } + break; + default: + cyfral_reset(cyfral); + break; + } + } + } else { + cyfral_reset(cyfral); + } + break; + } +} diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h new file mode 100644 index 00000000..4a7c00e4 --- /dev/null +++ b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h @@ -0,0 +1,38 @@ +/** + * @file protocol_cyfral.h + * + * Cyfral pulse format decoder + */ + +#pragma once +#include +#include "../../pulse_protocols/pulse_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ProtocolCyfral ProtocolCyfral; + +/** + * Allocate decoder + * @return ProtocolCyfral* + */ +ProtocolCyfral* protocol_cyfral_alloc(); + +/** + * Deallocate decoder + * @param cyfral + */ +void protocol_cyfral_free(ProtocolCyfral* cyfral); + +/** + * Get protocol interface + * @param cyfral + * @return PulseProtocol* + */ +PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c b/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c new file mode 100644 index 00000000..d76ef886 --- /dev/null +++ b/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c @@ -0,0 +1,262 @@ +#include "protocol_metakom.h" +#include +#include +#include +#include + +#define METAKOM_DATA_SIZE 4 +#define METAKOM_PERIOD_SAMPLE_COUNT 10 + +typedef enum { + METAKOM_WAIT_PERIOD_SYNC, + METAKOM_WAIT_START_BIT, + METAKOM_WAIT_START_WORD, + METAKOM_READ_WORD, + METAKOM_READ_STOP_WORD, +} MetakomState; + +typedef enum { + METAKOM_BIT_WAIT_FRONT_HIGH, + METAKOM_BIT_WAIT_FRONT_LOW, +} MetakomBitState; + +struct ProtocolMetakom { + PulseProtocol* protocol; + + // high + low period time + uint32_t period_time; + uint32_t low_time_storage; + uint8_t period_sample_index; + uint32_t period_sample_data[METAKOM_PERIOD_SAMPLE_COUNT]; + + // ready flag + // TODO: atomic access + bool ready; + + uint8_t tmp_data; + uint8_t tmp_counter; + + uint32_t key_data; + uint8_t key_data_index; + + MetakomBitState bit_state; + MetakomState state; +}; + +static void metakom_pulse(void* context, bool polarity, uint32_t length); +static void metakom_reset(void* context); +static void metakom_get_data(void* context, uint8_t* data, size_t length); +static bool metakom_decoded(void* context); + +ProtocolMetakom* protocol_metakom_alloc() { + ProtocolMetakom* metakom = malloc(sizeof(ProtocolMetakom)); + metakom_reset(metakom); + + metakom->protocol = pulse_protocol_alloc(); + + pulse_protocol_set_context(metakom->protocol, metakom); + pulse_protocol_set_pulse_cb(metakom->protocol, metakom_pulse); + pulse_protocol_set_reset_cb(metakom->protocol, metakom_reset); + pulse_protocol_set_get_data_cb(metakom->protocol, metakom_get_data); + pulse_protocol_set_decoded_cb(metakom->protocol, metakom_decoded); + + return metakom; +} + +void protocol_metakom_free(ProtocolMetakom* metakom) { + furi_assert(metakom); + pulse_protocol_free(metakom->protocol); + free(metakom); +} + +PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom) { + furi_assert(metakom); + return metakom->protocol; +} + +static void metakom_get_data(void* context, uint8_t* data, size_t length) { + furi_assert(context); + furi_check(length >= METAKOM_DATA_SIZE); + ProtocolMetakom* metakom = context; + memcpy(data, &metakom->key_data, METAKOM_DATA_SIZE); +} + +static bool metakom_decoded(void* context) { + furi_assert(context); + ProtocolMetakom* metakom = context; + bool decoded = metakom->ready; + return decoded; +} + +static void metakom_reset(void* context) { + furi_assert(context); + ProtocolMetakom* metakom = context; + + metakom->ready = false; + metakom->period_sample_index = 0; + metakom->period_time = 0; + metakom->tmp_counter = 0; + metakom->tmp_data = 0; + for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) { + metakom->period_sample_data[i] = 0; + }; + metakom->state = METAKOM_WAIT_PERIOD_SYNC; + metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW; + metakom->key_data = 0; + metakom->key_data_index = 0; + metakom->low_time_storage = 0; +} + +static bool metakom_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; +} + +static bool metakom_process_bit( + ProtocolMetakom* metakom, + bool polarity, + uint32_t time, + uint32_t* high_time, + uint32_t* low_time) { + bool result = false; + + switch(metakom->bit_state) { + case METAKOM_BIT_WAIT_FRONT_LOW: + if(polarity == false) { + *low_time = metakom->low_time_storage; + *high_time = time; + result = true; + metakom->bit_state = METAKOM_BIT_WAIT_FRONT_HIGH; + } + break; + case METAKOM_BIT_WAIT_FRONT_HIGH: + if(polarity == true) { + metakom->low_time_storage = time; + metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW; + } + break; + } + + return result; +} + +static void metakom_pulse(void* context, bool polarity, uint32_t time) { + furi_assert(context); + ProtocolMetakom* metakom = context; + + if(metakom->ready) return; + + uint32_t high_time = 0; + uint32_t low_time = 0; + + switch(metakom->state) { + case METAKOM_WAIT_PERIOD_SYNC: + if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + metakom->period_sample_data[metakom->period_sample_index] = high_time + low_time; + metakom->period_sample_index++; + + if(metakom->period_sample_index == METAKOM_PERIOD_SAMPLE_COUNT) { + for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) { + metakom->period_time += metakom->period_sample_data[i]; + }; + metakom->period_time /= METAKOM_PERIOD_SAMPLE_COUNT; + + metakom->state = METAKOM_WAIT_START_BIT; + } + } + + break; + case METAKOM_WAIT_START_BIT: + if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + metakom->tmp_counter++; + if(high_time > metakom->period_time) { + metakom->tmp_counter = 0; + metakom->state = METAKOM_WAIT_START_WORD; + } + + if(metakom->tmp_counter > 40) { + metakom_reset(metakom); + } + } + + break; + case METAKOM_WAIT_START_WORD: + if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(low_time < (metakom->period_time / 2)) { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; + } else { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b1; + } + metakom->tmp_counter++; + + if(metakom->tmp_counter == 3) { + if(metakom->tmp_data == 0b010) { + metakom->tmp_counter = 0; + metakom->tmp_data = 0; + metakom->state = METAKOM_READ_WORD; + } else { + metakom_reset(metakom); + } + } + } + break; + case METAKOM_READ_WORD: + if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(low_time < (metakom->period_time / 2)) { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; + } else { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b1; + } + metakom->tmp_counter++; + + if(metakom->tmp_counter == 8) { + if(metakom_parity_check(metakom->tmp_data)) { + metakom->key_data = (metakom->key_data << 8) | metakom->tmp_data; + metakom->key_data_index++; + metakom->tmp_data = 0; + metakom->tmp_counter = 0; + + if(metakom->key_data_index == 4) { + // check for stop bit + if(high_time > metakom->period_time) { + metakom->state = METAKOM_READ_STOP_WORD; + } else { + metakom_reset(metakom); + } + } + } else { + metakom_reset(metakom); + } + } + } + break; + case METAKOM_READ_STOP_WORD: + if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(low_time < (metakom->period_time / 2)) { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; + } else { + metakom->tmp_data = (metakom->tmp_data << 1) | 0b1; + } + metakom->tmp_counter++; + + if(metakom->tmp_counter == 3) { + if(metakom->tmp_data == 0b010) { + metakom->ready = true; + } else { + metakom_reset(metakom); + } + } + } + break; + } +} diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h b/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h new file mode 100644 index 00000000..fbafc235 --- /dev/null +++ b/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h @@ -0,0 +1,38 @@ +/** + * @file protocol_metakom.h + * + * Metakom pulse format decoder + */ + +#pragma once +#include +#include "../../pulse_protocols/pulse_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ProtocolMetakom ProtocolMetakom; + +/** + * Allocate decoder + * @return ProtocolMetakom* + */ +ProtocolMetakom* protocol_metakom_alloc(); + +/** + * Free decoder + * @param metakom + */ +void protocol_metakom_free(ProtocolMetakom* metakom); + +/** + * Get protocol interface + * @param metakom + * @return PulseProtocol* + */ +PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/maxim_crc.c b/lib/one_wire/maxim_crc.c new file mode 100644 index 00000000..bd89d3ad --- /dev/null +++ b/lib/one_wire/maxim_crc.c @@ -0,0 +1,16 @@ +#include "maxim_crc.h" + +uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init) { + uint8_t crc = crc_init; + + for(uint8_t index = 0; index < data_size; ++index) { + uint8_t input_byte = data[index]; + for(uint8_t bit_position = 0; bit_position < 8; ++bit_position) { + const uint8_t mix = (crc ^ input_byte) & (uint8_t)(0x01); + crc >>= 1; + if(mix != 0) crc ^= 0x8C; + input_byte >>= 1; + } + } + return crc; +} \ No newline at end of file diff --git a/lib/one_wire/maxim_crc.h b/lib/one_wire/maxim_crc.h new file mode 100644 index 00000000..1b7e8498 --- /dev/null +++ b/lib/one_wire/maxim_crc.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXIM_CRC8_INIT 0 + +uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/one_wire_device.c b/lib/one_wire/one_wire_device.c new file mode 100644 index 00000000..d9b4955d --- /dev/null +++ b/lib/one_wire/one_wire_device.c @@ -0,0 +1,59 @@ +#include +#include "maxim_crc.h" +#include "one_wire_device.h" +#include "one_wire_slave.h" +#include "one_wire_slave_i.h" + +struct OneWireDevice { + uint8_t id_storage[8]; + OneWireSlave* bus; +}; + +OneWireDevice* onewire_device_alloc( + uint8_t id_1, + uint8_t id_2, + uint8_t id_3, + uint8_t id_4, + uint8_t id_5, + uint8_t id_6, + uint8_t id_7, + uint8_t id_8) { + OneWireDevice* device = malloc(sizeof(OneWireDevice)); + device->id_storage[0] = id_1; + device->id_storage[1] = id_2; + device->id_storage[2] = id_3; + device->id_storage[3] = id_4; + device->id_storage[4] = id_5; + device->id_storage[5] = id_6; + device->id_storage[6] = id_7; + device->id_storage[7] = id_8; + device->bus = NULL; + + return device; +} + +void onewire_device_free(OneWireDevice* device) { + if(device->bus != NULL) { + onewire_slave_detach(device->bus); + } + + free(device); +} + +void onewire_device_send_id(OneWireDevice* device) { + if(device->bus != NULL) { + onewire_slave_send(device->bus, device->id_storage, 8); + } +} + +void onewire_device_attach(OneWireDevice* device, OneWireSlave* bus) { + device->bus = bus; +} + +void onewire_device_detach(OneWireDevice* device) { + device->bus = NULL; +} + +uint8_t* onewire_device_get_id_p(OneWireDevice* device) { + return device->id_storage; +} diff --git a/lib/one_wire/one_wire_device.h b/lib/one_wire/one_wire_device.h new file mode 100644 index 00000000..4ff16790 --- /dev/null +++ b/lib/one_wire/one_wire_device.h @@ -0,0 +1,74 @@ +/** + * @file one_wire_device.h + * + * 1-Wire slave library, device interface. Currently it can only emulate ID. + */ + +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OneWireSlave OneWireSlave; +typedef struct OneWireDevice OneWireDevice; + +/** + * Allocate onewire device with ID + * @param id_1 + * @param id_2 + * @param id_3 + * @param id_4 + * @param id_5 + * @param id_6 + * @param id_7 + * @param id_8 + * @return OneWireDevice* + */ +OneWireDevice* onewire_device_alloc( + uint8_t id_1, + uint8_t id_2, + uint8_t id_3, + uint8_t id_4, + uint8_t id_5, + uint8_t id_6, + uint8_t id_7, + uint8_t id_8); + +/** + * Deallocate onewire device + * @param device + */ +void onewire_device_free(OneWireDevice* device); + +/** + * Send ID report, called from onewire slave + * @param device + */ +void onewire_device_send_id(OneWireDevice* device); + +/** + * Attach device to onewire slave bus + * @param device + * @param bus + */ +void onewire_device_attach(OneWireDevice* device, OneWireSlave* bus); + +/** + * Attach device from onewire slave bus + * @param device + */ +void onewire_device_detach(OneWireDevice* device); + +/** + * Get pointer to device id array + * @param device + * @return uint8_t* + */ +uint8_t* onewire_device_get_id_p(OneWireDevice* device); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/one_wire_host.c b/lib/one_wire/one_wire_host.c new file mode 100644 index 00000000..3c907df7 --- /dev/null +++ b/lib/one_wire/one_wire_host.c @@ -0,0 +1,261 @@ +#include +#include +#include "one_wire_host.h" +#include "one_wire_host_timing.h" + +struct OneWireHost { + // global search state + unsigned char saved_rom[8]; + uint8_t last_discrepancy; + uint8_t last_family_discrepancy; + bool last_device_flag; +}; + +OneWireHost* onewire_host_alloc() { + OneWireHost* host = malloc(sizeof(OneWireHost)); + onewire_host_reset_search(host); + return host; +} + +void onewire_host_free(OneWireHost* host) { + onewire_host_stop(host); + free(host); +} + +bool onewire_host_reset(OneWireHost* host) { + uint8_t r; + uint8_t retries = 125; + + // wait until the gpio is high + furi_hal_ibutton_pin_high(); + do { + if(--retries == 0) return 0; + delay_us(2); + } while(!furi_hal_ibutton_pin_get_level()); + + // pre delay + delay_us(OWH_RESET_DELAY_PRE); + + // drive low + furi_hal_ibutton_pin_low(); + delay_us(OWH_RESET_DRIVE); + + // release + furi_hal_ibutton_pin_high(); + delay_us(OWH_RESET_RELEASE); + + // read and post delay + r = !furi_hal_ibutton_pin_get_level(); + delay_us(OWH_RESET_DELAY_POST); + + return r; +} + +bool onewire_host_read_bit(OneWireHost* host) { + bool result; + + // drive low + furi_hal_ibutton_pin_low(); + delay_us(OWH_READ_DRIVE); + + // release + furi_hal_ibutton_pin_high(); + delay_us(OWH_READ_RELEASE); + + // read and post delay + result = furi_hal_ibutton_pin_get_level(); + delay_us(OWH_READ_DELAY_POST); + + return result; +} + +uint8_t onewire_host_read(OneWireHost* host) { + uint8_t result = 0; + + for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { + if(onewire_host_read_bit(host)) { + result |= bitMask; + } + } + + return result; +} + +void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count) { + for(uint16_t i = 0; i < count; i++) { + buffer[i] = onewire_host_read(host); + } +} + +void onewire_host_write_bit(OneWireHost* host, bool value) { + if(value) { + // drive low + furi_hal_ibutton_pin_low(); + delay_us(OWH_WRITE_1_DRIVE); + + // release + furi_hal_ibutton_pin_high(); + delay_us(OWH_WRITE_1_RELEASE); + } else { + // drive low + furi_hal_ibutton_pin_low(); + delay_us(OWH_WRITE_0_DRIVE); + + // release + furi_hal_ibutton_pin_high(); + delay_us(OWH_WRITE_0_RELEASE); + } +} + +void onewire_host_write(OneWireHost* host, uint8_t value) { + uint8_t bitMask; + + for(bitMask = 0x01; bitMask; bitMask <<= 1) { + onewire_host_write_bit(host, (bitMask & value) ? 1 : 0); + } +} + +void onewire_host_skip(OneWireHost* host) { + onewire_host_write(host, 0xCC); +} + +void onewire_host_start(OneWireHost* host) { + furi_hal_ibutton_start_drive(); +} + +void onewire_host_stop(OneWireHost* host) { + furi_hal_ibutton_stop(); +} + +void onewire_host_reset_search(OneWireHost* host) { + host->last_discrepancy = 0; + host->last_device_flag = false; + host->last_family_discrepancy = 0; + for(int i = 7;; i--) { + host->saved_rom[i] = 0; + if(i == 0) break; + } +} + +void onewire_host_target_search(OneWireHost* host, uint8_t family_code) { + host->saved_rom[0] = family_code; + for(uint8_t i = 1; i < 8; i++) host->saved_rom[i] = 0; + host->last_discrepancy = 64; + host->last_family_discrepancy = 0; + host->last_device_flag = false; +} + +uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode) { + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number, search_result; + uint8_t id_bit, cmp_id_bit; + + unsigned char rom_byte_mask, search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = 0; + + // if the last call was not the last one + if(!host->last_device_flag) { + // 1-Wire reset + if(!onewire_host_reset(host)) { + // reset the search + host->last_discrepancy = 0; + host->last_device_flag = false; + host->last_family_discrepancy = 0; + return false; + } + + // issue the search command + switch(mode) { + case CONDITIONAL_SEARCH: + onewire_host_write(host, 0xEC); + break; + case NORMAL_SEARCH: + onewire_host_write(host, 0xF0); + break; + } + + // loop to do the search + do { + // read a bit and its complement + id_bit = onewire_host_read_bit(host); + cmp_id_bit = onewire_host_read_bit(host); + + // check for no devices on 1-wire + if((id_bit == 1) && (cmp_id_bit == 1)) + break; + else { + // all devices coupled have 0 or 1 + if(id_bit != cmp_id_bit) + search_direction = id_bit; // bit write value for search + else { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if(id_bit_number < host->last_discrepancy) + search_direction = + ((host->saved_rom[rom_byte_number] & rom_byte_mask) > 0); + else + // if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == host->last_discrepancy); + + // if 0 was picked then record its position in LastZero + if(search_direction == 0) { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if(last_zero < 9) host->last_family_discrepancy = last_zero; + } + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if(search_direction == 1) + host->saved_rom[rom_byte_number] |= rom_byte_mask; + else + host->saved_rom[rom_byte_number] &= ~rom_byte_mask; + + // serial number search direction write bit + onewire_host_write_bit(host, search_direction); + + // increment the byte counter id_bit_number + // and shift the mask rom_byte_mask + id_bit_number++; + rom_byte_mask <<= 1; + + // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if(rom_byte_mask == 0) { + rom_byte_number++; + rom_byte_mask = 1; + } + } + } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if(!(id_bit_number < 65)) { + // search successful so set last_Discrepancy, last_device_flag, search_result + host->last_discrepancy = last_zero; + + // check for last device + if(host->last_discrepancy == 0) host->last_device_flag = true; + + search_result = true; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if(!search_result || !host->saved_rom[0]) { + host->last_discrepancy = 0; + host->last_device_flag = false; + host->last_family_discrepancy = 0; + search_result = false; + } else { + for(int i = 0; i < 8; i++) newAddr[i] = host->saved_rom[i]; + } + + return search_result; +} diff --git a/lib/one_wire/one_wire_host.h b/lib/one_wire/one_wire_host.h new file mode 100644 index 00000000..21530640 --- /dev/null +++ b/lib/one_wire/one_wire_host.h @@ -0,0 +1,121 @@ +/** + * @file one_wire_host.h + * + * 1-Wire host (master) library + */ + +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + CONDITIONAL_SEARCH = 0, /**< Search for alarmed device */ + NORMAL_SEARCH = 1, /**< Search all devices */ +} OneWireHostSearchMode; + +typedef struct OneWireHost OneWireHost; + +/** + * Allocate onewire host bus + * @param gpio + * @return OneWireHost* + */ +OneWireHost* onewire_host_alloc(); + +/** + * Deallocate onewire host bus + * @param host + */ +void onewire_host_free(OneWireHost* host); + +/** + * Reset bus + * @param host + * @return bool + */ +bool onewire_host_reset(OneWireHost* host); + +/** + * Read one bit + * @param host + * @return bool + */ +bool onewire_host_read_bit(OneWireHost* host); + +/** + * Read one byte + * @param host + * @return uint8_t + */ +uint8_t onewire_host_read(OneWireHost* host); + +/** + * Read many bytes + * @param host + * @param buffer + * @param count + */ +void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count); + +/** + * Write one bit + * @param host + * @param value + */ +void onewire_host_write_bit(OneWireHost* host, bool value); + +/** + * Write one byte + * @param host + * @param value + */ +void onewire_host_write(OneWireHost* host, uint8_t value); + +/** + * Skip ROM command + * @param host + */ +void onewire_host_skip(OneWireHost* host); + +/** + * Start working with the bus + * @param host + */ +void onewire_host_start(OneWireHost* host); + +/** + * Stop working with the bus + * @param host + */ +void onewire_host_stop(OneWireHost* host); + +/** + * + * @param host + */ +void onewire_host_reset_search(OneWireHost* host); + +/** + * + * @param host + * @param family_code + */ +void onewire_host_target_search(OneWireHost* host, uint8_t family_code); + +/** + * + * @param host + * @param newAddr + * @param mode + * @return uint8_t + */ +uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/one_wire_host_timing.h b/lib/one_wire/one_wire_host_timing.h new file mode 100644 index 00000000..f95dd356 --- /dev/null +++ b/lib/one_wire/one_wire_host_timing.h @@ -0,0 +1,30 @@ +/** + * @file one_wire_host_timing.h + * + * 1-Wire library, timing list + */ + +#pragma once + +#define OWH_TIMING_A 9 +#define OWH_TIMING_B 64 +#define OWH_TIMING_C 64 +#define OWH_TIMING_D 14 +#define OWH_TIMING_E 9 +#define OWH_TIMING_F 55 +#define OWH_TIMING_G 0 +#define OWH_TIMING_H 480 +#define OWH_TIMING_I 70 +#define OWH_TIMING_J 410 + +#define OWH_WRITE_1_DRIVE OWH_TIMING_A +#define OWH_WRITE_1_RELEASE OWH_TIMING_B +#define OWH_WRITE_0_DRIVE OWH_TIMING_C +#define OWH_WRITE_0_RELEASE OWH_TIMING_D +#define OWH_READ_DRIVE 3 +#define OWH_READ_RELEASE OWH_TIMING_E +#define OWH_READ_DELAY_POST OWH_TIMING_F +#define OWH_RESET_DELAY_PRE OWH_TIMING_G +#define OWH_RESET_DRIVE OWH_TIMING_H +#define OWH_RESET_RELEASE OWH_TIMING_I +#define OWH_RESET_DELAY_POST OWH_TIMING_J diff --git a/lib/one_wire/one_wire_slave.c b/lib/one_wire/one_wire_slave.c new file mode 100644 index 00000000..37c4ed2f --- /dev/null +++ b/lib/one_wire/one_wire_slave.c @@ -0,0 +1,317 @@ +#include "one_wire_slave.h" +#include "one_wire_slave_i.h" +#include "one_wire_device.h" +#include +#include +#include + +#define OWS_RESET_MIN 270 +#define OWS_RESET_MAX 960 +#define OWS_PRESENCE_TIMEOUT 20 +#define OWS_PRESENCE_MIN 100 +#define OWS_PRESENCE_MAX 480 +#define OWS_MSG_HIGH_TIMEOUT 15000 +#define OWS_SLOT_MAX 135 +#define OWS_READ_MIN 20 +#define OWS_READ_MAX 60 +#define OWS_WRITE_ZERO 30 + +typedef enum { + NO_ERROR = 0, + VERY_LONG_RESET, + VERY_SHORT_RESET, + PRESENCE_LOW_ON_LINE, + AWAIT_TIMESLOT_TIMEOUT_HIGH, + INCORRECT_ONEWIRE_CMD, + FIRST_BIT_OF_BYTE_TIMEOUT, + RESET_IN_PROGRESS +} OneWireSlaveError; + +struct OneWireSlave { + OneWireSlaveError error; + OneWireDevice* device; + OneWireSlaveResultCallback result_cb; + void* result_cb_ctx; +}; + +/*********************** PRIVATE ***********************/ + +uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) { + uint32_t start = DWT->CYCCNT; + uint32_t time_ticks = time * instructions_per_us; + uint32_t time_captured; + + do { + time_captured = DWT->CYCCNT; + if(furi_hal_ibutton_pin_get_level() != pin_value) { + uint32_t remaining_time = time_ticks - (time_captured - start); + remaining_time /= instructions_per_us; + return remaining_time; + } + } while((time_captured - start) < time_ticks); + + return 0; +} + +bool onewire_slave_show_presence(OneWireSlave* bus) { + // wait while master delay presence check + onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true); + + // show presence + furi_hal_ibutton_pin_low(); + delay_us(OWS_PRESENCE_MIN); + furi_hal_ibutton_pin_high(); + + // somebody also can show presence + const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN; + + // so we will wait + if(onewire_slave_wait_while_gpio_is(bus, wait_low_time, false) == 0) { + bus->error = PRESENCE_LOW_ON_LINE; + return false; + } + + return true; +} + +bool onewire_slave_receive_bit(OneWireSlave* bus) { + // wait while bus is low + uint32_t time = OWS_SLOT_MAX; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + if(time == 0) { + bus->error = RESET_IN_PROGRESS; + return false; + } + + // wait while bus is high + time = OWS_MSG_HIGH_TIMEOUT; + time = onewire_slave_wait_while_gpio_is(bus, time, true); + if(time == 0) { + bus->error = AWAIT_TIMESLOT_TIMEOUT_HIGH; + return false; + } + + // wait a time of zero + time = OWS_READ_MIN; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + + return (time > 0); +} + +bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { + const bool write_zero = !value; + + // wait while bus is low + uint32_t time = OWS_SLOT_MAX; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + if(time == 0) { + bus->error = RESET_IN_PROGRESS; + return false; + } + + // wait while bus is high + time = OWS_MSG_HIGH_TIMEOUT; + time = onewire_slave_wait_while_gpio_is(bus, time, true); + if(time == 0) { + bus->error = AWAIT_TIMESLOT_TIMEOUT_HIGH; + return false; + } + + // choose write time + if(write_zero) { + furi_hal_ibutton_pin_low(); + time = OWS_WRITE_ZERO; + } else { + time = OWS_READ_MAX; + } + + // hold line for ZERO or ONE time + delay_us(time); + furi_hal_ibutton_pin_high(); + + return true; +} + +void onewire_slave_cmd_search_rom(OneWireSlave* bus) { + const uint8_t key_bytes = 8; + uint8_t* key = onewire_device_get_id_p(bus->device); + + for(uint8_t i = 0; i < key_bytes; i++) { + uint8_t key_byte = key[i]; + + for(uint8_t j = 0; j < 8; j++) { + bool bit = (key_byte >> j) & 0x01; + + if(!onewire_slave_send_bit(bus, bit)) return; + if(!onewire_slave_send_bit(bus, !bit)) return; + + onewire_slave_receive_bit(bus); + if(bus->error != NO_ERROR) return; + } + } +} + +bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) { + uint8_t cmd; + onewire_slave_receive(bus, &cmd, 1); + + if(bus->error == RESET_IN_PROGRESS) return true; + if(bus->error != NO_ERROR) return false; + + switch(cmd) { + case 0xF0: + // SEARCH ROM + onewire_slave_cmd_search_rom(bus); + return true; + + case 0x0F: + case 0x33: + // READ ROM + onewire_device_send_id(bus->device); + return true; + + default: // Unknown command + bus->error = INCORRECT_ONEWIRE_CMD; + } + + if(bus->error == RESET_IN_PROGRESS) return true; + return (bus->error == NO_ERROR); +} + +bool onewire_slave_bus_start(OneWireSlave* bus) { + bool result = true; + + if(bus->device == NULL) { + result = false; + } else { + FURI_CRITICAL_ENTER(); + furi_hal_ibutton_start_drive_in_isr(); + bus->error = NO_ERROR; + + if(onewire_slave_show_presence(bus)) { + // TODO think about multiple command cycles + onewire_slave_receive_and_process_cmd(bus); + result = (bus->error == NO_ERROR || bus->error == INCORRECT_ONEWIRE_CMD); + + } else { + result = false; + } + + furi_hal_ibutton_start_interrupt_in_isr(); + FURI_CRITICAL_EXIT(); + } + + return result; +} + +static void exti_cb(void* context) { + OneWireSlave* bus = context; + + volatile bool input_state = furi_hal_ibutton_pin_get_level(); + static uint32_t pulse_start = 0; + + if(input_state) { + uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / instructions_per_us; + if(pulse_length >= OWS_RESET_MIN) { + if(pulse_length <= OWS_RESET_MAX) { + // reset cycle ok + bool result = onewire_slave_bus_start(bus); + if(result && bus->result_cb != NULL) { + bus->result_cb(bus->result_cb_ctx); + } + } else { + bus->error = VERY_LONG_RESET; + } + } else { + bus->error = VERY_SHORT_RESET; + } + } else { + //FALL event + pulse_start = DWT->CYCCNT; + } +}; + +/*********************** PUBLIC ***********************/ + +OneWireSlave* onewire_slave_alloc() { + OneWireSlave* bus = malloc(sizeof(OneWireSlave)); + bus->error = NO_ERROR; + bus->device = NULL; + bus->result_cb = NULL; + bus->result_cb_ctx = NULL; + return bus; +} + +void onewire_slave_free(OneWireSlave* bus) { + onewire_slave_stop(bus); + free(bus); +} + +void onewire_slave_start(OneWireSlave* bus) { + furi_hal_ibutton_add_interrupt(exti_cb, bus); + furi_hal_ibutton_start_interrupt(); +} + +void onewire_slave_stop(OneWireSlave* bus) { + furi_hal_ibutton_stop(); + furi_hal_ibutton_remove_interrupt(); +} + +void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) { + bus->device = device; + onewire_device_attach(device, bus); +} + +void onewire_slave_detach(OneWireSlave* bus) { + if(bus->device != NULL) { + onewire_device_detach(bus->device); + } + bus->device = NULL; +} + +void onewire_slave_set_result_callback( + OneWireSlave* bus, + OneWireSlaveResultCallback result_cb, + void* context) { + bus->result_cb = result_cb; + bus->result_cb_ctx = context; +} + +bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) { + uint8_t bytes_sent = 0; + + furi_hal_ibutton_pin_high(); + + // bytes loop + for(; bytes_sent < data_length; ++bytes_sent) { + const uint8_t data_byte = address[bytes_sent]; + + // bit loop + for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { + if(!onewire_slave_send_bit(bus, bit_mask & data_byte)) { + // if we cannot send first bit + if((bit_mask == 0x01) && (bus->error == AWAIT_TIMESLOT_TIMEOUT_HIGH)) + bus->error = FIRST_BIT_OF_BYTE_TIMEOUT; + return false; + } + } + } + return true; +} + +bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) { + uint8_t bytes_received = 0; + + furi_hal_ibutton_pin_high(); + + for(; bytes_received < data_length; ++bytes_received) { + uint8_t value = 0; + + for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { + if(onewire_slave_receive_bit(bus)) value |= bit_mask; + } + + data[bytes_received] = value; + } + return (bytes_received != data_length); +} diff --git a/lib/one_wire/one_wire_slave.h b/lib/one_wire/one_wire_slave.h new file mode 100644 index 00000000..82e9f552 --- /dev/null +++ b/lib/one_wire/one_wire_slave.h @@ -0,0 +1,71 @@ +/** + * @file one_wire_slave.h + * + * 1-Wire slave library. Currently it can only emulate ID. + */ + +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OneWireDevice OneWireDevice; +typedef struct OneWireSlave OneWireSlave; +typedef void (*OneWireSlaveResultCallback)(void* context); + +/** + * Allocate onewire slave + * @param pin + * @return OneWireSlave* + */ +OneWireSlave* onewire_slave_alloc(); + +/** + * Free onewire slave + * @param bus + */ +void onewire_slave_free(OneWireSlave* bus); + +/** + * Start working with the bus + * @param bus + */ +void onewire_slave_start(OneWireSlave* bus); + +/** + * Stop working with the bus + * @param bus + */ +void onewire_slave_stop(OneWireSlave* bus); + +/** + * Attach device for emulation + * @param bus + * @param device + */ +void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device); + +/** + * Detach device from bus + * @param bus + */ +void onewire_slave_detach(OneWireSlave* bus); + +/** + * Set a callback to report emulation success + * @param bus + * @param result_cb + * @param context + */ +void onewire_slave_set_result_callback( + OneWireSlave* bus, + OneWireSlaveResultCallback result_cb, + void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/one_wire/one_wire_slave_i.h b/lib/one_wire/one_wire_slave_i.h new file mode 100644 index 00000000..55e0762e --- /dev/null +++ b/lib/one_wire/one_wire_slave_i.h @@ -0,0 +1,38 @@ +/** + * @file one_wire_slave_i.h + * + * 1-Wire slave library, internal functions + */ + +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OneWireDevice OneWireDevice; +typedef struct OneWireSlave OneWireSlave; + +/** + * Send data, called from emulated device + * @param bus + * @param address + * @param data_length + * @return bool + */ +bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length); + +/** + * Receive data, called from emulated device + * @param bus + * @param data + * @param data_length + * @return bool + */ +bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length); + +#ifdef __cplusplus +} +#endif diff --git a/lib/one_wire/pulse_protocols/pulse_decoder.c b/lib/one_wire/pulse_protocols/pulse_decoder.c new file mode 100644 index 00000000..e8197a08 --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_decoder.c @@ -0,0 +1,66 @@ +#include +#include "pulse_decoder.h" +#include +#include + +#define MAX_PROTOCOL 5 + +struct PulseDecoder { + PulseProtocol* protocols[MAX_PROTOCOL]; +}; + +PulseDecoder* pulse_decoder_alloc() { + PulseDecoder* decoder = malloc(sizeof(PulseDecoder)); + memset(decoder, 0, sizeof(PulseDecoder)); + return decoder; +} + +void pulse_decoder_free(PulseDecoder* reader) { + furi_assert(reader); + free(reader); +} + +void pulse_decoder_add_protocol(PulseDecoder* reader, PulseProtocol* protocol, int32_t index) { + furi_check(index < MAX_PROTOCOL); + furi_check(reader->protocols[index] == NULL); + reader->protocols[index] = protocol; +} + +void pulse_decoder_process_pulse(PulseDecoder* reader, bool polarity, uint32_t length) { + furi_assert(reader); + for(size_t index = 0; index < MAX_PROTOCOL; index++) { + if(reader->protocols[index] != NULL) { + pulse_protocol_process_pulse(reader->protocols[index], polarity, length); + } + } +} + +int32_t pulse_decoder_get_decoded_index(PulseDecoder* reader) { + furi_assert(reader); + int32_t decoded = -1; + for(size_t index = 0; index < MAX_PROTOCOL; index++) { + if(reader->protocols[index] != NULL) { + if(pulse_protocol_decoded(reader->protocols[index])) { + decoded = index; + break; + } + } + } + + return decoded; +} + +void pulse_decoder_reset(PulseDecoder* reader) { + furi_assert(reader); + for(size_t index = 0; index < MAX_PROTOCOL; index++) { + if(reader->protocols[index] != NULL) { + pulse_protocol_reset(reader->protocols[index]); + } + } +} + +void pulse_decoder_get_data(PulseDecoder* reader, int32_t index, uint8_t* data, size_t length) { + furi_assert(reader); + furi_check(reader->protocols[index] != NULL); + pulse_protocol_get_data(reader->protocols[index], data, length); +} diff --git a/lib/one_wire/pulse_protocols/pulse_decoder.h b/lib/one_wire/pulse_protocols/pulse_decoder.h new file mode 100644 index 00000000..4e9f9d22 --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_decoder.h @@ -0,0 +1,70 @@ +/** + * @file pulse_decoder.h + * + * Generic pulse protocol decoder library + */ + +#pragma once +#include +#include +#include "pulse_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PulseDecoder PulseDecoder; + +/** + * Allocate decoder + * @return PulseDecoder* + */ +PulseDecoder* pulse_decoder_alloc(); + +/** + * Deallocate decoder + * @param decoder + */ +void pulse_decoder_free(PulseDecoder* decoder); + +/** + * Add protocol to decoder + * @param decoder + * @param protocol protocol implementation + * @param index protocol index, should not be repeated + */ +void pulse_decoder_add_protocol(PulseDecoder* decoder, PulseProtocol* protocol, int32_t index); + +/** + * Push and process pulse with decoder + * @param decoder + * @param polarity + * @param length + */ +void pulse_decoder_process_pulse(PulseDecoder* decoder, bool polarity, uint32_t length); + +/** + * Get indec of decoded protocol + * @param decoder + * @return int32_t, -1 if nothing decoded, or index of decoded protocol + */ +int32_t pulse_decoder_get_decoded_index(PulseDecoder* decoder); + +/** + * Reset all protocols in decoder + * @param decoder + */ +void pulse_decoder_reset(PulseDecoder* decoder); + +/** + * Get decoded data from protocol + * @param decoder + * @param index + * @param data + * @param length + */ +void pulse_decoder_get_data(PulseDecoder* decoder, int32_t index, uint8_t* data, size_t length); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/pulse_protocols/pulse_glue.c b/lib/one_wire/pulse_protocols/pulse_glue.c new file mode 100644 index 00000000..9cb914db --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_glue.c @@ -0,0 +1,55 @@ +#include "pulse_glue.h" + +struct PulseGlue { + int32_t hi_period; + int32_t low_period; + int32_t next_hi_period; +}; + +PulseGlue* pulse_glue_alloc() { + PulseGlue* pulse_glue = malloc(sizeof(PulseGlue)); + pulse_glue_reset(pulse_glue); + return pulse_glue; +} + +void pulse_glue_free(PulseGlue* pulse_glue) { + free(pulse_glue); +} + +void pulse_glue_reset(PulseGlue* pulse_glue) { + pulse_glue->hi_period = 0; + pulse_glue->low_period = 0; + pulse_glue->next_hi_period = 0; +} + +bool pulse_glue_push(PulseGlue* pulse_glue, bool polarity, uint32_t length) { + bool pop_ready = false; + if(polarity) { + if(pulse_glue->low_period == 0) { + // stage 1, accumulate hi period + pulse_glue->hi_period += length; + } else { + // stage 3, accumulate next hi period and be ready for pulse_glue_pop + pulse_glue->next_hi_period = length; + + // data is ready + pop_ready = true; + } + } else { + if(pulse_glue->hi_period != 0) { + // stage 2, accumulate low period + pulse_glue->low_period += length; + } + } + + return pop_ready; +} + +void pulse_glue_pop(PulseGlue* pulse_glue, uint32_t* length, uint32_t* period) { + *length = pulse_glue->hi_period + pulse_glue->low_period; + *period = pulse_glue->hi_period; + + pulse_glue->hi_period = pulse_glue->next_hi_period; + pulse_glue->low_period = 0; + pulse_glue->next_hi_period = 0; +} diff --git a/lib/one_wire/pulse_protocols/pulse_glue.h b/lib/one_wire/pulse_protocols/pulse_glue.h new file mode 100644 index 00000000..aa58f239 --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_glue.h @@ -0,0 +1,26 @@ +/** + * @file pulse_glue.h + * + * Simple tool to glue separated pulses to corret + */ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PulseGlue PulseGlue; + +PulseGlue* pulse_glue_alloc(); +void pulse_glue_free(PulseGlue* pulse_glue); +void pulse_glue_reset(PulseGlue* pulse_glue); + +bool pulse_glue_push(PulseGlue* pulse_glue, bool polarity, uint32_t length); +void pulse_glue_pop(PulseGlue* pulse_glue, uint32_t* length, uint32_t* period); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/pulse_protocols/pulse_protocol.c b/lib/one_wire/pulse_protocols/pulse_protocol.c new file mode 100644 index 00000000..ac01ea92 --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_protocol.c @@ -0,0 +1,67 @@ +#include "pulse_protocol.h" +#include +#include + +struct PulseProtocol { + void* context; + PulseProtocolPulseCallback pulse_cb; + PulseProtocolResetCallback reset_cb; + PulseProtocolGetDataCallback get_data_cb; + PulseProtocolDecodedCallback decoded_cb; +}; + +PulseProtocol* pulse_protocol_alloc() { + PulseProtocol* protocol = malloc(sizeof(PulseProtocol)); + memset(protocol, 0, sizeof(PulseProtocol)); + return protocol; +} + +void pulse_protocol_set_context(PulseProtocol* protocol, void* context) { + protocol->context = context; +} + +void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback) { + protocol->pulse_cb = callback; +} + +void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback) { + protocol->reset_cb = callback; +} + +void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback) { + protocol->get_data_cb = callback; +} + +void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback) { + protocol->decoded_cb = callback; +} + +void pulse_protocol_free(PulseProtocol* protocol) { + free(protocol); +} + +void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length) { + if(protocol->pulse_cb != NULL) { + protocol->pulse_cb(protocol->context, polarity, length); + } +} + +void pulse_protocol_reset(PulseProtocol* protocol) { + if(protocol->reset_cb != NULL) { + protocol->reset_cb(protocol->context); + } +} + +bool pulse_protocol_decoded(PulseProtocol* protocol) { + bool result = false; + if(protocol->decoded_cb != NULL) { + result = protocol->decoded_cb(protocol->context); + } + return result; +} + +void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length) { + if(protocol->get_data_cb != NULL) { + protocol->get_data_cb(protocol->context, data, length); + } +} \ No newline at end of file diff --git a/lib/one_wire/pulse_protocols/pulse_protocol.h b/lib/one_wire/pulse_protocols/pulse_protocol.h new file mode 100644 index 00000000..01bc14a1 --- /dev/null +++ b/lib/one_wire/pulse_protocols/pulse_protocol.h @@ -0,0 +1,122 @@ +/** + * @file pulse_protocol.h + * + * Generic pulse protocol decoder library, protocol interface + */ + +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Anonymous PulseProtocol struct + */ +typedef struct PulseProtocol PulseProtocol; + +/** + * Process pulse callback + */ +typedef void (*PulseProtocolPulseCallback)(void* context, bool polarity, uint32_t length); + +/** + * Reset protocol callback + */ +typedef void (*PulseProtocolResetCallback)(void* context); + +/** + * Get decoded data callback + */ +typedef void (*PulseProtocolGetDataCallback)(void* context, uint8_t* data, size_t length); + +/** + * Is protocol decoded callback + */ +typedef bool (*PulseProtocolDecodedCallback)(void* context); + +/** + * Allocate protocol + * @return PulseProtocol* + */ +PulseProtocol* pulse_protocol_alloc(); + +/** + * Deallocate protocol + * @param protocol + */ +void pulse_protocol_free(PulseProtocol* protocol); + +/** + * Set context for callbacks + * @param protocol + * @param context + */ +void pulse_protocol_set_context(PulseProtocol* protocol, void* context); + +/** + * Set "Process pulse" callback. Called from the decoder when a new pulse is received. + * @param protocol + * @param callback + */ +void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback); + +/** + * Set "Reset protocol" callback. Called from the decoder when the decoder is reset. + * @param protocol + * @param callback + */ +void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback); + +/** + * Set "Get decoded data" callback. Called from the decoder when the decoder wants to get decoded data. + * @param protocol + * @param callback + */ +void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback); + +/** + * Set "Is protocol decoded" callback. Called from the decoder when the decoder wants to know if a protocol has been decoded. + * @param protocol + * @param callback + */ +void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback); + +/** + * Part of decoder interface. + * @param protocol + * @param polarity + * @param length + */ +void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length); + +/** + * Part of decoder interface. + * @param protocol + * @return true + * @return false + */ +bool pulse_protocol_decoded(PulseProtocol* protocol); + +/** + * Part of decoder interface. + * @param protocol + * @return true + * @return false + */ +void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length); + +/** + * Part of decoder interface. + * @param protocol + * @return true + * @return false + */ +void pulse_protocol_reset(PulseProtocol* protocol); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/onewire/maxim_crc.cpp b/lib/onewire/maxim_crc.cpp deleted file mode 100644 index f56d84dc..00000000 --- a/lib/onewire/maxim_crc.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "maxim_crc.h" - -uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init) { - uint8_t crc = crc_init; - - for(uint8_t index = 0; index < data_size; ++index) { - uint8_t input_byte = data[index]; - for(uint8_t bit_position = 0; bit_position < 8; ++bit_position) { - const uint8_t mix = (crc ^ input_byte) & static_cast(0x01); - crc >>= 1; - if(mix != 0) crc ^= 0x8C; - input_byte >>= 1; - } - } - return crc; -} - -uint16_t maxim_crc16(const uint8_t* address, const uint8_t length, const uint16_t init) { - uint16_t crc = init; - - static const uint8_t odd_parity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; - - for(uint8_t i = 0; i < length; ++i) { - uint16_t cdata = address[i]; - cdata = (cdata ^ crc) & static_cast(0xff); - crc >>= 8; - - if((odd_parity[cdata & 0x0F] ^ odd_parity[cdata >> 4]) != 0) crc ^= 0xC001; - - cdata <<= 6; - crc ^= cdata; - cdata <<= 1; - crc ^= cdata; - } - - return crc; -} - -uint16_t maxim_crc16(uint8_t value, uint16_t crc) { - static const uint8_t odd_parity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; - value = (value ^ static_cast(crc)); - crc >>= 8; - if((odd_parity[value & 0x0F] ^ odd_parity[value >> 4]) != 0) crc ^= 0xC001; - uint16_t cdata = (static_cast(value) << 6); - crc ^= cdata; - crc ^= (static_cast(cdata) << 1); - return crc; -} \ No newline at end of file diff --git a/lib/onewire/maxim_crc.h b/lib/onewire/maxim_crc.h deleted file mode 100644 index 1a9569fa..00000000 --- a/lib/onewire/maxim_crc.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include - -uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init = 0); -uint16_t maxim_crc16(const uint8_t* address, const uint8_t length, const uint16_t init = 0); -uint16_t maxim_crc16(uint8_t value, uint16_t crc); \ No newline at end of file diff --git a/lib/onewire/one_wire_device.cpp b/lib/onewire/one_wire_device.cpp deleted file mode 100644 index d1e6319a..00000000 --- a/lib/onewire/one_wire_device.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "one_wire_device.h" - -OneWireDevice::OneWireDevice( - uint8_t id_1, - uint8_t id_2, - uint8_t id_3, - uint8_t id_4, - uint8_t id_5, - uint8_t id_6, - uint8_t id_7) { - id_storage[0] = id_1; - id_storage[1] = id_2; - id_storage[2] = id_3; - id_storage[3] = id_4; - id_storage[4] = id_5; - id_storage[5] = id_6; - id_storage[6] = id_7; - id_storage[7] = maxim_crc8(id_storage, 7); -} - -OneWireDevice::~OneWireDevice() { - if(bus != nullptr) { - bus->deattach(); - } -} - -void OneWireDevice::send_id() const { - if(bus != nullptr) { - bus->send(id_storage, 8); - } -} - -void OneWireDevice::attach(OneWireSlave* _bus) { - bus = _bus; -} - -void OneWireDevice::deattach(void) { - bus = nullptr; -} diff --git a/lib/onewire/one_wire_device.h b/lib/onewire/one_wire_device.h deleted file mode 100644 index 0aff3d28..00000000 --- a/lib/onewire/one_wire_device.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include "maxim_crc.h" -#include "one_wire_slave.h" - -class OneWireDevice { -public: - OneWireDevice( - uint8_t id_1, - uint8_t id_2, - uint8_t id_3, - uint8_t id_4, - uint8_t id_5, - uint8_t id_6, - uint8_t id_7); - - ~OneWireDevice(); - - uint8_t id_storage[8]; - - void send_id() const; - - OneWireSlave* bus = nullptr; - void attach(OneWireSlave* _bus); - void deattach(void); -}; \ No newline at end of file diff --git a/lib/onewire/one_wire_device_ds_1990.cpp b/lib/onewire/one_wire_device_ds_1990.cpp deleted file mode 100644 index cde6134c..00000000 --- a/lib/onewire/one_wire_device_ds_1990.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "one_wire_device_ds_1990.h" - -DS1990::DS1990( - uint8_t ID1, - uint8_t ID2, - uint8_t ID3, - uint8_t ID4, - uint8_t ID5, - uint8_t ID6, - uint8_t ID7) - : OneWireDevice(ID1, ID2, ID3, ID4, ID5, ID6, ID7) { -} \ No newline at end of file diff --git a/lib/onewire/one_wire_device_ds_1990.h b/lib/onewire/one_wire_device_ds_1990.h deleted file mode 100644 index bf3eb411..00000000 --- a/lib/onewire/one_wire_device_ds_1990.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "one_wire_device.h" - -class DS1990 : public OneWireDevice { -public: - static constexpr uint8_t family_code{0x01}; - - DS1990( - uint8_t ID1, - uint8_t ID2, - uint8_t ID3, - uint8_t ID4, - uint8_t ID5, - uint8_t ID6, - uint8_t ID7); -}; \ No newline at end of file diff --git a/lib/onewire/one_wire_master.cpp b/lib/onewire/one_wire_master.cpp deleted file mode 100644 index dcea651c..00000000 --- a/lib/onewire/one_wire_master.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include "one_wire_master.h" -#include "one_wire_timings.h" - -OneWireMaster::OneWireMaster(const GpioPin* one_wire_gpio) { - gpio = one_wire_gpio; - reset_search(); -} - -OneWireMaster::~OneWireMaster() { - stop(); -} - -void OneWireMaster::start(void) { - hal_gpio_init(gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); -} - -void OneWireMaster::stop(void) { - hal_gpio_init(gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); -} - -void OneWireMaster::reset_search() { - // reset the search state - last_discrepancy = 0; - last_device_flag = false; - last_family_discrepancy = 0; - for(int i = 7;; i--) { - saved_rom[i] = 0; - if(i == 0) break; - } -} - -void OneWireMaster::target_search(uint8_t family_code) { - // set the search state to find SearchFamily type devices - saved_rom[0] = family_code; - for(uint8_t i = 1; i < 8; i++) saved_rom[i] = 0; - last_discrepancy = 64; - last_family_discrepancy = 0; - last_device_flag = false; -} - -uint8_t OneWireMaster::search(uint8_t* newAddr, bool search_mode) { - uint8_t id_bit_number; - uint8_t last_zero, rom_byte_number, search_result; - uint8_t id_bit, cmp_id_bit; - - unsigned char rom_byte_mask, search_direction; - - // initialize for search - id_bit_number = 1; - last_zero = 0; - rom_byte_number = 0; - rom_byte_mask = 1; - search_result = 0; - - // if the last call was not the last one - if(!last_device_flag) { - // 1-Wire reset - if(!reset()) { - // reset the search - last_discrepancy = 0; - last_device_flag = false; - last_family_discrepancy = 0; - return false; - } - - // issue the search command - if(search_mode == true) { - write(0xF0); // NORMAL SEARCH - } else { - write(0xEC); // CONDITIONAL SEARCH - } - - // loop to do the search - do { - // read a bit and its complement - id_bit = read_bit(); - cmp_id_bit = read_bit(); - - // check for no devices on 1-wire - if((id_bit == 1) && (cmp_id_bit == 1)) - break; - else { - // all devices coupled have 0 or 1 - if(id_bit != cmp_id_bit) - search_direction = id_bit; // bit write value for search - else { - // if this discrepancy if before the Last Discrepancy - // on a previous next then pick the same as last time - if(id_bit_number < last_discrepancy) - search_direction = ((saved_rom[rom_byte_number] & rom_byte_mask) > 0); - else - // if equal to last pick 1, if not then pick 0 - search_direction = (id_bit_number == last_discrepancy); - - // if 0 was picked then record its position in LastZero - if(search_direction == 0) { - last_zero = id_bit_number; - - // check for Last discrepancy in family - if(last_zero < 9) last_family_discrepancy = last_zero; - } - } - - // set or clear the bit in the ROM byte rom_byte_number - // with mask rom_byte_mask - if(search_direction == 1) - saved_rom[rom_byte_number] |= rom_byte_mask; - else - saved_rom[rom_byte_number] &= ~rom_byte_mask; - - // serial number search direction write bit - write_bit(search_direction); - - // increment the byte counter id_bit_number - // and shift the mask rom_byte_mask - id_bit_number++; - rom_byte_mask <<= 1; - - // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask - if(rom_byte_mask == 0) { - rom_byte_number++; - rom_byte_mask = 1; - } - } - } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 - - // if the search was successful then - if(!(id_bit_number < 65)) { - // search successful so set last_Discrepancy, last_device_flag, search_result - last_discrepancy = last_zero; - - // check for last device - if(last_discrepancy == 0) last_device_flag = true; - - search_result = true; - } - } - - // if no device found then reset counters so next 'search' will be like a first - if(!search_result || !saved_rom[0]) { - last_discrepancy = 0; - last_device_flag = false; - last_family_discrepancy = 0; - search_result = false; - } else { - for(int i = 0; i < 8; i++) newAddr[i] = saved_rom[i]; - } - - return search_result; -} - -bool OneWireMaster::reset(void) { - uint8_t r; - uint8_t retries = 125; - - // wait until the gpio is high - hal_gpio_write(gpio, true); - do { - if(--retries == 0) return 0; - delay_us(2); - } while(!hal_gpio_read(gpio)); - - // pre delay - delay_us(OneWireTiming::RESET_DELAY_PRE); - - // drive low - hal_gpio_write(gpio, false); - delay_us(OneWireTiming::RESET_DRIVE); - - // release - hal_gpio_write(gpio, true); - delay_us(OneWireTiming::RESET_RELEASE); - - // read and post delay - r = !hal_gpio_read(gpio); - delay_us(OneWireTiming::RESET_DELAY_POST); - - return r; -} - -bool OneWireMaster::read_bit(void) { - bool result; - - // drive low - hal_gpio_write(gpio, false); - delay_us(OneWireTiming::READ_DRIVE); - - // release - hal_gpio_write(gpio, true); - delay_us(OneWireTiming::READ_RELEASE); - - // read and post delay - result = hal_gpio_read(gpio); - delay_us(OneWireTiming::READ_DELAY_POST); - - return result; -} - -void OneWireMaster::write_bit(bool value) { - if(value) { - // drive low - hal_gpio_write(gpio, false); - delay_us(OneWireTiming::WRITE_1_DRIVE); - - // release - hal_gpio_write(gpio, true); - delay_us(OneWireTiming::WRITE_1_RELEASE); - } else { - // drive low - hal_gpio_write(gpio, false); - delay_us(OneWireTiming::WRITE_0_DRIVE); - - // release - hal_gpio_write(gpio, true); - delay_us(OneWireTiming::WRITE_0_RELEASE); - } -} - -uint8_t OneWireMaster::read(void) { - uint8_t result = 0; - - for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { - if(read_bit()) { - result |= bitMask; - } - } - - return result; -} - -void OneWireMaster::read_bytes(uint8_t* buffer, uint16_t count) { - for(uint16_t i = 0; i < count; i++) { - buffer[i] = read(); - } -} - -void OneWireMaster::write(uint8_t value) { - uint8_t bitMask; - - for(bitMask = 0x01; bitMask; bitMask <<= 1) { - write_bit((bitMask & value) ? 1 : 0); - } -} - -void OneWireMaster::skip(void) { - write(0xCC); -} diff --git a/lib/onewire/one_wire_master.h b/lib/onewire/one_wire_master.h deleted file mode 100644 index 1f00567d..00000000 --- a/lib/onewire/one_wire_master.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include -#include -#include "one_wire_timings.h" - -class OneWireMaster { -private: - const GpioPin* gpio; - - // global search state - unsigned char saved_rom[8]; - uint8_t last_discrepancy; - uint8_t last_family_discrepancy; - bool last_device_flag; - -public: - OneWireMaster(const GpioPin* one_wire_gpio); - ~OneWireMaster(); - bool reset(void); - bool read_bit(void); - uint8_t read(void); - void read_bytes(uint8_t* buf, uint16_t count); - void write_bit(bool value); - void write(uint8_t value); - void skip(void); - void start(void); - void stop(void); - - void reset_search(); - void target_search(uint8_t family_code); - uint8_t search(uint8_t* newAddr, bool search_mode = true); -}; \ No newline at end of file diff --git a/lib/onewire/one_wire_slave.cpp b/lib/onewire/one_wire_slave.cpp deleted file mode 100644 index c0f50caa..00000000 --- a/lib/onewire/one_wire_slave.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "one_wire_slave.h" -#include "callback-connector.h" -#include "main.h" -#include "one_wire_device.h" - -#define OWET OneWireEmulateTiming - -void OneWireSlave::start(void) { - // add exti interrupt - hal_gpio_add_int_callback(one_wire_pin_record, exti_cb, this); - - // init gpio - hal_gpio_init(one_wire_pin_record, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); - pin_set_float(); - - // init instructions per us count - __instructions_per_us = (SystemCoreClock / 1000000.0f); -} - -void OneWireSlave::stop(void) { - // deinit gpio - hal_gpio_init(one_wire_pin_record, GpioModeInput, GpioPullNo, GpioSpeedLow); - // remove exti interrupt - hal_gpio_remove_int_callback(one_wire_pin_record); - - // deattach devices - deattach(); -} - -OneWireSlave::OneWireSlave(const GpioPin* pin) { - one_wire_pin_record = pin; - exti_cb = cbc::obtain_connector(this, &OneWireSlave::exti_callback); -} - -OneWireSlave::~OneWireSlave() { - stop(); -} - -void OneWireSlave::attach(OneWireDevice* attached_device) { - device = attached_device; - device->attach(this); -} - -void OneWireSlave::deattach(void) { - if(device != nullptr) { - device->deattach(); - } - device = nullptr; -} - -void OneWireSlave::set_result_callback(OneWireSlaveResultCallback result_cb, void* ctx) { - this->result_cb = result_cb; - this->result_cb_ctx = ctx; -} - -void OneWireSlave::pin_set_float() { - hal_gpio_write(one_wire_pin_record, true); -} - -void OneWireSlave::pin_set_low() { - hal_gpio_write(one_wire_pin_record, false); -} - -void OneWireSlave::pin_init_interrupt_in_isr_ctx(void) { - hal_gpio_init(one_wire_pin_record, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); - __HAL_GPIO_EXTI_CLEAR_IT(one_wire_pin_record->pin); -} - -void OneWireSlave::pin_init_opendrain_in_isr_ctx(void) { - hal_gpio_init(one_wire_pin_record, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - __HAL_GPIO_EXTI_CLEAR_IT(one_wire_pin_record->pin); -} - -OneWiteTimeType OneWireSlave::wait_while_gpio_is(OneWiteTimeType time, const bool pin_value) { - uint32_t start = DWT->CYCCNT; - uint32_t time_ticks = time * __instructions_per_us; - uint32_t time_captured; - - do { - time_captured = DWT->CYCCNT; - if(hal_gpio_read(one_wire_pin_record) != pin_value) { - OneWiteTimeType remaining_time = time_ticks - (time_captured - start); - remaining_time /= __instructions_per_us; - return remaining_time; - } - } while((time_captured - start) < time_ticks); - - return 0; -} - -bool OneWireSlave::show_presence(void) { - // wait while master delay presence check - wait_while_gpio_is(OWET::PRESENCE_TIMEOUT, true); - - // show presence - pin_set_low(); - delay_us(OWET::PRESENCE_MIN); - pin_set_float(); - - // somebody also can show presence - const OneWiteTimeType wait_low_time = OWET::PRESENCE_MAX - OWET::PRESENCE_MIN; - - // so we will wait - if(wait_while_gpio_is(wait_low_time, false) == 0) { - error = OneWireSlaveError::PRESENCE_LOW_ON_LINE; - return false; - } - - return true; -} - -bool OneWireSlave::receive_bit(void) { - // wait while bus is low - OneWiteTimeType time = OWET::SLOT_MAX; - time = wait_while_gpio_is(time, false); - if(time == 0) { - error = OneWireSlaveError::RESET_IN_PROGRESS; - return false; - } - - // wait while bus is high - time = OWET::MSG_HIGH_TIMEOUT; - time = wait_while_gpio_is(time, true); - if(time == 0) { - error = OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH; - return false; - } - - // wait a time of zero - time = OWET::READ_MIN; - time = wait_while_gpio_is(time, false); - - return (time > 0); -} - -bool OneWireSlave::send_bit(bool value) { - const bool write_zero = !value; - - // wait while bus is low - OneWiteTimeType time = OWET::SLOT_MAX; - time = wait_while_gpio_is(time, false); - if(time == 0) { - error = OneWireSlaveError::RESET_IN_PROGRESS; - return false; - } - - // wait while bus is high - time = OWET::MSG_HIGH_TIMEOUT; - time = wait_while_gpio_is(time, true); - if(time == 0) { - error = OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH; - return false; - } - - // choose write time - if(write_zero) { - pin_set_low(); - time = OWET::WRITE_ZERO; - } else { - time = OWET::READ_MAX; - } - - // hold line for ZERO or ONE time - delay_us(time); - pin_set_float(); - - return true; -} - -bool OneWireSlave::send(const uint8_t* address, const uint8_t data_length) { - uint8_t bytes_sent = 0; - - pin_set_float(); - - // bytes loop - for(; bytes_sent < data_length; ++bytes_sent) { - const uint8_t data_byte = address[bytes_sent]; - - // bit loop - for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { - if(!send_bit(static_cast(bit_mask & data_byte))) { - // if we cannot send first bit - if((bit_mask == 0x01) && (error == OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH)) - error = OneWireSlaveError::FIRST_BIT_OF_BYTE_TIMEOUT; - return false; - } - } - } - return true; -} - -bool OneWireSlave::receive(uint8_t* data, const uint8_t data_length) { - uint8_t bytes_received = 0; - - pin_set_float(); - - for(; bytes_received < data_length; ++bytes_received) { - uint8_t value = 0; - - for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { - if(receive_bit()) value |= bit_mask; - } - - data[bytes_received] = value; - } - return (bytes_received != data_length); -} - -void OneWireSlave::cmd_search_rom(void) { - const uint8_t key_bytes = 8; - uint8_t* key = device->id_storage; - - for(uint8_t i = 0; i < key_bytes; i++) { - uint8_t key_byte = key[i]; - - for(uint8_t j = 0; j < 8; j++) { - bool bit = (key_byte >> j) & 0x01; - - if(!send_bit(bit)) return; - if(!send_bit(!bit)) return; - - receive_bit(); - if(error != OneWireSlaveError::NO_ERROR) return; - } - } -} - -bool OneWireSlave::receive_and_process_cmd(void) { - uint8_t cmd; - receive(&cmd, 1); - - if(error == OneWireSlaveError::RESET_IN_PROGRESS) return true; - if(error != OneWireSlaveError::NO_ERROR) return false; - - switch(cmd) { - case 0xF0: - // SEARCH ROM - cmd_search_rom(); - return true; - - case 0x0F: - case 0x33: - // READ ROM - device->send_id(); - return true; - - default: // Unknown command - error = OneWireSlaveError::INCORRECT_ONEWIRE_CMD; - } - - if(error == OneWireSlaveError::RESET_IN_PROGRESS) return true; - return (error == OneWireSlaveError::NO_ERROR); -} - -bool OneWireSlave::bus_start(void) { - bool result = true; - - if(device == nullptr) { - result = false; - } else { - FURI_CRITICAL_ENTER(); - pin_init_opendrain_in_isr_ctx(); - error = OneWireSlaveError::NO_ERROR; - - if(show_presence()) { - // TODO think about multiple command cycles - receive_and_process_cmd(); - result = - (error == OneWireSlaveError::NO_ERROR || - error == OneWireSlaveError::INCORRECT_ONEWIRE_CMD); - - } else { - result = false; - } - - pin_init_interrupt_in_isr_ctx(); - FURI_CRITICAL_EXIT(); - } - - return result; -} - -void OneWireSlave::exti_callback(void* _ctx) { - OneWireSlave* _this = static_cast(_ctx); - - volatile bool input_state = hal_gpio_read(_this->one_wire_pin_record); - static uint32_t pulse_start = 0; - - if(input_state) { - uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / __instructions_per_us; - if(pulse_length >= OWET::RESET_MIN) { - if(pulse_length <= OWET::RESET_MAX) { - // reset cycle ok - bool result = _this->bus_start(); - if(result && _this->result_cb != nullptr) { - _this->result_cb(result, _this->result_cb_ctx); - } - } else { - error = OneWireSlaveError::VERY_LONG_RESET; - } - } else { - error = OneWireSlaveError::VERY_SHORT_RESET; - } - } else { - //FALL event - pulse_start = DWT->CYCCNT; - } -} diff --git a/lib/onewire/one_wire_slave.h b/lib/onewire/one_wire_slave.h deleted file mode 100644 index 2773d137..00000000 --- a/lib/onewire/one_wire_slave.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include -#include -#include "one_wire_timings.h" - -class OneWireDevice; -typedef void (*OneWireSlaveResultCallback)(bool success, void* ctx); - -class OneWireSlave { -private: - enum class OneWireSlaveError : uint8_t { - NO_ERROR = 0, - READ_TIMESLOT_TIMEOUT, - WRITE_TIMESLOT_TIMEOUT, - WAIT_RESET_TIMEOUT, - VERY_LONG_RESET, - VERY_SHORT_RESET, - PRESENCE_LOW_ON_LINE, - READ_TIMESLOT_TIMEOUT_LOW, - AWAIT_TIMESLOT_TIMEOUT_HIGH, - PRESENCE_HIGH_ON_LINE, - INCORRECT_ONEWIRE_CMD, - INCORRECT_SLAVE_USAGE, - TRIED_INCORRECT_WRITE, - FIRST_TIMESLOT_TIMEOUT, - FIRST_BIT_OF_BYTE_TIMEOUT, - RESET_IN_PROGRESS - }; - - const GpioPin* one_wire_pin_record; - - // exti callback and its pointer - void exti_callback(void* _ctx); - void (*exti_cb)(void* _ctx); - - uint32_t __instructions_per_us; - - OneWireSlaveError error; - OneWireDevice* device = nullptr; - - bool bus_start(void); - - void pin_set_float(void); - void pin_set_low(void); - void pin_init_interrupt_in_isr_ctx(void); - void pin_init_opendrain_in_isr_ctx(void); - - OneWiteTimeType wait_while_gpio_is(OneWiteTimeType time, const bool pin_value); - - bool show_presence(void); - bool receive_and_process_cmd(void); - - bool receive_bit(void); - bool send_bit(bool value); - - void cmd_search_rom(void); - - OneWireSlaveResultCallback result_cb = nullptr; - void* result_cb_ctx = nullptr; - -public: - void start(void); - void stop(void); - - bool send(const uint8_t* address, const uint8_t data_length); - bool receive(uint8_t* data, const uint8_t data_length = 1); - - OneWireSlave(const GpioPin* pin); - ~OneWireSlave(); - - void attach(OneWireDevice* device); - void deattach(void); - - void set_result_callback(OneWireSlaveResultCallback result_cb, void* ctx); -}; \ No newline at end of file diff --git a/lib/onewire/one_wire_timings.cpp b/lib/onewire/one_wire_timings.cpp deleted file mode 100644 index 23a4a934..00000000 --- a/lib/onewire/one_wire_timings.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "one_wire_timings.h" - -// fix pre C++17 "undefined reference" errors -constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MIN; -constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MAX; - -constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_TIMEOUT; -constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MIN; -constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MAX; - -constexpr const OneWiteTimeType OneWireEmulateTiming::MSG_HIGH_TIMEOUT; -constexpr const OneWiteTimeType OneWireEmulateTiming::SLOT_MAX; - -constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MIN; -constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MAX; -constexpr const OneWiteTimeType OneWireEmulateTiming::WRITE_ZERO; diff --git a/lib/onewire/one_wire_timings.h b/lib/onewire/one_wire_timings.h deleted file mode 100644 index 19aa9e03..00000000 --- a/lib/onewire/one_wire_timings.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include - -class __OneWireTiming { -public: - constexpr static const uint16_t TIMING_A = 9; - constexpr static const uint16_t TIMING_B = 64; - constexpr static const uint16_t TIMING_C = 64; - constexpr static const uint16_t TIMING_D = 14; - constexpr static const uint16_t TIMING_E = 9; - constexpr static const uint16_t TIMING_F = 55; - constexpr static const uint16_t TIMING_G = 0; - constexpr static const uint16_t TIMING_H = 480; - constexpr static const uint16_t TIMING_I = 70; - constexpr static const uint16_t TIMING_J = 410; -}; - -class OneWireTiming { -public: - constexpr static const uint16_t WRITE_1_DRIVE = __OneWireTiming::TIMING_A; - constexpr static const uint16_t WRITE_1_RELEASE = __OneWireTiming::TIMING_B; - - constexpr static const uint16_t WRITE_0_DRIVE = __OneWireTiming::TIMING_C; - constexpr static const uint16_t WRITE_0_RELEASE = __OneWireTiming::TIMING_D; - - constexpr static const uint16_t READ_DRIVE = 3; - constexpr static const uint16_t READ_RELEASE = __OneWireTiming::TIMING_E; - constexpr static const uint16_t READ_DELAY_POST = __OneWireTiming::TIMING_F; - - constexpr static const uint16_t RESET_DELAY_PRE = __OneWireTiming::TIMING_G; - constexpr static const uint16_t RESET_DRIVE = __OneWireTiming::TIMING_H; - constexpr static const uint16_t RESET_RELEASE = __OneWireTiming::TIMING_I; - constexpr static const uint16_t RESET_DELAY_POST = __OneWireTiming::TIMING_J; -}; - -typedef uint32_t OneWiteTimeType; - -class OneWireEmulateTiming { -public: - constexpr static const OneWiteTimeType RESET_MIN = 270; - constexpr static const OneWiteTimeType RESET_MAX = 960; - - constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = 20; - constexpr static const OneWiteTimeType PRESENCE_MIN = 100; - constexpr static const OneWiteTimeType PRESENCE_MAX = 480; - - constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = 15000; - constexpr static const OneWiteTimeType SLOT_MAX = 135; - - constexpr static const OneWiteTimeType READ_MIN = 20; - constexpr static const OneWiteTimeType READ_MAX = 60; - constexpr static const OneWiteTimeType WRITE_ZERO = 30; -}; \ No newline at end of file