From cf1c8fb2239cea509a1b6b7c72302549b0b159f7 Mon Sep 17 00:00:00 2001 From: DrZlo13 Date: Thu, 28 Jan 2021 22:30:31 +1000 Subject: [PATCH] [FL-85][FL-446][FL-720] Dallas key blanks and OneWire lib rework (#313) * sepate one wire class * TM2004 writer * app mode write ds1990 * test another blanks protocol * new ibutton slave * one wire states * tim1 capture compare and update interrupts * interrupt mgr, new timers IRQ * discard HAL_TIM_PeriodElapsedCallback from main * add exti_14 line * add external interrupt callback * use int mgr in input * better interrupt managment * add interrupt callback enable and disable fns * properly init app * changed timings * rename one wire classes * use new owb classes * properly remove interrupts * new blanks writer * remove unused tests * new core includes * extern c guard * fix api_interrupt_remove usage * remove debug info, new way to detect blanks writing * remove copy constructor * change keys template * fix app sources recipe --- applications/applications.mk | 2 +- applications/ibutton/blanks_writer.cpp | 319 +++++++++++ applications/ibutton/blanks_writer.h | 40 ++ applications/ibutton/ibutton.cpp | 12 +- applications/ibutton/ibutton.h | 2 +- .../ibutton/ibutton_mode_dallas_emulate.h | 34 +- .../ibutton/ibutton_mode_dallas_read.h | 23 +- .../ibutton/ibutton_mode_dallas_write.h | 64 +++ applications/input/input.c | 11 +- applications/lf-rfid/lf-rfid.c | 3 +- applications/tests/furi_new_test.c | 97 ---- applications/tests/minunit_test.c | 6 - core/api-hal/api-interrupt-mgr.c | 107 +++- core/api-hal/api-interrupt-mgr.h | 7 +- firmware/targets/f4/Inc/stm32wbxx_it.h | 2 + firmware/targets/f4/Src/stm32wbxx_it.c | 34 +- .../targets/f4/api-hal/api-hal-timebase.h | 12 +- firmware/targets/f4/api-hal/api-interrupts.c | 23 + lib/cyfral/cyfral_reader_comp.h | 2 +- lib/onewire/one_wire_device.cpp | 23 +- lib/onewire/one_wire_device.h | 20 +- lib/onewire/one_wire_device_ds_1990.cpp | 15 - lib/onewire/one_wire_device_ds_1990.h | 5 - .../{one_wire_gpio.h => one_wire_master.cpp} | 43 +- lib/onewire/one_wire_master.h | 21 + lib/onewire/one_wire_slave.cpp | 312 +++++++++++ lib/onewire/one_wire_slave.h | 74 +++ lib/onewire/one_wire_slave_gpio.cpp | 517 ------------------ lib/onewire/one_wire_slave_gpio.h | 92 ---- lib/onewire/one_wire_timings.cpp | 17 +- lib/onewire/one_wire_timings.h | 29 +- 31 files changed, 1099 insertions(+), 869 deletions(-) create mode 100644 applications/ibutton/blanks_writer.cpp create mode 100644 applications/ibutton/blanks_writer.h create mode 100644 applications/ibutton/ibutton_mode_dallas_write.h delete mode 100644 applications/tests/furi_new_test.c rename lib/onewire/{one_wire_gpio.h => one_wire_master.cpp} (70%) create mode 100644 lib/onewire/one_wire_master.h create mode 100644 lib/onewire/one_wire_slave.cpp create mode 100644 lib/onewire/one_wire_slave.h delete mode 100644 lib/onewire/one_wire_slave_gpio.cpp delete mode 100644 lib/onewire/one_wire_slave_gpio.h diff --git a/applications/applications.mk b/applications/applications.mk index a7dd5645..63487ef8 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -286,7 +286,7 @@ endif BUILD_IBUTTON ?= 0 ifeq ($(BUILD_IBUTTON), 1) CFLAGS += -DBUILD_IBUTTON -CPP_SOURCES += $(APP_DIR)/ibutton/ibutton.cpp +CPP_SOURCES += $(wildcard $(APP_DIR)/ibutton/*.cpp) endif APP_SDNFC ?= 0 diff --git a/applications/ibutton/blanks_writer.cpp b/applications/ibutton/blanks_writer.cpp new file mode 100644 index 00000000..9e5976fe --- /dev/null +++ b/applications/ibutton/blanks_writer.cpp @@ -0,0 +1,319 @@ +#include "blanks_writer.h" + +class RW1990_1 { +public: + constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xD1; + constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0xB5; + constexpr static const uint8_t CMD_WRITE_ROM = 0xD5; +}; + +class RW1990_2 { +public: + constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0x1D; + constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0x1E; + constexpr static const uint8_t CMD_WRITE_ROM = 0xD5; +}; + +class TM2004 { +public: + constexpr static const uint8_t CMD_READ_STATUS = 0xAA; + constexpr static const uint8_t CMD_READ_MEMORY = 0xF0; + constexpr static const uint8_t CMD_WRITE_ROM = 0x3C; + constexpr static const uint8_t CMD_FINALIZATION = 0x35; + + constexpr static const uint8_t ANSWER_READ_MEMORY = 0xF5; +}; + +class TM01 { +public: + constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xC1; + constexpr static const uint8_t CMD_WRITE_ROM = 0xC5; + constexpr static const uint8_t CMD_SWITCH_TO_CYFRAL = 0xCA; + constexpr static const uint8_t CMD_SWITCH_TO_METAKOM = 0xCB; +}; + +class DS1990 { +public: + constexpr static const uint8_t CMD_READ_ROM = 0x33; +}; + +#include +#include +#include + +void BlanksWriter::onewire_release(void) { + gpio_write(gpio, true); +} + +void BlanksWriter::onewire_write_one_bit(bool value, uint32_t delay = 10000) { + onewire->write_bit(value); + delay_us(delay); + onewire_release(); +} + +BlanksWriter::BlanksWriter(const GpioPin* one_wire_gpio) { + gpio = one_wire_gpio; + onewire = new OneWireMaster(gpio); +} + +BlanksWriter::~BlanksWriter() { + free(onewire); +} + +WriterResult BlanksWriter::write(KeyType type, const uint8_t* key, uint8_t key_length) { + uint8_t write_result = -1; + WriterResult result = WR_ERROR; + + bool same_key = false; + + osKernelLock(); + bool presence = onewire->reset(); + osKernelUnlock(); + + if(presence) { + switch(type) { + case KeyType::KEY_DS1990: + same_key = compare_key_ds1990(key, key_length); + + if(!same_key) { + // currently we can write: + // RW1990, TM08v2, TM08vi-2 by write_1990_1() + // RW2004, RW2004 with EEPROM by write_TM2004(); + + if(write_result != 1) { + write_result = write_1990_1(key, key_length); + } + if(write_result != 1) { + write_result = write_1990_2(key, key_length); + } + if(write_result != 1) { + write_result = write_TM2004(key, key_length); + } + + if(write_result == 1) { + result = WR_OK; + } else if(write_result == 0) { + result = WR_ERROR; + } + } else { + write_result = 0; + result = WR_SAME_KEY; + } + break; + + default: + break; + } + } + + return result; +} + +bool BlanksWriter::write_TM2004(const uint8_t* key, uint8_t key_length) { + uint8_t answer; + bool result = true; + + osKernelLock(); + __disable_irq(); + + // write rom, addr is 0x0000 + onewire->reset(); + onewire->write(TM2004::CMD_WRITE_ROM); + onewire->write(0x00); + onewire->write(0x00); + + // write key + for(uint8_t i = 0; i < key_length; i++) { + // write key byte + onewire->write(key[i]); + answer = onewire->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->read(); + + // check that writed and readed are same + if(key[i] != answer) { + result = false; + break; + } + } + + onewire->reset(); + + __enable_irq(); + osKernelUnlock(); + + return result; +} + +bool BlanksWriter::write_1990_1(const uint8_t* key, uint8_t key_length) { + bool result = true; + + osKernelLock(); + __disable_irq(); + + // unlock + onewire->reset(); + onewire->write(RW1990_1::CMD_WRITE_RECORD_FLAG); + delay_us(10); + onewire_write_one_bit(0, 5000); + + // write key + onewire->reset(); + onewire->write(RW1990_1::CMD_WRITE_ROM); + for(uint8_t i = 0; i < key_length; i++) { + // inverted key for RW1990.1 + write_byte_ds1990(~key[i]); + delay_us(30000); + } + + // lock + onewire->write(RW1990_1::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(1); + + __enable_irq(); + osKernelUnlock(); + + if(!compare_key_ds1990(key, key_length)) { + result = false; + } + + return result; +} + +bool BlanksWriter::write_1990_2(const uint8_t* key, uint8_t key_length) { + bool result = true; + + osKernelLock(); + __disable_irq(); + + // unlock + onewire->reset(); + onewire->write(RW1990_2::CMD_WRITE_RECORD_FLAG); + delay_us(10); + onewire_write_one_bit(1, 5000); + + // write key + onewire->reset(); + onewire->write(RW1990_2::CMD_WRITE_ROM); + for(uint8_t i = 0; i < key_length; i++) { + write_byte_ds1990(key[i]); + delay_us(30000); + } + + // lock + onewire->write(RW1990_2::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(0); + + __enable_irq(); + osKernelUnlock(); + + if(!compare_key_ds1990(key, key_length)) { + result = false; + } + + return result; +} + +// TODO: untested +bool BlanksWriter::write_TM01(KeyType type, const uint8_t* key, uint8_t key_length) { + bool result = true; + + osKernelLock(); + __disable_irq(); + + // unlock + onewire->reset(); + onewire->write(TM01::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(1, 10000); + + // write key + onewire->reset(); + onewire->write(TM01::CMD_WRITE_ROM); + + // TODO: key types + //if(type == KEY_METAKOM || type == KEY_CYFRAL) { + //} else { + for(uint8_t i = 0; i < key_length; i++) { + write_byte_ds1990(key[i]); + delay_us(10000); + } + //} + + // lock + onewire->write(TM01::CMD_WRITE_RECORD_FLAG); + onewire_write_one_bit(0, 10000); + + __enable_irq(); + osKernelUnlock(); + + if(!compare_key_ds1990(key, key_length)) { + result = false; + } + + osKernelLock(); + __disable_irq(); + + if(type == KEY_METAKOM || type == KEY_CYFRAL) { + onewire->reset(); + if(type == KEY_CYFRAL) + onewire->write(TM01::CMD_SWITCH_TO_CYFRAL); + else + onewire->write(TM01::CMD_SWITCH_TO_METAKOM); + onewire_write_one_bit(1); + } + + __enable_irq(); + osKernelUnlock(); + + return result; +} + +void BlanksWriter::write_byte_ds1990(uint8_t data) { + for(uint8_t n_bit = 0; n_bit < 8; n_bit++) { + onewire->write_bit(data & 1); + onewire_release(); + delay_us(5000); + data = data >> 1; + } +} + +bool BlanksWriter::compare_key_ds1990(const uint8_t* key, uint8_t key_length) { + uint8_t buff[key_length]; + bool result = false; + + osKernelLock(); + bool presence = onewire->reset(); + osKernelUnlock(); + + if(presence) { + osKernelLock(); + __disable_irq(); + onewire->write(DS1990::CMD_READ_ROM); + onewire->read_bytes(buff, key_length); + __enable_irq(); + osKernelUnlock(); + + result = true; + for(uint8_t i = 0; i < 8; i++) { + if(key[i] != buff[i]) { + result = false; + break; + } + } + } + return result; +} + +void BlanksWriter::start() { + onewire->start(); +} + +void BlanksWriter::stop() { + onewire->stop(); +} \ No newline at end of file diff --git a/applications/ibutton/blanks_writer.h b/applications/ibutton/blanks_writer.h new file mode 100644 index 00000000..8b8f84cd --- /dev/null +++ b/applications/ibutton/blanks_writer.h @@ -0,0 +1,40 @@ +#pragma once +#include "one_wire_master.h" +#include "maxim_crc.h" + +typedef enum { + KEY_DS1990, /**< DS1990 */ + KEY_CYFRAL, /**< CYFRAL*/ + KEY_METAKOM, /**< METAKOM */ +} KeyType; + +typedef enum { + WR_OK, + WR_SAME_KEY, + WR_ERROR, +} WriterResult; + +class BlanksWriter { +private: + const GpioPin* gpio; + OneWireMaster* onewire; + + void onewire_release(void); + void onewire_write_one_bit(bool value, uint32_t delay); + + bool write_TM2004(const uint8_t* key, uint8_t key_length); + bool write_1990_1(const uint8_t* key, uint8_t key_length); + bool write_1990_2(const uint8_t* key, uint8_t key_length); + bool write_TM01(KeyType type, const uint8_t* key, uint8_t key_length); + + void write_byte_ds1990(uint8_t data); + bool compare_key_ds1990(const uint8_t* key, uint8_t key_length); + +public: + BlanksWriter(const GpioPin* one_wire_gpio); + ~BlanksWriter(); + + WriterResult write(KeyType type, const uint8_t* key, uint8_t key_length); + void start(); + void stop(); +}; diff --git a/applications/ibutton/ibutton.cpp b/applications/ibutton/ibutton.cpp index a19b6127..98424cad 100644 --- a/applications/ibutton/ibutton.cpp +++ b/applications/ibutton/ibutton.cpp @@ -1,6 +1,7 @@ #include "ibutton.h" #include "ibutton_mode_dallas_read.h" #include "ibutton_mode_dallas_emulate.h" +#include "ibutton_mode_dallas_write.h" #include "ibutton_mode_cyfral_read.h" #include "ibutton_mode_cyfral_emulate.h" @@ -8,8 +9,9 @@ void AppiButton::run() { mode[0] = new AppiButtonModeDallasRead(this); mode[1] = new AppiButtonModeDallasEmulate(this); - mode[2] = new AppiButtonModeCyfralRead(this); - mode[3] = new AppiButtonModeCyfralEmulate(this); + mode[2] = new AppiButtonModeDallasWrite(this); + mode[3] = new AppiButtonModeCyfralRead(this); + mode[4] = new AppiButtonModeCyfralEmulate(this); switch_to_mode(0); @@ -21,6 +23,7 @@ void AppiButton::run() { gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain); + api_hal_timebase_insomnia_enter(); app_ready(); AppiButtonEvent event; @@ -29,9 +32,10 @@ void AppiButton::run() { if(event.type == AppiButtonEvent::EventTypeKey) { // press events if(event.value.input.state && event.value.input.input == InputBack) { - printf("[ibutton] bye!\n"); - // TODO remove all widgets create by app widget_enabled_set(widget, false); + gui_remove_widget(gui, widget); + api_hal_timebase_insomnia_exit(); + osThreadExit(); } diff --git a/applications/ibutton/ibutton.h b/applications/ibutton/ibutton.h index 6bfcaabe..17d344e9 100644 --- a/applications/ibutton/ibutton.h +++ b/applications/ibutton/ibutton.h @@ -56,7 +56,7 @@ public: const GpioPin* red_led_record; const GpioPin* green_led_record; - static const uint8_t modes_count = 4; + static const uint8_t modes_count = 5; AppTemplateMode* mode[modes_count]; void run(); diff --git a/applications/ibutton/ibutton_mode_dallas_emulate.h b/applications/ibutton/ibutton_mode_dallas_emulate.h index be458ce2..02a0f4dd 100644 --- a/applications/ibutton/ibutton_mode_dallas_emulate.h +++ b/applications/ibutton/ibutton_mode_dallas_emulate.h @@ -1,38 +1,50 @@ #pragma once #include "ibutton.h" -#include "one_wire_slave_gpio.h" +#include "one_wire_slave.h" #include "one_wire_device_ds_1990.h" +#include "callback-connector.h" +#include class AppiButtonModeDallasEmulate : public AppTemplateMode { +private: + void result_callback(bool success, void* ctx); + public: const char* name = "dallas emulate"; AppiButton* app; - OneWireGpioSlave* onewire_slave; DS1990 key; + OneWireSlave* onewire_slave; void event(AppiButtonEvent* event, AppiButtonState* state); void render(Canvas* canvas, AppiButtonState* state); void acquire(); void release(); + std::atomic emulated_result{false}; + AppiButtonModeDallasEmulate(AppiButton* parent_app) : key(1, 2, 3, 4, 5, 6, 7) { app = parent_app; // TODO open record const GpioPin* one_wire_pin_record = &ibutton_gpio; - onewire_slave = new OneWireGpioSlave(one_wire_pin_record); - onewire_slave->attach(key); + onewire_slave = new OneWireSlave(one_wire_pin_record); + onewire_slave->attach(&key); + + auto cb = cbc::obtain_connector(this, &AppiButtonModeDallasEmulate::result_callback); + onewire_slave->set_result_callback(cb, this); }; }; +void AppiButtonModeDallasEmulate::result_callback(bool success, void* ctx) { + AppiButtonModeDallasEmulate* _this = static_cast(ctx); + _this->emulated_result = success; +} + void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* state) { if(event->type == AppiButtonEvent::EventTypeTick) { - onewire_slave->detach(key); - memcpy(key.id_storage, state->dallas_address[state->dallas_address_index], 8); - onewire_slave->attach(key); - - if(onewire_slave->emulate()) { + if(emulated_result) { + emulated_result = false; app->blink_green(); } } else if(event->type == AppiButtonEvent::EventTypeKey) { @@ -44,6 +56,10 @@ void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* app->increase_dallas_address(); } } + + onewire_slave->deattach(); + memcpy(key.id_storage, state->dallas_address[state->dallas_address_index], 8); + onewire_slave->attach(&key); } void AppiButtonModeDallasEmulate::render(Canvas* canvas, AppiButtonState* state) { diff --git a/applications/ibutton/ibutton_mode_dallas_read.h b/applications/ibutton/ibutton_mode_dallas_read.h index 0ea554c9..2e23b38a 100644 --- a/applications/ibutton/ibutton_mode_dallas_read.h +++ b/applications/ibutton/ibutton_mode_dallas_read.h @@ -1,13 +1,13 @@ #pragma once #include "ibutton.h" -#include "one_wire_gpio.h" +#include "one_wire_master.h" #include "maxim_crc.h" class AppiButtonModeDallasRead : public AppTemplateMode { public: const char* name = "dallas read"; AppiButton* app; - OneWireGpio* onewire; + OneWireMaster* onewire; void event(AppiButtonEvent* event, AppiButtonState* state); void render(Canvas* canvas, AppiButtonState* state); @@ -19,7 +19,7 @@ public: // TODO open record const GpioPin* one_wire_pin_record = &ibutton_gpio; - onewire = new OneWireGpio(one_wire_pin_record); + onewire = new OneWireMaster(one_wire_pin_record); }; }; @@ -33,30 +33,17 @@ void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* st osKernelUnlock(); if(result) { - printf("device on line\n"); - - delay(50); osKernelLock(); + __disable_irq(); onewire->write(0x33); onewire->read_bytes(address, 8); + __enable_irq(); osKernelUnlock(); - printf("address: %x", address[0]); - for(uint8_t i = 1; i < 8; i++) { - printf(":%x", address[i]); - } - printf("\n"); - - printf("crc8: %x\n", maxim_crc8(address, 7)); - if(maxim_crc8(address, 8) == 0) { - printf("CRC valid\n"); memcpy(app->state.dallas_address[app->state.dallas_address_index], address, 8); app->blink_green(); - } else { - printf("CRC invalid\n"); } - } else { } } else if(event->type == AppiButtonEvent::EventTypeKey) { if(event->value.input.state && event->value.input.input == InputUp) { diff --git a/applications/ibutton/ibutton_mode_dallas_write.h b/applications/ibutton/ibutton_mode_dallas_write.h new file mode 100644 index 00000000..6f0f72c8 --- /dev/null +++ b/applications/ibutton/ibutton_mode_dallas_write.h @@ -0,0 +1,64 @@ +#pragma once +#include "ibutton.h" +#include "blanks_writer.h" +#include "maxim_crc.h" + +class AppiButtonModeDallasWrite : public AppTemplateMode { +public: + const char* name = "dallas read"; + AppiButton* app; + BlanksWriter* writer; + + void event(AppiButtonEvent* event, AppiButtonState* state); + void render(Canvas* canvas, AppiButtonState* state); + void acquire(); + void release(); + + const GpioPin* one_wire_pin_record; + + AppiButtonModeDallasWrite(AppiButton* parent_app) { + app = parent_app; + + // TODO open record + one_wire_pin_record = &ibutton_gpio; + writer = new BlanksWriter(one_wire_pin_record); + }; +}; + +void AppiButtonModeDallasWrite::event(AppiButtonEvent* event, AppiButtonState* state) { + if(event->type == AppiButtonEvent::EventTypeTick) { + WriterResult result = + writer->write(KEY_DS1990, state->dallas_address[state->dallas_address_index], 8); + + if(result == WR_SAME_KEY) { + app->blink_green(); + } + + if(result == WR_OK) { + app->blink_red(); + } + + } else if(event->type == AppiButtonEvent::EventTypeKey) { + if(event->value.input.state && event->value.input.input == InputUp) { + app->decrease_dallas_address(); + } + + if(event->value.input.state && event->value.input.input == InputDown) { + app->increase_dallas_address(); + } + } +} + +void AppiButtonModeDallasWrite::render(Canvas* canvas, AppiButtonState* state) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 2, 25, "< Dallas write >"); + app->render_dallas_list(canvas, state); +} + +void AppiButtonModeDallasWrite::acquire() { + writer->start(); +} + +void AppiButtonModeDallasWrite::release() { + writer->stop(); +} \ No newline at end of file diff --git a/applications/input/input.c b/applications/input/input.c index 8b522d02..00e0f7b8 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -18,6 +18,8 @@ static InputState input_state = { false, }; +static void exti_input_callback(void* _pin, void* _ctx); + void input_task(void* p) { uint32_t state_bits = 0; uint8_t debounce_counters[INPUT_COUNT]; @@ -38,6 +40,8 @@ void input_task(void* p) { furi_record_create("input_state", &input_state_record); furi_record_create("input_events", &input_events_record); + api_interrupt_add(exti_input_callback, InterruptTypeExternalInterrupt, NULL); + // we ready to work initialized = true; @@ -103,7 +107,10 @@ void input_task(void* p) { } } -void HAL_GPIO_EXTI_Callback(uint16_t pin) { +static void exti_input_callback(void* _pin, void* _ctx) { + // interrupt manager get us pin constant, so... + uint32_t pin = (uint32_t)_pin; + #ifdef APP_NFC if(pin == NFC_IRQ_Pin) { nfc_isr(); @@ -121,4 +128,4 @@ void HAL_GPIO_EXTI_Callback(uint16_t pin) { if(!initialized) return; signal_event(&event); -} +} \ No newline at end of file diff --git a/applications/lf-rfid/lf-rfid.c b/applications/lf-rfid/lf-rfid.c index a5c26f3a..d94de580 100644 --- a/applications/lf-rfid/lf-rfid.c +++ b/applications/lf-rfid/lf-rfid.c @@ -330,7 +330,8 @@ void lf_rfid_workaround(void* p) { api_interrupt_add( comparator_trigger_callback, InterruptTypeComparatorTrigger, comp_ctx); } else { - api_interrupt_remove(comparator_trigger_callback); + api_interrupt_remove( + comparator_trigger_callback, InterruptTypeComparatorTrigger); } hal_pwmn_set( diff --git a/applications/tests/furi_new_test.c b/applications/tests/furi_new_test.c deleted file mode 100644 index c507353b..00000000 --- a/applications/tests/furi_new_test.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include "minunit.h" -#include "furi-new.h" - -const int int_value_init = 0x1234; -const int int_value_changed = 0x5678; -osMessageQueueId_t test_messages; - -typedef struct { - char text[256]; - bool result; -} test_message; - -#define SEND_MESSAGE(value, data) \ - { \ - message.result = value; \ - snprintf(message.text, 256, "Error at line %d, %s", __LINE__, data); \ - osMessageQueuePut(test_messages, &message, 0U, 0U); \ - } - -void _furi_new_wait() { - osThreadFlagsWait(0x0001U, osFlagsWaitAny, osWaitForever); -} - -void _furi_new_continue(FuriAppId thread_id) { - osThreadFlagsSet(thread_id, 0x0001U); -} - -void _furi_new_main_app(void* p) { - test_message message; - - _furi_new_wait(); - - int another_test_value = int_value_init; - furi_record_create("test/another_app_record", &another_test_value); - - SEND_MESSAGE(false, "dummy text"); - - new_flapp_app_exit(); -} - -void test_furi_new() { - test_message message; - test_messages = osMessageQueueNew(1, sizeof(test_message), NULL); - - // init core - new_furi_init(); - - // launch test thread - FuriAppId main_app = new_flapp_app_start(_furi_new_main_app, "main_app", 512, NULL); - _furi_new_continue(main_app); - - while(1) { - if(osMessageQueueGet(test_messages, &message, NULL, osWaitForever) == osOK) { - if(message.result == true) { - break; - } else { - mu_assert(false, message.text); - } - } - }; - - /* - // test that "create" wont affect pointer value - furi_record_create("test/record", &test_value); - mu_assert_int_eq(test_value, int_value_init); - - // test that we get correct pointer - int* test_value_pointer = furi_record_open("test/record"); - mu_assert_pointers_not_eq(test_value_pointer, NULL); - mu_assert_pointers_eq(test_value_pointer, &test_value); - - *test_value_pointer = int_value_changed; - mu_assert_int_eq(test_value, int_value_changed); - - // start another app - new_record_available = osSemaphoreNew(1, 1, NULL); - osSemaphoreAcquire(new_record_available, osWaitForever); - - osThreadAttr_t another_app_attr = {.name = "another_app", .stack_size = 512}; - osThreadId_t player = osThreadNew(another_app, NULL, &another_app_attr); - - // wait until app create record - osSemaphoreAcquire(new_record_available, osWaitForever); - - // open record, test that record pointed to int_value_init - test_value_pointer = furi_record_open("test/another_app_record"); - mu_assert_pointers_not_eq(test_value_pointer, NULL); - mu_assert_int_eq(*test_value_pointer, int_value_init); - - // test that we can close, (unsubscribe) from record - bool close_result = new_furi_close("test/another_app_record"); - mu_assert(close_result, "cannot close record"); - */ -} \ No newline at end of file diff --git a/applications/tests/minunit_test.c b/applications/tests/minunit_test.c index 87c312d7..0fa28313 100644 --- a/applications/tests/minunit_test.c +++ b/applications/tests/minunit_test.c @@ -16,7 +16,6 @@ void test_furi_value_manager(); void test_furi_event(); void test_furi_memmgr(); -void test_furi_new(); static int foo = 0; @@ -63,10 +62,6 @@ MU_TEST(mu_test_furi_memmgr) { test_furi_memmgr(); } -MU_TEST(mu_test_furi_new) { - test_furi_new(); -} - MU_TEST(mu_test_furi_value_expanders) { test_furi_value_composer(); test_furi_value_manager(); @@ -92,7 +87,6 @@ MU_TEST_SUITE(test_suite) { MU_RUN_TEST(mu_test_furi_event); MU_RUN_TEST(mu_test_furi_memmgr); - MU_RUN_TEST(mu_test_furi_new); } int run_minunit() { diff --git a/core/api-hal/api-interrupt-mgr.c b/core/api-hal/api-interrupt-mgr.c index 1dffffa8..30ce131e 100644 --- a/core/api-hal/api-interrupt-mgr.c +++ b/core/api-hal/api-interrupt-mgr.c @@ -1,23 +1,36 @@ #include "api-interrupt-mgr.h" +#include "mlib/m-dict.h" #include #include LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST); -list_interrupt_t interrupts; -osMutexId_t interrupt_list_mutex; +DICT_DEF2(dict_interrupt, uint32_t, M_DEFAULT_OPLIST, list_interrupt_t, M_A1_OPLIST); + +dict_interrupt_t interrupts_dict; +osMutexId_t interrupt_mutex; bool api_interrupt_init() { - interrupt_list_mutex = osMutexNew(NULL); - return (interrupt_list_mutex != NULL); + dict_interrupt_init(interrupts_dict); + interrupt_mutex = osMutexNew(NULL); + return (interrupt_mutex != NULL); } void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context) { - if(osMutexAcquire(interrupt_list_mutex, osWaitForever) == osOK) { + if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) { + list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type); + + if(list == NULL) { + list_interrupt_t new_list; + list_interrupt_init(new_list); + dict_interrupt_set_at(interrupts_dict, (uint32_t)type, new_list); + list = dict_interrupt_get(interrupts_dict, (uint32_t)type); + } + // put uninitialized item to the list // M_POD_OPLIST provide memset(&(a), 0, sizeof (a)) constructor // so item will not be ready until we set ready flag - InterruptCallbackItem* item = list_interrupt_push_new(interrupts); + InterruptCallbackItem* item = list_interrupt_push_new(*list); // initialize item item->callback = callback; @@ -28,26 +41,66 @@ void api_interrupt_add(InterruptCallback callback, InterruptType type, void* con // TODO remove on app exit //flapp_on_exit(api_interrupt_remove, callback); - osMutexRelease(interrupt_list_mutex); + osMutexRelease(interrupt_mutex); } } -void api_interrupt_remove(InterruptCallback callback) { - if(osMutexAcquire(interrupt_list_mutex, osWaitForever) == osOK) { - // iterate over items - list_interrupt_it_t it; - for(list_interrupt_it(it, interrupts); !list_interrupt_end_p(it); - list_interrupt_next(it)) { - const InterruptCallbackItem* item = list_interrupt_cref(it); +void api_interrupt_remove(InterruptCallback callback, InterruptType type) { + if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) { + list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type); - // if the iterator is equal to our element - if(item->callback == callback) { - list_interrupt_remove(interrupts, it); - break; + if(list != NULL) { + // iterate over items + list_interrupt_it_t it; + list_interrupt_it(it, *list); + while(!list_interrupt_end_p(it)) { + if(it->current->data.callback == callback) { + list_interrupt_remove(*list, it); + } else { + list_interrupt_next(it); + } } } - osMutexRelease(interrupt_list_mutex); + osMutexRelease(interrupt_mutex); + } +} + +void api_interrupt_enable(InterruptCallback callback, InterruptType type) { + if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) { + list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type); + + if(list != NULL) { + // iterate over items + list_interrupt_it_t it; + for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) { + // if the iterator is equal to our element + if(it->current->data.callback == callback) { + it->current->data.ready = true; + } + } + } + + osMutexRelease(interrupt_mutex); + } +} + +void api_interrupt_disable(InterruptCallback callback, InterruptType type) { + if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) { + list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type); + + if(list != NULL) { + // iterate over items + list_interrupt_it_t it; + for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) { + // if the iterator is equal to our element + if(it->current->data.callback == callback) { + it->current->data.ready = false; + } + } + } + + osMutexRelease(interrupt_mutex); } } @@ -55,14 +108,16 @@ void api_interrupt_call(InterruptType type, void* hw) { // that executed in interrupt ctx so mutex don't needed // but we need to check ready flag - // iterate over items - list_interrupt_it_t it; - for(list_interrupt_it(it, interrupts); !list_interrupt_end_p(it); list_interrupt_next(it)) { - const InterruptCallbackItem* item = list_interrupt_cref(it); + list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type); - // if the iterator is equal to our element - if(item->type == type && item->ready) { - item->callback(hw, item->context); + if(list != NULL) { + // iterate over items + list_interrupt_it_t it; + for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) { + // if the iterator is equal to our element + if(it->current->data.ready) { + it->current->data.callback(hw, it->current->data.context); + } } } } \ No newline at end of file diff --git a/core/api-hal/api-interrupt-mgr.h b/core/api-hal/api-interrupt-mgr.h index e34a4c3a..a38983d6 100644 --- a/core/api-hal/api-interrupt-mgr.h +++ b/core/api-hal/api-interrupt-mgr.h @@ -11,6 +11,9 @@ typedef void (*InterruptCallback)(void*, void*); typedef enum { InterruptTypeComparatorTrigger, InterruptTypeTimerCapture, + InterruptTypeTimerOutputCompare, + InterruptTypeTimerUpdate, + InterruptTypeExternalInterrupt, } InterruptType; typedef struct { @@ -22,7 +25,9 @@ typedef struct { bool api_interrupt_init(); void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context); -void api_interrupt_remove(InterruptCallback callback); +void api_interrupt_remove(InterruptCallback callback, InterruptType type); +void api_interrupt_enable(InterruptCallback callback, InterruptType type); +void api_interrupt_disable(InterruptCallback callback, InterruptType type); void api_interrupt_call(InterruptType type, void* hw); #ifdef __cplusplus diff --git a/firmware/targets/f4/Inc/stm32wbxx_it.h b/firmware/targets/f4/Inc/stm32wbxx_it.h index 43df3f69..6003805c 100644 --- a/firmware/targets/f4/Inc/stm32wbxx_it.h +++ b/firmware/targets/f4/Inc/stm32wbxx_it.h @@ -62,7 +62,9 @@ void ADC1_IRQHandler(void); void USB_LP_IRQHandler(void); void COMP_IRQHandler(void); void EXTI9_5_IRQHandler(void); +void TIM1_UP_TIM16_IRQHandler(void); void TIM1_TRG_COM_TIM17_IRQHandler(void); +void TIM1_CC_IRQHandler(void); void TIM2_IRQHandler(void); void EXTI15_10_IRQHandler(void); void HSEM_IRQHandler(void); diff --git a/firmware/targets/f4/Src/stm32wbxx_it.c b/firmware/targets/f4/Src/stm32wbxx_it.c index bd020eb6..1e706611 100644 --- a/firmware/targets/f4/Src/stm32wbxx_it.c +++ b/firmware/targets/f4/Src/stm32wbxx_it.c @@ -64,6 +64,9 @@ extern COMP_HandleTypeDef hcomp1; extern RTC_HandleTypeDef hrtc; extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim16; +extern TIM_HandleTypeDef htim17; + /* USER CODE BEGIN EV */ /* USER CODE END EV */ @@ -292,6 +295,21 @@ void EXTI9_5_IRQHandler(void) /* USER CODE END EXTI9_5_IRQn 1 */ } +/** + * @brief This function handles TIM1 update interrupt and TIM16 global interrupt. + */ +void TIM1_UP_TIM16_IRQHandler(void) +{ + /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */ + + /* USER CODE END TIM1_UP_TIM16_IRQn 0 */ + HAL_TIM_IRQHandler(&htim1); + HAL_TIM_IRQHandler(&htim16); + /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */ + + /* USER CODE END TIM1_UP_TIM16_IRQn 1 */ +} + /** * @brief This function handles TIM1 trigger and commutation interrupts and TIM17 global interrupt. */ @@ -306,6 +324,20 @@ void TIM1_TRG_COM_TIM17_IRQHandler(void) /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */ } +/** + * @brief This function handles TIM1 capture compare interrupt. + */ +void TIM1_CC_IRQHandler(void) +{ + /* USER CODE BEGIN TIM1_CC_IRQn 0 */ + + /* USER CODE END TIM1_CC_IRQn 0 */ + HAL_TIM_IRQHandler(&htim1); + /* USER CODE BEGIN TIM1_CC_IRQn 1 */ + + /* USER CODE END TIM1_CC_IRQn 1 */ +} + /** * @brief This function handles TIM2 global interrupt. */ @@ -333,7 +365,7 @@ void EXTI15_10_IRQHandler(void) HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12); HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); /* USER CODE BEGIN EXTI15_10_IRQn 1 */ - + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14); /* USER CODE END EXTI15_10_IRQn 1 */ } diff --git a/firmware/targets/f4/api-hal/api-hal-timebase.h b/firmware/targets/f4/api-hal/api-hal-timebase.h index 6c6a992d..18bffde7 100644 --- a/firmware/targets/f4/api-hal/api-hal-timebase.h +++ b/firmware/targets/f4/api-hal/api-hal-timebase.h @@ -2,6 +2,11 @@ #include + +#ifdef __cplusplus +extern "C" { +#endif + /* Initialize timebase * Configure and start tick timer */ @@ -24,4 +29,9 @@ void api_hal_timebase_insomnia_enter(); * @warning Internally decreases insomnia level. * Must be paired with api_hal_timebase_insomnia_enter */ -void api_hal_timebase_insomnia_exit(); \ No newline at end of file +void api_hal_timebase_insomnia_exit(); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f4/api-hal/api-interrupts.c b/firmware/targets/f4/api-hal/api-interrupts.c index 37f1a10b..56c42c4e 100644 --- a/firmware/targets/f4/api-hal/api-interrupts.c +++ b/firmware/targets/f4/api-hal/api-interrupts.c @@ -4,10 +4,33 @@ extern void api_interrupt_call(InterruptType type, void* hw); /* interrupts */ + +/* Comparator trigger event */ void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) { api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); } +/* Timer input capture event */ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) { api_interrupt_call(InterruptTypeTimerCapture, htim); +} + +/* Output compare event */ +void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { + api_interrupt_call(InterruptTypeTimerOutputCompare, htim); +} + +/* Timer update event */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { + api_interrupt_call(InterruptTypeTimerUpdate, htim); + + // handle HAL ticks + if(htim->Instance == TIM17) { + HAL_IncTick(); + } +} + +/* External interrupt event */ +void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { + api_interrupt_call(InterruptTypeExternalInterrupt, GPIO_Pin); } \ No newline at end of file diff --git a/lib/cyfral/cyfral_reader_comp.h b/lib/cyfral/cyfral_reader_comp.h index fa1b283f..963c21ec 100644 --- a/lib/cyfral/cyfral_reader_comp.h +++ b/lib/cyfral/cyfral_reader_comp.h @@ -256,7 +256,7 @@ void CyfralReaderComp::stop(void) { // disconnect comparator callback auto cmp_cb = cbc::obtain_connector(this, &CyfralReaderComp::comparator_trigger_callback); - api_interrupt_remove(cmp_cb); + api_interrupt_remove(cmp_cb, InterruptTypeComparatorTrigger); osMessageQueueDelete(comp_event_queue); } diff --git a/lib/onewire/one_wire_device.cpp b/lib/onewire/one_wire_device.cpp index 39129549..d1e6319a 100644 --- a/lib/onewire/one_wire_device.cpp +++ b/lib/onewire/one_wire_device.cpp @@ -1,8 +1,5 @@ #include "one_wire_device.h" -// TODO fix GPL compability -// currently we use rework of OneWireHub - OneWireDevice::OneWireDevice( uint8_t id_1, uint8_t id_2, @@ -21,6 +18,22 @@ OneWireDevice::OneWireDevice( id_storage[7] = maxim_crc8(id_storage, 7); } -void OneWireDevice::send_id(OneWireGpioSlave* owner) const { - owner->send(id_storage, 8); +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 index d4f0abe5..0aff3d28 100644 --- a/lib/onewire/one_wire_device.h +++ b/lib/onewire/one_wire_device.h @@ -1,10 +1,7 @@ #pragma once #include #include "maxim_crc.h" -#include "one_wire_slave_gpio.h" - -// TODO fix GPL compability -// currently we use rework of OneWireHub +#include "one_wire_slave.h" class OneWireDevice { public: @@ -17,18 +14,13 @@ public: uint8_t id_6, uint8_t id_7); - ~OneWireDevice() = default; // TODO: detach if deleted before hub - - // allow only move constructor - OneWireDevice(OneWireDevice&& one_wire_device) = default; - OneWireDevice(const OneWireDevice& one_wire_device) = delete; - OneWireDevice& operator=(OneWireDevice& one_wire_device) = delete; - OneWireDevice& operator=(const OneWireDevice& one_wire_device) = delete; - OneWireDevice& operator=(OneWireDevice&& one_wire_device) = delete; + ~OneWireDevice(); uint8_t id_storage[8]; - void send_id(OneWireGpioSlave* owner) const; + void send_id() const; - virtual void do_work(OneWireGpioSlave* owner) = 0; + 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 index 663553fb..cde6134c 100644 --- a/lib/onewire/one_wire_device_ds_1990.cpp +++ b/lib/onewire/one_wire_device_ds_1990.cpp @@ -1,8 +1,5 @@ #include "one_wire_device_ds_1990.h" -// TODO fix GPL compability -// currently we use rework of OneWireHub - DS1990::DS1990( uint8_t ID1, uint8_t ID2, @@ -12,16 +9,4 @@ DS1990::DS1990( uint8_t ID6, uint8_t ID7) : OneWireDevice(ID1, ID2, ID3, ID4, ID5, ID6, ID7) { -} - -void DS1990::do_work(OneWireGpioSlave* owner) { - uint8_t cmd; - - if(owner->receive(&cmd)) return; - - switch(cmd) { - default: - return; - //owner->raiseSlaveError(cmd); - } } \ 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 index 6b3d99b8..bf3eb411 100644 --- a/lib/onewire/one_wire_device_ds_1990.h +++ b/lib/onewire/one_wire_device_ds_1990.h @@ -1,9 +1,6 @@ #pragma once #include "one_wire_device.h" -// TODO fix GPL compability -// currently we use rework of OneWireHub - class DS1990 : public OneWireDevice { public: static constexpr uint8_t family_code{0x01}; @@ -16,6 +13,4 @@ public: uint8_t ID5, uint8_t ID6, uint8_t ID7); - - void do_work(OneWireGpioSlave* owner) final; }; \ No newline at end of file diff --git a/lib/onewire/one_wire_gpio.h b/lib/onewire/one_wire_master.cpp similarity index 70% rename from lib/onewire/one_wire_gpio.h rename to lib/onewire/one_wire_master.cpp index a78dcdf2..f21d8db1 100644 --- a/lib/onewire/one_wire_gpio.h +++ b/lib/onewire/one_wire_master.cpp @@ -1,41 +1,24 @@ #pragma once -#include +#include "one_wire_master.h" #include "one_wire_timings.h" -class OneWireGpio { -private: - const GpioPin* gpio; - -public: - OneWireGpio(const GpioPin* one_wire_gpio); - ~OneWireGpio(); - 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 start(void); - void stop(void); -}; - -OneWireGpio::OneWireGpio(const GpioPin* one_wire_gpio) { +OneWireMaster::OneWireMaster(const GpioPin* one_wire_gpio) { gpio = one_wire_gpio; } -OneWireGpio::~OneWireGpio() { +OneWireMaster::~OneWireMaster() { stop(); } -void OneWireGpio::start(void) { +void OneWireMaster::start(void) { gpio_init(gpio, GpioModeOutputOpenDrain); } -void OneWireGpio::stop(void) { +void OneWireMaster::stop(void) { gpio_init(gpio, GpioModeAnalog); } -bool OneWireGpio::reset(void) { +bool OneWireMaster::reset(void) { uint8_t r; uint8_t retries = 125; @@ -64,7 +47,7 @@ bool OneWireGpio::reset(void) { return r; } -bool OneWireGpio::read_bit(void) { +bool OneWireMaster::read_bit(void) { bool result; // drive low @@ -82,7 +65,7 @@ bool OneWireGpio::read_bit(void) { return result; } -void OneWireGpio::write_bit(bool value) { +void OneWireMaster::write_bit(bool value) { if(value) { // drive low gpio_write(gpio, false); @@ -102,7 +85,7 @@ void OneWireGpio::write_bit(bool value) { } } -uint8_t OneWireGpio::read(void) { +uint8_t OneWireMaster::read(void) { uint8_t result = 0; for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { @@ -114,16 +97,20 @@ uint8_t OneWireGpio::read(void) { return result; } -void OneWireGpio::read_bytes(uint8_t* buffer, uint16_t count) { +void OneWireMaster::read_bytes(uint8_t* buffer, uint16_t count) { for(uint16_t i = 0; i < count; i++) { buffer[i] = read(); } } -void OneWireGpio::write(uint8_t value) { +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 new file mode 100644 index 00000000..c64be0ee --- /dev/null +++ b/lib/onewire/one_wire_master.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "one_wire_timings.h" + +class OneWireMaster { +private: + const GpioPin* gpio; + +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); +}; \ No newline at end of file diff --git a/lib/onewire/one_wire_slave.cpp b/lib/onewire/one_wire_slave.cpp new file mode 100644 index 00000000..288eb513 --- /dev/null +++ b/lib/onewire/one_wire_slave.cpp @@ -0,0 +1,312 @@ +#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 + api_interrupt_add(exti_cb, InterruptTypeExternalInterrupt, this); + + // init gpio + gpio_init(one_wire_pin_record, GpioModeInterruptRiseFall); + pin_set_float(); + + // init instructions per us count + __instructions_per_us = (SystemCoreClock / 1000000.0f); +} + +void OneWireSlave::stop(void) { + // deinit gpio + gpio_init_ex(one_wire_pin_record, GpioModeInput, GpioPullNo, GpioSpeedLow); + + // remove exti interrupt + api_interrupt_remove(exti_cb, InterruptTypeExternalInterrupt); + + // 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) { + device = nullptr; + device->deattach(); +} + +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() { + gpio_write(one_wire_pin_record, true); +} + +void OneWireSlave::pin_set_low() { + 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(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; + + const bool bit_recv = 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 0x33: + // READ ROM + device->send_id(); + return false; + + 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 { + pin_init_opendrain_in_isr_ctx(); + error = OneWireSlaveError::NO_ERROR; + + if(show_presence()) { + __disable_irq(); + + // TODO think about multiple command cycles + bool return_to_reset = receive_and_process_cmd(); + result = + (error == OneWireSlaveError::NO_ERROR || + error == OneWireSlaveError::INCORRECT_ONEWIRE_CMD); + + __enable_irq(); + } else { + result = false; + } + + pin_init_interrupt_in_isr_ctx(); + } + + return result; +} + +void OneWireSlave::exti_callback(void* _pin, void* _ctx) { + // interrupt manager get us pin constant, so... + uint32_t pin = (uint32_t)_pin; + OneWireSlave* _this = static_cast(_ctx); + + if(pin == _this->one_wire_pin_record->pin) { + volatile bool input_state = 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(_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; + } + } +} \ No newline at end of file diff --git a/lib/onewire/one_wire_slave.h b/lib/onewire/one_wire_slave.h new file mode 100644 index 00000000..13b53c0c --- /dev/null +++ b/lib/onewire/one_wire_slave.h @@ -0,0 +1,74 @@ +#pragma once +#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* _pin, void* _ctx); + void (*exti_cb)(void* _pin, 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_slave_gpio.cpp b/lib/onewire/one_wire_slave_gpio.cpp deleted file mode 100644 index 9dbc4d7d..00000000 --- a/lib/onewire/one_wire_slave_gpio.cpp +++ /dev/null @@ -1,517 +0,0 @@ -#include "one_wire_slave_gpio.h" -#include "one_wire_device.h" -#include "one_wire_device_ds_1990.h" - -// TODO fix GPL compability -// currently we use rework of OneWireHub - -static uint32_t __instructions_per_us = 0; - -OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) { - gpio = one_wire_gpio; - error = OneWireGpioSlaveError::NO_ERROR; - devices_count = 0; - device_selected = nullptr; - - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - devices[i] = nullptr; - } - - __instructions_per_us = (SystemCoreClock / 1000000.0f); -} - -OneWireGpioSlave::~OneWireGpioSlave() { - stop(); -} - -void OneWireGpioSlave::start(void) { - gpio_init(gpio, GpioModeOutputOpenDrain); -} - -void OneWireGpioSlave::stop(void) { - gpio_init(gpio, GpioModeAnalog); -} - -bool OneWireGpioSlave::emulate() { - bool anything_emulated = false; - error = OneWireGpioSlaveError::NO_ERROR; - - while(1) { - if(devices_count == 0) return false; - - if(!check_reset()) { - return anything_emulated; - } else { - } - - // OK, we receive reset - osKernelLock(); - - if(!show_presence()) { - return anything_emulated; - } else { - anything_emulated = true; - } - - // and we succefully show our presence on bus - __disable_irq(); - - // TODO think about return condition - if(!receive_and_process_cmd()) { - __enable_irq(); - osKernelUnlock(); - } else { - __enable_irq(); - osKernelUnlock(); - } - } -} - -OneWiteTimeType OneWireGpioSlave::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(gpio_read(gpio) != 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; -} - -void OneWireGpioSlave::pin_set_float() { - gpio_write(gpio, true); -} - -void OneWireGpioSlave::pin_set_low() { - gpio_write(gpio, false); -} - -const char* OneWireGpioSlave::decode_error() { - const char* error_text[16] = { - "NO_ERROR", - "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"}; - - return error_text[static_cast(error)]; -} - -uint8_t OneWireGpioSlave::attach(OneWireDevice& device) { - if(devices_count >= ONE_WIRE_MAX_DEVICES) return 255; // hub is full - - uint8_t position = 255; - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - if(devices[i] == &device) { - return i; - } - if((position > ONE_WIRE_MAX_DEVICES) && (devices[i] == nullptr)) { - position = i; - } - } - - if(position == 255) return 255; - - devices[position] = &device; - devices_count++; - build_id_tree(); - return position; -} - -bool OneWireGpioSlave::detach(const OneWireDevice& device) { - uint8_t position = 255; - - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - if(devices[i] == &device) { - position = i; - break; - } - } - - if(position != 255) return detach(position); - - return false; -} - -bool OneWireGpioSlave::detach(uint8_t device_number) { - if(devices[device_number] == nullptr) return false; - if(devices_count == 0) return false; - if(device_number >= ONE_WIRE_MAX_DEVICES) return false; - - devices[device_number] = nullptr; - devices_count--; - build_id_tree(); - - return true; -} - -uint8_t OneWireGpioSlave::get_next_device_index(const uint8_t index_start) const { - for(uint8_t i = index_start; i < ONE_WIRE_MAX_DEVICES; ++i) { - if(devices[i] != nullptr) return i; - } - return 0; -} - -uint8_t OneWireGpioSlave::build_id_tree(void) { - uint32_t device_mask = 0; - uint32_t bit_mask = 0x01; - - // build mask - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - if(devices[i] != nullptr) device_mask |= bit_mask; - bit_mask <<= 1; - } - - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - id_tree[i].id_position = 255; - } - - // begin with root-element - build_id_tree(0, device_mask); // goto branch - - return 0; -} - -uint8_t OneWireGpioSlave::build_id_tree(uint8_t id_bit_position, uint32_t device_mask) { - if(device_mask == 0) return (255); - - while(id_bit_position < 64) { - uint32_t mask_pos{0}; - uint32_t mask_neg{0}; - const uint8_t pos_byte{static_cast(id_bit_position >> 3)}; - const uint8_t mask_bit{static_cast(1 << (id_bit_position & 7))}; - uint32_t mask_id{1}; - - // searchid_tree through all active slaves - for(uint8_t id = 0; id < ONE_WIRE_MAX_DEVICES; ++id) { - if((device_mask & mask_id) != 0) { - // if slave is in mask differentiate the bitValue - if((devices[id]->id_storage[pos_byte] & mask_bit) != 0) - mask_pos |= mask_id; - else - mask_neg |= mask_id; - } - mask_id <<= 1; - } - - if((mask_neg != 0) && (mask_pos != 0)) { - // there was found a junction - const uint8_t active_element = get_first_id_tree_el_position(); - - id_tree[active_element].id_position = id_bit_position; - id_tree[active_element].device_selected = get_first_bit_set_position(device_mask); - id_bit_position++; - id_tree[active_element].got_one = build_id_tree(id_bit_position, mask_pos); - id_tree[active_element].got_zero = build_id_tree(id_bit_position, mask_neg); - return active_element; - } - - id_bit_position++; - } - - // gone through the address, store this result - uint8_t active_element = get_first_id_tree_el_position(); - - id_tree[active_element].id_position = 128; - id_tree[active_element].device_selected = get_first_bit_set_position(device_mask); - id_tree[active_element].got_one = 255; - id_tree[active_element].got_zero = 255; - - return active_element; -} - -uint8_t OneWireGpioSlave::get_first_bit_set_position(uint32_t mask) const { - uint32_t _mask = mask; - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - if((_mask & 1) != 0) return i; - _mask >>= 1; - } - return 0; -} - -uint8_t OneWireGpioSlave::get_first_id_tree_el_position(void) const { - for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) { - if(id_tree[i].id_position == 255) return i; - } - return 0; -} - -void OneWireGpioSlave::cmd_search_rom(void) { - uint8_t id_bit_position = 0; - uint8_t trigger_position = 0; - uint8_t active_slave = id_tree[trigger_position].device_selected; - uint8_t trigger_bit = id_tree[trigger_position].id_position; - - while(id_bit_position < 64) { - // if junction is reached, act different - if(id_bit_position == trigger_bit) { - if(!send_bit(false)) return; - if(!send_bit(false)) return; - - const bool bit_recv = receive_bit(); - if(error != OneWireGpioSlaveError::NO_ERROR) return; - - // switch to next junction - trigger_position = bit_recv ? id_tree[trigger_position].got_one : - id_tree[trigger_position].got_zero; - - active_slave = id_tree[trigger_position].device_selected; - - trigger_bit = (trigger_position == 255) ? uint8_t(255) : - id_tree[trigger_position].id_position; - } else { - const uint8_t pos_byte = (id_bit_position >> 3); - const uint8_t mask_bit = (static_cast(1) << (id_bit_position & (7))); - bool bit_send; - - if((devices[active_slave]->id_storage[pos_byte] & mask_bit) != 0) { - bit_send = true; - if(!send_bit(true)) return; - if(!send_bit(false)) return; - } else { - bit_send = false; - if(!send_bit(false)) return; - if(!send_bit(true)) return; - } - - const bool bit_recv = receive_bit(); - if(error != OneWireGpioSlaveError::NO_ERROR) return; - - if(bit_send != bit_recv) return; - } - id_bit_position++; - } - - device_selected = devices[active_slave]; -} - -bool OneWireGpioSlave::check_reset(void) { - pin_set_float(); - - if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) { - error = OneWireGpioSlaveError::NO_ERROR; - - if(wait_while_gpio_is( - OWET::RESET_MIN[overdrive_mode] - OWET::SLOT_MAX[overdrive_mode] - - OWET::READ_MAX[overdrive_mode], - false) == 0) { - // we want to show_presence on high, so wait for it - const OneWiteTimeType time_remaining = wait_while_gpio_is(OWET::RESET_MAX[0], false); - - if(overdrive_mode && - ((OWET::RESET_MAX[0] - OWET::RESET_MIN[overdrive_mode]) > time_remaining)) { - overdrive_mode = false; - }; - - return true; - } - } - - // if line is low, then just leave - if(gpio_read(gpio) == 0) { - return false; - } - - // wait while gpio is high - if(wait_while_gpio_is(OWET::RESET_TIMEOUT, true) == 0) { - return false; - } - - // store low time - OneWiteTimeType time_remaining = wait_while_gpio_is(OWET::RESET_MAX[0], false); - - // low time more than RESET_MAX time - if(time_remaining == 0) { - error = OneWireGpioSlaveError::VERY_LONG_RESET; - return false; - } - - // get real reset time - time_remaining = OWET::RESET_MAX[0] - time_remaining; - - // if time, while bus was low, fit in standart reset timings - if(overdrive_mode && ((OWET::RESET_MAX[0] - OWET::RESET_MIN[0]) <= time_remaining)) { - // normal reset detected - overdrive_mode = false; - }; - - bool result = (time_remaining <= OWET::RESET_MAX[0]) && - time_remaining >= OWET::RESET_MIN[overdrive_mode]; - - return result; -} - -bool OneWireGpioSlave::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[overdrive_mode]); - pin_set_float(); - - // somebody also can show presence - const OneWiteTimeType wait_low_time = - OWET::PRESENCE_MAX[overdrive_mode] - OWET::PRESENCE_MIN[overdrive_mode]; - - // so we will wait - if(wait_while_gpio_is(wait_low_time, false) == 0) { - error = OneWireGpioSlaveError::PRESENCE_LOW_ON_LINE; - return false; - } - - return true; -} - -bool OneWireGpioSlave::receive_and_process_cmd(void) { - receive(&cmd); - - if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) return true; - if(error != OneWireGpioSlaveError::NO_ERROR) return false; - - switch(cmd) { - case 0xF0: - // SEARCH ROM - device_selected = nullptr; - cmd_search_rom(); - - // trigger reinit - return true; - - case 0x33: - // READ ROM - - // work only when one slave on the bus - if((device_selected == nullptr) && (devices_count == 1)) { - device_selected = devices[get_next_device_index()]; - } - if(device_selected != nullptr) { - device_selected->send_id(this); - } - return false; - - default: // Unknown command - error = OneWireGpioSlaveError::INCORRECT_ONEWIRE_CMD; - //error_cmd = cmd; - } - - if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) return true; - return (error == OneWireGpioSlaveError::NO_ERROR); -} - -bool OneWireGpioSlave::receive_bit(void) { - // wait while bus is low - OneWiteTimeType time = OWET::SLOT_MAX[overdrive_mode]; - time = wait_while_gpio_is(time, false); - if(time == 0) { - error = OneWireGpioSlaveError::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 = OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH; - error_place = 1; - return false; - } - - // wait a time of zero - time = OWET::READ_MIN[overdrive_mode]; - time = wait_while_gpio_is(time, false); - - return (time > 0); -} - -bool OneWireGpioSlave::send_bit(bool value) { - const bool write_zero = !value; - - // wait while bus is low - OneWiteTimeType time = OWET::SLOT_MAX[overdrive_mode]; - time = wait_while_gpio_is(time, false); - if(time == 0) { - error = OneWireGpioSlaveError::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 = OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH; - error_place = 2; - return false; - } - - // choose write time - if(write_zero) { - pin_set_low(); - time = OWET::WRITE_ZERO[overdrive_mode]; - } else { - time = OWET::READ_MAX[overdrive_mode]; - } - - // hold line for ZERO or ONE time - delay_us(time); - pin_set_float(); - - return true; -} - -bool OneWireGpioSlave::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 == OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH)) - error = OneWireGpioSlaveError::FIRST_BIT_OF_BYTE_TIMEOUT; - return false; - } - } - } - return true; -} - -bool OneWireGpioSlave::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); -} \ No newline at end of file diff --git a/lib/onewire/one_wire_slave_gpio.h b/lib/onewire/one_wire_slave_gpio.h deleted file mode 100644 index 2f9deb4b..00000000 --- a/lib/onewire/one_wire_slave_gpio.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include -#include "one_wire_timings.h" - -// TODO fix GPL compability -// currently we use rework of OneWireHub - -#define ONE_WIRE_MAX_DEVICES 1 -#define ONE_WIRE_TREE_SIZE ((2 * ONE_WIRE_MAX_DEVICES) - 1) - -#define OWET OneWireEmulateTiming - -class OneWireDevice; - -enum class OneWireGpioSlaveError : uint8_t { - NO_ERROR = 0, - READ_TIMESLOT_TIMEOUT = 1, - WRITE_TIMESLOT_TIMEOUT = 2, - WAIT_RESET_TIMEOUT = 3, - VERY_LONG_RESET = 4, - VERY_SHORT_RESET = 5, - PRESENCE_LOW_ON_LINE = 6, - READ_TIMESLOT_TIMEOUT_LOW = 7, - AWAIT_TIMESLOT_TIMEOUT_HIGH = 8, - PRESENCE_HIGH_ON_LINE = 9, - INCORRECT_ONEWIRE_CMD = 10, - INCORRECT_SLAVE_USAGE = 11, - TRIED_INCORRECT_WRITE = 12, - FIRST_TIMESLOT_TIMEOUT = 13, - FIRST_BIT_OF_BYTE_TIMEOUT = 14, - RESET_IN_PROGRESS = 15 -}; - -class OneWireGpioSlave { -private: - const GpioPin* gpio; - bool overdrive_mode = false; - uint8_t cmd; - OneWireGpioSlaveError error; - uint8_t error_place; - - uint8_t devices_count; - OneWireDevice* devices[ONE_WIRE_MAX_DEVICES]; - OneWireDevice* device_selected; - - struct IDTree { - uint8_t device_selected; // for which slave is this jump-command relevant - uint8_t id_position; // where does the algorithm has to look for a junction - uint8_t got_zero; // if 0 switch to which tree branch - uint8_t got_one; // if 1 switch to which tree branch - } id_tree[ONE_WIRE_TREE_SIZE]; - -public: - OneWireGpioSlave(const GpioPin* one_wire_gpio); - ~OneWireGpioSlave(); - - void start(void); - void stop(void); - bool emulate(); - bool check_reset(void); - bool show_presence(void); - bool receive_and_process_cmd(void); - bool receive(uint8_t* data, const uint8_t data_length = 1); - bool receive_bit(void); - bool send_bit(bool value); - bool send(const uint8_t* address, const uint8_t data_length = 1); - - OneWiteTimeType wait_while_gpio_is(volatile OneWiteTimeType retries, const bool pin_value); - - // set pin state - inline void pin_set_float(); - inline void pin_set_low(); - - // get error text - const char* decode_error(); - - // devices managment - uint8_t attach(OneWireDevice& device); - bool detach(const OneWireDevice& device); - bool detach(uint8_t device_number); - uint8_t get_next_device_index(const uint8_t index_start = 0) const; - - // id tree managment - uint8_t build_id_tree(void); - uint8_t build_id_tree(uint8_t id_bit_position, uint32_t device_mask); - - uint8_t get_first_bit_set_position(uint32_t mask) const; - uint8_t get_first_id_tree_el_position(void) const; - - // commands - void cmd_search_rom(void); -}; \ No newline at end of file diff --git a/lib/onewire/one_wire_timings.cpp b/lib/onewire/one_wire_timings.cpp index b6c3d55c..23a4a934 100644 --- a/lib/onewire/one_wire_timings.cpp +++ b/lib/onewire/one_wire_timings.cpp @@ -1,17 +1,16 @@ #include "one_wire_timings.h" // fix pre C++17 "undefined reference" errors -constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_TIMEOUT; -constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MIN[2]; -constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MAX[2]; +constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MIN; +constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MAX; constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_TIMEOUT; -constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MIN[2]; -constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MAX[2]; +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[2]; +constexpr const OneWiteTimeType OneWireEmulateTiming::SLOT_MAX; -constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MIN[2]; -constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MAX[2]; -constexpr const OneWiteTimeType OneWireEmulateTiming::WRITE_ZERO[2]; +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 index 49fc751e..b5290077 100644 --- a/lib/onewire/one_wire_timings.h +++ b/lib/onewire/one_wire_timings.h @@ -3,10 +3,10 @@ class __OneWireTiming { public: - constexpr static const uint16_t TIMING_A = 6; + constexpr static const uint16_t TIMING_A = 9; constexpr static const uint16_t TIMING_B = 64; - constexpr static const uint16_t TIMING_C = 60; - constexpr static const uint16_t TIMING_D = 10; + 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; @@ -23,7 +23,7 @@ public: 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 = __OneWireTiming::TIMING_A; + 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; @@ -37,18 +37,17 @@ typedef uint32_t OneWiteTimeType; class OneWireEmulateTiming { public: - constexpr static const OneWiteTimeType RESET_TIMEOUT = {5000}; - constexpr static const OneWiteTimeType RESET_MIN[2] = {430, 48}; - constexpr static const OneWiteTimeType RESET_MAX[2] = {960, 80}; + constexpr static const OneWiteTimeType RESET_MIN = 430; + constexpr static const OneWiteTimeType RESET_MAX = 960; - constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = {20}; - constexpr static const OneWiteTimeType PRESENCE_MIN[2] = {160, 8}; - constexpr static const OneWiteTimeType PRESENCE_MAX[2] = {480, 32}; + constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = 20; + constexpr static const OneWiteTimeType PRESENCE_MIN = 160; + constexpr static const OneWiteTimeType PRESENCE_MAX = 480; - constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = {15000}; - constexpr static const OneWiteTimeType SLOT_MAX[2] = {135, 30}; + constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = 15000; + constexpr static const OneWiteTimeType SLOT_MAX = 135; - constexpr static const OneWiteTimeType READ_MIN[2] = {20, 4}; - constexpr static const OneWiteTimeType READ_MAX[2] = {60, 10}; - constexpr static const OneWiteTimeType WRITE_ZERO[2] = {30, 8}; + 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