From 204b50381a0975b72af8b0be33b6371e69c024a0 Mon Sep 17 00:00:00 2001 From: Shukai Ni Date: Wed, 22 Mar 2023 05:47:47 -0400 Subject: [PATCH 1/5] Correct FAP default upload path in AppsOnSDCard.md (#2524) Since the fap's source code is in `applications_user`, the documentation should also point to `applications_user` as the parent directory --- documentation/AppsOnSDCard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index 754305706..212df5b1b 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -13,7 +13,7 @@ FAPs are created and developed the same way as internal applications that are pa To build your application as a FAP, create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest, and set its _apptype_ to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details. - To build your application, run `./fbt fap_{APPID}`, where APPID is your application's ID in its manifest. -- To build your app and upload it over USB to run on Flipper, use `./fbt launch_app APPSRC=applications/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). +- To build your app and upload it over USB to run on Flipper, use `./fbt launch_app APPSRC=applications_user/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). - To build all FAPs, run `./fbt faps` or `./fbt fap_dist`. ## FAP assets From acc32f66e843a13996ae16c6287de6cbcf98be70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 22 Mar 2023 19:48:41 +0900 Subject: [PATCH 2/5] Github: force cleanup tree on decontaminate (#2526) --- .github/workflows/build.yml | 2 +- .github/workflows/lint_and_submodule_check.yml | 2 +- .github/workflows/merge_report.yml | 2 +- .github/workflows/pvs_studio.yml | 2 +- .github/workflows/unit_tests.yml | 2 +- .github/workflows/updater_test.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ab2490ce..898a1291c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 46cca5c0d..10b3c1d9a 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -24,7 +24,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index e88346edf..a382733df 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 65ffd1954..d11e268da 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -25,7 +25,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 6f044ebca..0ec531064 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index c04d526fc..e1e655b00 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi From 973287b09b2e001503d91d94e05d9fe04bfafd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 22 Mar 2023 20:26:40 +0900 Subject: [PATCH 3/5] Github: wipe workspace before checkout (#2527) * Github: wipe workspace before checkout * Github: allow find to fail * Github: limit maxdepth for find --- .github/workflows/build.yml | 21 ++++--------------- .../workflows/lint_and_submodule_check.yml | 12 ++--------- .github/workflows/merge_report.yml | 12 ++--------- .github/workflows/pvs_studio.yml | 12 ++--------- .github/workflows/unit_tests.yml | 12 ++--------- .github/workflows/updater_test.yml | 20 ++++-------------- 6 files changed, 16 insertions(+), 73 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 898a1291c..56e50d5f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,16 +18,8 @@ jobs: main: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 @@ -171,13 +163,8 @@ jobs: if: ${{ !startsWith(github.ref, 'refs/tags') }} runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ] - then - git submodule status \ - || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 10b3c1d9a..cecfd1248 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -18,16 +18,8 @@ jobs: lint_sources_check_submodules: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index a382733df..71515e1c5 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -12,16 +12,8 @@ jobs: merge_report: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index d11e268da..6dbf84edb 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -19,16 +19,8 @@ jobs: if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted, FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 0ec531064..6a824fac3 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -12,16 +12,8 @@ jobs: run_units_on_bench: runs-on: [self-hosted, FlipperZeroUnitTest] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index e1e655b00..2861529d8 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -12,16 +12,8 @@ jobs: test_updater_on_bench: runs-on: [self-hosted, FlipperZeroUpdaterTest] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 @@ -57,12 +49,8 @@ jobs: run: | echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT - - name: 'Decontaminate previous build leftovers' - if: failure() - run: | - if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout latest release' uses: actions/checkout@v3 From 1f236ede0e4d13f2ca0c031bd7c0e2017540d68c Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 22 Mar 2023 17:41:14 +0300 Subject: [PATCH 4/5] [#2501] Disable UART IRQs by default (#2523) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f7/furi_hal/furi_hal_uart.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/firmware/targets/f7/furi_hal/furi_hal_uart.c index 54232e67f..71b5c7ba0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.c +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.c @@ -44,7 +44,8 @@ static void furi_hal_usart_init(uint32_t baud) { while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1)) ; - LL_USART_EnableIT_RXNE_RXFNE(USART1); + LL_USART_DisableIT_ERROR(USART1); + NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); } @@ -79,8 +80,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { ; furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); + LL_LPUART_DisableIT_ERROR(LPUART1); - LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); } @@ -190,19 +191,25 @@ void furi_hal_uart_set_irq_cb( void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx), void* ctx) { if(cb == NULL) { - if(ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) { NVIC_DisableIRQ(USART1_IRQn); - else if(ch == FuriHalUartIdLPUART1) + LL_USART_DisableIT_RXNE_RXFNE(USART1); + } else if(ch == FuriHalUartIdLPUART1) { NVIC_DisableIRQ(LPUART1_IRQn); + LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1); + } irq_cb[ch] = cb; irq_ctx[ch] = ctx; } else { irq_ctx[ch] = ctx; irq_cb[ch] = cb; - if(ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) { NVIC_EnableIRQ(USART1_IRQn); - else if(ch == FuriHalUartIdLPUART1) + LL_USART_EnableIT_RXNE_RXFNE(USART1); + } else if(ch == FuriHalUartIdLPUART1) { NVIC_EnableIRQ(LPUART1_IRQn); + LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); + } } } From 8b224ecb15d0899c3e67edd693a18f58d9029b57 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 22 Mar 2023 17:54:06 +0300 Subject: [PATCH 5/5] [FL-3179] 1-Wire Overdrive Mode (#2522) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Separate ibutton to its own module, add one_wire to f18 * Move onewire cli to a separate app * Add definitions for normal and overdrive timings * Update api definitions * Add rough overdrive timings definition for onewire emulation * Remove one_wire_host_timing.h * Add rough overdrive timings for onewire host * Improve overdrive mode * Working overdrive mode from flipper to flipper * Update thermometer example app * Turn on otg power when running thermometer example app * Implement reset overdrive switching * Always exit out of overdrive mode * Improve overdrive timings * Fix typos * Fix reset behaviour * Use overdrive mode everywhere in DS1996 * Improve comments * Bump API version Co-authored-by: あく --- .../examples/example_thermo/example_thermo.c | 13 +- firmware/targets/f18/api_symbols.csv | 8 +- firmware/targets/f7/api_symbols.csv | 8 +- lib/ibutton/protocols/dallas/dallas_common.h | 4 +- .../protocols/dallas/protocol_dallas_base.h | 4 +- .../protocols/dallas/protocol_ds1971.c | 18 +- .../protocols/dallas/protocol_ds1990.c | 10 +- .../protocols/dallas/protocol_ds1992.c | 10 +- .../protocols/dallas/protocol_ds1996.c | 62 ++++-- .../protocols/dallas/protocol_ds_generic.c | 10 +- lib/one_wire/SConscript | 1 - lib/one_wire/one_wire_host.c | 85 ++++++-- lib/one_wire/one_wire_host.h | 89 +++++---- lib/one_wire/one_wire_host_timing.h | 30 --- lib/one_wire/one_wire_slave.c | 188 +++++++++++------- lib/one_wire/one_wire_slave.h | 84 +++++--- 16 files changed, 397 insertions(+), 227 deletions(-) delete mode 100644 lib/one_wire/one_wire_host_timing.h diff --git a/applications/examples/example_thermo/example_thermo.c b/applications/examples/example_thermo/example_thermo.c index b3bc7cd99..4241cb59d 100644 --- a/applications/examples/example_thermo/example_thermo.c +++ b/applications/examples/example_thermo/example_thermo.c @@ -19,9 +19,12 @@ #include #include +#include + #define UPDATE_PERIOD_MS 1000UL #define TEXT_STORE_SIZE 64U +#define DS18B20_CMD_SKIP_ROM 0xccU #define DS18B20_CMD_CONVERT 0x44U #define DS18B20_CMD_READ_SCRATCHPAD 0xbeU @@ -92,7 +95,7 @@ static void example_thermo_request_temperature(ExampleThermoContext* context) { /* After the reset, a ROM operation must follow. If there is only one device connected, the "Skip ROM" command is most appropriate (it can also be used to address all of the connected devices in some cases).*/ - onewire_host_skip(onewire); + onewire_host_write(onewire, DS18B20_CMD_SKIP_ROM); /* After the ROM operation, a device-specific command is issued. In this case, it's a request to start measuring the temperature. */ onewire_host_write(onewire, DS18B20_CMD_CONVERT); @@ -133,7 +136,7 @@ static void example_thermo_read_temperature(ExampleThermoContext* context) { /* After the reset, a ROM operation must follow. If there is only one device connected, the "Skip ROM" command is most appropriate (it can also be used to address all of the connected devices in some cases).*/ - onewire_host_skip(onewire); + onewire_host_write(onewire, DS18B20_CMD_SKIP_ROM); /* After the ROM operation, a device-specific command is issued. This time, it will be the "Read Scratchpad" command which will @@ -267,6 +270,9 @@ static void example_thermo_input_callback(InputEvent* event, void* ctx) { /* Starts the reader thread and handles the input */ static void example_thermo_run(ExampleThermoContext* context) { + /* Enable power on external pins */ + furi_hal_power_enable_otg(); + /* Configure the hardware in host mode */ onewire_host_start(context->onewire); @@ -299,6 +305,9 @@ static void example_thermo_run(ExampleThermoContext* context) { /* Reset the hardware */ onewire_host_stop(context->onewire); + + /* Disable power on external pins */ + furi_hal_power_disable_otg(); } /******************** Initialisation & startup *****************************/ diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index b6be56f60..e6fae33ee 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,19.0,, +Version,+,20.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -153,7 +153,6 @@ Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, -Header,+,lib/one_wire/one_wire_host_timing.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, Header,+,lib/toolbox/args.h,, @@ -1481,8 +1480,8 @@ Function,+,onewire_host_read_bit,_Bool,OneWireHost* Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t" Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost* -Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" -Function,+,onewire_host_skip,void,OneWireHost* +Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode" +Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool" Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" @@ -1496,6 +1495,7 @@ Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave* Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" +Function,+,onewire_slave_set_overdrive,void,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_start,void,OneWireSlave* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e6de39b1d..7ac9a2459 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,19.0,, +Version,+,20.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -172,7 +172,6 @@ Header,+,lib/mlib/m-variant.h,, Header,+,lib/nfc/nfc_device.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, -Header,+,lib/one_wire/one_wire_host_timing.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, Header,+,lib/subghz/blocks/const.h,, @@ -2062,8 +2061,8 @@ Function,+,onewire_host_read_bit,_Bool,OneWireHost* Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t" Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost* -Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" -Function,+,onewire_host_skip,void,OneWireHost* +Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode" +Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool" Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" @@ -2077,6 +2076,7 @@ Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave* Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" +Function,+,onewire_slave_set_overdrive,void,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_start,void,OneWireSlave* diff --git a/lib/ibutton/protocols/dallas/dallas_common.h b/lib/ibutton/protocols/dallas/dallas_common.h index 7991a1f8b..6f5ff7cc0 100644 --- a/lib/ibutton/protocols/dallas/dallas_common.h +++ b/lib/ibutton/protocols/dallas/dallas_common.h @@ -1,10 +1,10 @@ #pragma once -#include - #include #include +#include + #define DALLAS_COMMON_MANUFACTURER_NAME "Dallas" #define DALLAS_COMMON_CMD_READ_ROM 0x33U diff --git a/lib/ibutton/protocols/dallas/protocol_dallas_base.h b/lib/ibutton/protocols/dallas/protocol_dallas_base.h index b4edb2b20..55e109936 100644 --- a/lib/ibutton/protocols/dallas/protocol_dallas_base.h +++ b/lib/ibutton/protocols/dallas/protocol_dallas_base.h @@ -2,11 +2,11 @@ #include "../protocol_common_i.h" -#include - #include #include +#include + typedef bool (*iButtonProtocolDallasReadWriteFunc)(OneWireHost*, iButtonProtocolData*); typedef void (*iButtonProtocolDallasEmulateFunc)(OneWireSlave*, iButtonProtocolData*); typedef bool (*iButtonProtocolDallasSaveFunc)(FlipperFormat*, const iButtonProtocolData*); diff --git a/lib/ibutton/protocols/dallas/protocol_ds1971.c b/lib/ibutton/protocols/dallas/protocol_ds1971.c index eb5b330b7..a806acb22 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1971.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1971.c @@ -53,7 +53,7 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1971 = { .name = DS1971_FAMILY_NAME, .read = dallas_ds1971_read, - .write_blank = NULL, /* No data to write a blank */ + .write_blank = NULL, // TODO: Implement writing to blank .write_copy = dallas_ds1971_write_copy, .emulate = dallas_ds1971_emulate, .save = dallas_ds1971_save, @@ -76,7 +76,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d DS1971ProtocolData* data = protocol_data; onewire_host_reset(host); - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); // Starting writing from address 0x0000 onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH); onewire_host_write(host, 0x00); @@ -87,7 +87,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d bool pad_valid = false; if(onewire_host_reset(host)) { pad_valid = true; - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); onewire_host_write(host, DALLAS_COMMON_CMD_READ_SCRATCH); onewire_host_write(host, 0x00); @@ -103,7 +103,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d // Copy scratchpad to memory and confirm if(pad_valid) { if(onewire_host_reset(host)) { - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); onewire_host_write(host, DALLAS_COMMON_CMD_COPY_SCRATCH); onewire_host_write(host, DS1971_CMD_FINALIZATION); @@ -114,10 +114,16 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d return pad_valid; } -static void dallas_ds1971_reset_callback(void* context) { +static bool dallas_ds1971_reset_callback(bool is_short, void* context) { furi_assert(context); DS1971ProtocolData* data = context; - data->state.command_state = DallasCommonCommandStateIdle; + + if(!is_short) { + data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + } + + return !is_short; } static bool dallas_ds1971_command_callback(uint8_t command, void* context) { diff --git a/lib/ibutton/protocols/dallas/protocol_ds1990.c b/lib/ibutton/protocols/dallas/protocol_ds1990.c index 0d9c937ee..86d39f1bd 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1990.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1990.c @@ -67,6 +67,14 @@ bool dallas_ds1990_write_blank(OneWireHost* host, iButtonProtocolData* protocol_ tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } +static bool dallas_ds1990_reset_callback(bool is_short, void* context) { + DS1990ProtocolData* data = context; + if(!is_short) { + onewire_slave_set_overdrive(data->state.bus, is_short); + } + return !is_short; +} + static bool dallas_ds1990_command_callback(uint8_t command, void* context) { furi_assert(context); DS1990ProtocolData* data = context; @@ -92,7 +100,7 @@ void dallas_ds1990_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data DS1990ProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_reset_callback(bus, dallas_ds1990_reset_callback, protocol_data); onewire_slave_set_command_callback(bus, dallas_ds1990_command_callback, protocol_data); } diff --git a/lib/ibutton/protocols/dallas/protocol_ds1992.c b/lib/ibutton/protocols/dallas/protocol_ds1992.c index 17d631259..0b4d4b34f 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1992.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1992.c @@ -87,10 +87,16 @@ bool dallas_ds1992_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d DS1992_SRAM_DATA_SIZE); } -static void dallas_ds1992_reset_callback(void* context) { +static bool dallas_ds1992_reset_callback(bool is_short, void* context) { furi_assert(context); DS1992ProtocolData* data = context; - data->state.command_state = DallasCommonCommandStateIdle; + + if(!is_short) { + data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + } + + return !is_short; } static bool dallas_ds1992_command_callback(uint8_t command, void* context) { diff --git a/lib/ibutton/protocols/dallas/protocol_ds1996.c b/lib/ibutton/protocols/dallas/protocol_ds1996.c index 74a5792c6..5358b63e2 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1996.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1996.c @@ -63,24 +63,54 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1996 = { bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1996ProtocolData* data = protocol_data; - return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data) && - dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE); + bool success = false; + + do { + if(!onewire_host_reset(host)) break; + if(!dallas_common_read_rom(host, &data->rom_data)) break; + if(!onewire_host_reset(host)) break; + + onewire_host_write(host, DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM); + onewire_host_set_overdrive(host, true); + + if(!dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE)) break; + success = true; + } while(false); + + onewire_host_set_overdrive(host, false); + return success; } bool dallas_ds1996_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1996ProtocolData* data = protocol_data; - return dallas_common_write_mem( - host, - DS1996_COPY_SCRATCH_TIMEOUT_US, - DS1996_SRAM_PAGE_SIZE, - data->sram_data, - DS1996_SRAM_DATA_SIZE); + bool success = false; + + do { + if(!onewire_host_reset(host)) break; + + onewire_host_write(host, DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM); + onewire_host_set_overdrive(host, true); + + if(!dallas_common_write_mem( + host, + DS1996_COPY_SCRATCH_TIMEOUT_US, + DS1996_SRAM_PAGE_SIZE, + data->sram_data, + DS1996_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + onewire_host_set_overdrive(host, false); + return success; } -static void dallas_ds1996_reset_callback(void* context) { +static bool dallas_ds1996_reset_callback(bool is_short, void* context) { furi_assert(context); DS1996ProtocolData* data = context; data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + return true; } static bool dallas_ds1996_command_callback(uint8_t command, void* context) { @@ -96,8 +126,7 @@ static bool dallas_ds1996_command_callback(uint8_t command, void* context) { } else if(data->state.command_state == DallasCommonCommandStateRomCmd) { data->state.command_state = DallasCommonCommandStateMemCmd; - dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); - return false; + return dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); } else { return false; @@ -120,8 +149,17 @@ static bool dallas_ds1996_command_callback(uint8_t command, void* context) { } case DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + onewire_slave_set_overdrive(bus, true); + return true; + } else { + return false; + } + + case DALLAS_COMMON_CMD_MATCH_ROM: case DALLAS_COMMON_CMD_OVERDRIVE_MATCH_ROM: - /* TODO: Overdrive mode support */ + /* TODO: Match ROM command support */ default: return false; } diff --git a/lib/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/ibutton/protocols/dallas/protocol_ds_generic.c index 50fd04511..af355f461 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds_generic.c +++ b/lib/ibutton/protocols/dallas/protocol_ds_generic.c @@ -61,6 +61,14 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } +static bool ds_generic_reset_callback(bool is_short, void* context) { + DallasGenericProtocolData* data = context; + if(!is_short) { + onewire_slave_set_overdrive(data->state.bus, is_short); + } + return !is_short; +} + static bool ds_generic_command_callback(uint8_t command, void* context) { furi_assert(context); DallasGenericProtocolData* data = context; @@ -85,7 +93,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { DallasGenericProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, NULL); onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data); } diff --git a/lib/one_wire/SConscript b/lib/one_wire/SConscript index 8d73c9dbf..2dde9153d 100644 --- a/lib/one_wire/SConscript +++ b/lib/one_wire/SConscript @@ -8,7 +8,6 @@ env.Append( "#/lib/one_wire", ], SDK_HEADERS=[ - File("one_wire_host_timing.h"), File("one_wire_host.h"), File("one_wire_slave.h"), File("maxim_crc.h"), diff --git a/lib/one_wire/one_wire_host.c b/lib/one_wire/one_wire_host.c index 0a4a79f5c..678812105 100644 --- a/lib/one_wire/one_wire_host.c +++ b/lib/one_wire/one_wire_host.c @@ -1,10 +1,54 @@ #include +/** + * Timings based on Application Note 126: + * https://www.analog.com/media/en/technical-documentation/tech-articles/1wire-communication-through-software--maxim-integrated.pdf + */ + #include "one_wire_host.h" -#include "one_wire_host_timing.h" + +typedef struct { + uint16_t a; + uint16_t b; + uint16_t c; + uint16_t d; + uint16_t e; + uint16_t f; + uint16_t g; + uint16_t h; + uint16_t i; + uint16_t j; +} OneWireHostTimings; + +static const OneWireHostTimings onewire_host_timings_normal = { + .a = 9, + .b = 64, + .c = 64, + .d = 14, + .e = 9, + .f = 55, + .g = 0, + .h = 480, + .i = 70, + .j = 410, +}; + +static const OneWireHostTimings onewire_host_timings_overdrive = { + .a = 1, + .b = 8, + .c = 8, + .d = 3, + .e = 1, + .f = 7, + .g = 3, + .h = 70, + .i = 9, + .j = 40, +}; struct OneWireHost { const GpioPin* gpio_pin; + const OneWireHostTimings* timings; unsigned char saved_rom[8]; /** < global search state */ uint8_t last_discrepancy; uint8_t last_family_discrepancy; @@ -15,6 +59,7 @@ OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin) { OneWireHost* host = malloc(sizeof(OneWireHost)); host->gpio_pin = gpio_pin; onewire_host_reset_search(host); + onewire_host_set_overdrive(host, false); return host; } @@ -27,6 +72,8 @@ bool onewire_host_reset(OneWireHost* host) { uint8_t r; uint8_t retries = 125; + const OneWireHostTimings* timings = host->timings; + // wait until the gpio is high furi_hal_gpio_write(host->gpio_pin, true); do { @@ -35,19 +82,19 @@ bool onewire_host_reset(OneWireHost* host) { } while(!furi_hal_gpio_read(host->gpio_pin)); // pre delay - furi_delay_us(OWH_RESET_DELAY_PRE); + furi_delay_us(timings->g); // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_RESET_DRIVE); + furi_delay_us(timings->h); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_RESET_RELEASE); + furi_delay_us(timings->i); // read and post delay r = !furi_hal_gpio_read(host->gpio_pin); - furi_delay_us(OWH_RESET_DELAY_POST); + furi_delay_us(timings->j); return r; } @@ -55,17 +102,19 @@ bool onewire_host_reset(OneWireHost* host) { bool onewire_host_read_bit(OneWireHost* host) { bool result; + const OneWireHostTimings* timings = host->timings; + // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_READ_DRIVE); + furi_delay_us(timings->a); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_READ_RELEASE); + furi_delay_us(timings->e); // read and post delay result = furi_hal_gpio_read(host->gpio_pin); - furi_delay_us(OWH_READ_DELAY_POST); + furi_delay_us(timings->f); return result; } @@ -89,22 +138,24 @@ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count) } void onewire_host_write_bit(OneWireHost* host, bool value) { + const OneWireHostTimings* timings = host->timings; + if(value) { // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_WRITE_1_DRIVE); + furi_delay_us(timings->a); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_WRITE_1_RELEASE); + furi_delay_us(timings->b); } else { // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_WRITE_0_DRIVE); + furi_delay_us(timings->c); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_WRITE_0_RELEASE); + furi_delay_us(timings->d); } } @@ -122,10 +173,6 @@ void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t } } -void onewire_host_skip(OneWireHost* host) { - onewire_host_write(host, 0xCC); -} - void onewire_host_start(OneWireHost* host) { furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); @@ -154,7 +201,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) { host->last_device_flag = false; } -uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) { +bool onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) { uint8_t id_bit_number; uint8_t last_zero, rom_byte_number, search_result; uint8_t id_bit, cmp_id_bit; @@ -268,3 +315,7 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSea return search_result; } + +void onewire_host_set_overdrive(OneWireHost* host, bool set) { + host->timings = set ? &onewire_host_timings_overdrive : &onewire_host_timings_normal; +} diff --git a/lib/one_wire/one_wire_host.h b/lib/one_wire/one_wire_host.h index dc469904d..9f9bd4ffd 100644 --- a/lib/one_wire/one_wire_host.h +++ b/lib/one_wire/one_wire_host.h @@ -15,114 +15,115 @@ extern "C" { typedef enum { OneWireHostSearchModeConditional = 0, /**< Search for alarmed device */ - OneWireHostSearchModeNormal = 1, /**< Search all devices */ + OneWireHostSearchModeNormal = 1, /**< Search for all devices */ } OneWireHostSearchMode; typedef struct OneWireHost OneWireHost; /** - * Allocate onewire host bus - * @param pin - * @return OneWireHost* + * Allocate OneWireHost instance + * @param [in] gpio_pin connection pin + * @return pointer to OneWireHost instance */ OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin); /** - * Deallocate onewire host bus - * @param host + * Destroy OneWireHost instance, free resources + * @param [in] host pointer to OneWireHost instance */ void onewire_host_free(OneWireHost* host); /** - * Reset bus - * @param host - * @return bool + * Reset the 1-Wire bus + * @param [in] host pointer to OneWireHost instance + * @return true if presence was detected, false otherwise */ bool onewire_host_reset(OneWireHost* host); /** * Read one bit - * @param host - * @return bool + * @param [in] host pointer to OneWireHost instance + * @return received bit value */ bool onewire_host_read_bit(OneWireHost* host); /** * Read one byte - * @param host - * @return uint8_t + * @param [in] host pointer to OneWireHost instance + * @return received byte value */ uint8_t onewire_host_read(OneWireHost* host); /** - * Read many bytes - * @param host - * @param buffer - * @param count + * Read one or more bytes + * @param [in] host pointer to OneWireHost instance + * @param [out] buffer received data buffer + * @param [in] count number of bytes to read */ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count); /** * Write one bit - * @param host - * @param value + * @param [in] host pointer to OneWireHost instance + * @param value bit value to write */ void onewire_host_write_bit(OneWireHost* host, bool value); /** * Write one byte - * @param host - * @param value + * @param [in] host pointer to OneWireHost instance + * @param value byte value to write */ void onewire_host_write(OneWireHost* host, uint8_t value); /** - * Write many bytes - * @param host - * @param buffer - * @param count + * Write one or more bytes + * @param [in] host pointer to OneWireHost instance + * @param [in] buffer pointer to the data to write + * @param [in] count size of the data to write */ void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t count); -/** - * Skip ROM command - * @param host - */ -void onewire_host_skip(OneWireHost* host); - /** * Start working with the bus - * @param host + * @param [in] host pointer to OneWireHost instance */ void onewire_host_start(OneWireHost* host); /** * Stop working with the bus - * @param host + * @param [in] host pointer to OneWireHost instance */ void onewire_host_stop(OneWireHost* host); /** - * - * @param host + * Reset previous search results + * @param [in] host pointer to OneWireHost instance */ void onewire_host_reset_search(OneWireHost* host); /** - * - * @param host - * @param family_code + * Set the family code to search for + * @param [in] host pointer to OneWireHost instance + * @param [in] family_code device family code */ void onewire_host_target_search(OneWireHost* host, uint8_t family_code); /** - * - * @param host - * @param newAddr - * @param mode - * @return uint8_t + * Search for devices on the 1-Wire bus + * @param [in] host pointer to OneWireHost instance + * @param [out] new_addr pointer to the buffer to contain the unique ROM of the found device + * @param [in] mode search mode + * @return true on success, false otherwise */ -uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode); +bool onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode); + +/** + * Enable overdrive mode + * @param [in] host pointer to OneWireHost instance + * @param [in] set true to turn overdrive on, false to turn it off + */ +void onewire_host_set_overdrive(OneWireHost* host, bool set); #ifdef __cplusplus } diff --git a/lib/one_wire/one_wire_host_timing.h b/lib/one_wire/one_wire_host_timing.h deleted file mode 100644 index f95dd3561..000000000 --- a/lib/one_wire/one_wire_host_timing.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @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 index d1676cf3b..733b36e30 100644 --- a/lib/one_wire/one_wire_slave.c +++ b/lib/one_wire/one_wire_slave.c @@ -3,20 +3,7 @@ #include #include -#define ONEWIRE_TRSTL_MIN 270 /* Minimum Reset Low time */ -#define ONEWIRE_TRSTL_MAX 1200 /* Maximum Reset Low time */ - -#define ONEWIRE_TPDH_TYP 20 /* Typical Presence Detect High time */ -#define ONEWIRE_TPDL_MIN 100 /* Minimum Presence Detect Low time */ -#define ONEWIRE_TPDL_MAX 480 /* Maximum Presence Detect Low time */ - -#define ONEWIRE_TSLOT_MIN 60 /* Minimum Read/Write Slot time */ -#define ONEWIRE_TSLOT_MAX 135 /* Maximum Read/Write Slot time */ - -#define ONEWIRE_TW1L_MAX 20 /* Maximum Master Write 1 time */ -#define ONEWIRE_TRL_TMSR_MAX 30 /* Maximum Master Read Low + Read Sample time */ - -#define ONEWIRE_TH_TIMEOUT 15000 /* Maximum time before general timeout */ +#define TH_TIMEOUT_MAX 15000 /* Maximum time before general timeout */ typedef enum { OneWireSlaveErrorNone = 0, @@ -26,10 +13,29 @@ typedef enum { OneWireSlaveErrorTimeout, } OneWireSlaveError; +typedef struct { + uint16_t trstl_min; /* Minimum Reset Low time */ + uint16_t trstl_max; /* Maximum Reset Low time */ + + uint16_t tpdh_typ; /* Typical Presence Detect High time */ + uint16_t tpdl_min; /* Minimum Presence Detect Low time */ + uint16_t tpdl_max; /* Maximum Presence Detect Low time */ + + uint16_t tslot_min; /* Minimum Read/Write Slot time */ + uint16_t tslot_max; /* Maximum Read/Write Slot time */ + + uint16_t tw1l_max; /* Maximum Master Write 1 time */ + uint16_t trl_tmsr_max; /* Maximum Master Read Low + Read Sample time */ +} OneWireSlaveTimings; + struct OneWireSlave { const GpioPin* gpio_pin; + const OneWireSlaveTimings* timings; OneWireSlaveError error; + bool is_first_reset; + bool is_short_reset; + OneWireSlaveResetCallback reset_callback; OneWireSlaveCommandCallback command_callback; OneWireSlaveResultCallback result_callback; @@ -39,42 +45,72 @@ struct OneWireSlave { void* command_callback_context; }; +static const OneWireSlaveTimings onewire_slave_timings_normal = { + .trstl_min = 270, + .trstl_max = 1200, + + .tpdh_typ = 20, + .tpdl_min = 100, + .tpdl_max = 480, + + .tslot_min = 60, + .tslot_max = 135, + + .tw1l_max = 20, + .trl_tmsr_max = 30, +}; + +static const OneWireSlaveTimings onewire_slave_timings_overdrive = { + .trstl_min = 48, + .trstl_max = 80, + + .tpdh_typ = 0, + .tpdl_min = 8, + .tpdl_max = 24, + + .tslot_min = 6, + .tslot_max = 16, + + .tw1l_max = 2, + .trl_tmsr_max = 3, +}; + /*********************** PRIVATE ***********************/ -static 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 * furi_hal_cortex_instructions_per_microsecond(); - uint32_t time_captured; +static bool + onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time_us, const bool pin_value) { + const uint32_t time_start = DWT->CYCCNT; + const uint32_t time_ticks = time_us * furi_hal_cortex_instructions_per_microsecond(); + + uint32_t time_elapsed; do { //-V1044 - time_captured = DWT->CYCCNT; + time_elapsed = DWT->CYCCNT - time_start; if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) { - uint32_t remaining_time = time_ticks - (time_captured - start); - remaining_time /= furi_hal_cortex_instructions_per_microsecond(); - return remaining_time; + return time_ticks >= time_elapsed; } - } while((time_captured - start) < time_ticks); + } while(time_elapsed < time_ticks); - return 0; + return false; } -static bool onewire_slave_show_presence(OneWireSlave* bus) { +static inline bool onewire_slave_show_presence(OneWireSlave* bus) { + const OneWireSlaveTimings* timings = bus->timings; // wait until the bus is high (might return immediately) - onewire_slave_wait_while_gpio_is(bus, ONEWIRE_TRSTL_MAX, false); + onewire_slave_wait_while_gpio_is(bus, timings->trstl_max, false); // wait while master delay presence check - furi_delay_us(ONEWIRE_TPDH_TYP); + furi_delay_us(timings->tpdh_typ); // show presence furi_hal_gpio_write(bus->gpio_pin, false); - furi_delay_us(ONEWIRE_TPDL_MIN); + furi_delay_us(timings->tpdl_min); furi_hal_gpio_write(bus->gpio_pin, true); // somebody also can show presence - const uint32_t wait_low_time = ONEWIRE_TPDL_MAX - ONEWIRE_TPDL_MIN; + const uint32_t wait_low_time = timings->tpdl_max - timings->tpdl_min; // so we will wait - if(onewire_slave_wait_while_gpio_is(bus, wait_low_time, false) == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, wait_low_time, false)) { bus->error = OneWireSlaveErrorPresenceConflict; return false; } @@ -85,27 +121,36 @@ static bool onewire_slave_show_presence(OneWireSlave* bus) { static inline bool onewire_slave_receive_and_process_command(OneWireSlave* bus) { /* Reset condition detected, send a presence pulse and reset protocol state */ if(bus->error == OneWireSlaveErrorResetInProgress) { - if(onewire_slave_show_presence(bus)) { - bus->error = OneWireSlaveErrorNone; + if(!bus->is_first_reset) { + /* Guess the reset type */ + bus->is_short_reset = onewire_slave_wait_while_gpio_is( + bus, + onewire_slave_timings_overdrive.trstl_max - + onewire_slave_timings_overdrive.tslot_max, + false); + } else { + bus->is_first_reset = false; + } - if(bus->reset_callback != NULL) { - bus->reset_callback(bus->reset_callback_context); + furi_assert(bus->reset_callback); + + if(bus->reset_callback(bus->is_short_reset, bus->reset_callback_context)) { + if(onewire_slave_show_presence(bus)) { + bus->error = OneWireSlaveErrorNone; + return true; } - - return true; } } else if(bus->error == OneWireSlaveErrorNone) { uint8_t command; - if(!onewire_slave_receive(bus, &command, 1)) { - /* Upon failure, request an additional iteration to - choose the appropriate action by checking bus->error */ - return true; - } else if(bus->command_callback) { - return bus->command_callback(command, bus->command_callback_context); - } else { - bus->error = OneWireSlaveErrorInvalidCommand; + if(onewire_slave_receive(bus, &command, sizeof(command))) { + furi_assert(bus->command_callback); + if(bus->command_callback(command, bus->command_callback_context)) { + return true; + } } + + return (bus->error == OneWireSlaveErrorResetInProgress); } return false; @@ -115,9 +160,6 @@ static inline bool onewire_slave_bus_start(OneWireSlave* bus) { FURI_CRITICAL_ENTER(); furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - /* Start in Reset state in order to send a presence pulse immediately */ - bus->error = OneWireSlaveErrorResetInProgress; - while(onewire_slave_receive_and_process_command(bus)) ; @@ -139,7 +181,15 @@ static void onewire_slave_exti_callback(void* context) { const uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); - if((pulse_length >= ONEWIRE_TRSTL_MIN) && pulse_length <= (ONEWIRE_TRSTL_MAX)) { + if((pulse_length >= onewire_slave_timings_overdrive.trstl_min) && + (pulse_length <= onewire_slave_timings_normal.trstl_max)) { + /* Start in reset state in order to send a presence pulse immediately */ + bus->error = OneWireSlaveErrorResetInProgress; + /* Determine reset type (chooses speed mode if supported by the emulated device) */ + bus->is_short_reset = pulse_length <= onewire_slave_timings_overdrive.trstl_max; + /* Initial reset allows going directly into overdrive mode */ + bus->is_first_reset = true; + const bool result = onewire_slave_bus_start(bus); if(result && bus->result_callback != NULL) { @@ -158,6 +208,7 @@ OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) { OneWireSlave* bus = malloc(sizeof(OneWireSlave)); bus->gpio_pin = gpio_pin; + bus->timings = &onewire_slave_timings_normal; bus->error = OneWireSlaveErrorNone; return bus; @@ -205,52 +256,45 @@ void onewire_slave_set_result_callback( } bool onewire_slave_receive_bit(OneWireSlave* bus) { + const OneWireSlaveTimings* timings = bus->timings; // wait while bus is low - uint32_t time = ONEWIRE_TSLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) { bus->error = OneWireSlaveErrorResetInProgress; return false; } // wait while bus is high - time = ONEWIRE_TH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) { bus->error = OneWireSlaveErrorTimeout; return false; } // wait a time of zero - time = ONEWIRE_TW1L_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - - return (time > 0); + return onewire_slave_wait_while_gpio_is(bus, timings->tw1l_max, false); } bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { + const OneWireSlaveTimings* timings = bus->timings; // wait while bus is low - uint32_t time = ONEWIRE_TSLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) { bus->error = OneWireSlaveErrorResetInProgress; return false; } // wait while bus is high - time = ONEWIRE_TH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) { bus->error = OneWireSlaveErrorTimeout; return false; } // choose write time + uint32_t time; + if(!value) { furi_hal_gpio_write(bus->gpio_pin, false); - time = ONEWIRE_TRL_TMSR_MAX; + time = timings->trl_tmsr_max; } else { - time = ONEWIRE_TSLOT_MIN; + time = timings->tslot_min; } // hold line for ZERO or ONE time @@ -301,3 +345,13 @@ bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size) { } return true; } + +void onewire_slave_set_overdrive(OneWireSlave* bus, bool set) { + const OneWireSlaveTimings* new_timings = set ? &onewire_slave_timings_overdrive : + &onewire_slave_timings_normal; + if(bus->timings != new_timings) { + /* Prevent erroneous reset by waiting for the previous time slot to finish */ + onewire_slave_wait_while_gpio_is(bus, bus->timings->tslot_max, false); + bus->timings = new_timings; + } +} diff --git a/lib/one_wire/one_wire_slave.h b/lib/one_wire/one_wire_slave.h index 914cd9335..21114b912 100644 --- a/lib/one_wire/one_wire_slave.h +++ b/lib/one_wire/one_wire_slave.h @@ -18,68 +18,85 @@ extern "C" { typedef struct OneWireDevice OneWireDevice; typedef struct OneWireSlave OneWireSlave; -typedef void (*OneWireSlaveResetCallback)(void* context); -typedef void (*OneWireSlaveResultCallback)(void* context); +typedef bool (*OneWireSlaveResetCallback)(bool is_short, void* context); typedef bool (*OneWireSlaveCommandCallback)(uint8_t command, void* context); +typedef void (*OneWireSlaveResultCallback)(void* context); /** - * Allocate onewire slave - * @param gpio_pin - * @return OneWireSlave* + * Allocate OneWireSlave instance + * @param [in] gpio_pin connection pin + * @return pointer to OneWireSlave instance */ OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin); /** - * Free onewire slave - * @param bus + * Destroy OneWireSlave instance, free resources + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_free(OneWireSlave* bus); /** * Start working with the bus - * @param bus + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_start(OneWireSlave* bus); /** * Stop working with the bus - * @param bus + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_stop(OneWireSlave* bus); /** - * TODO: description comment + * Receive one bit + * @param [in] bus pointer to OneWireSlave instance + * @return received bit value */ bool onewire_slave_receive_bit(OneWireSlave* bus); /** - * TODO: description comment + * Send one bit + * @param [in] bus pointer to OneWireSlave instance + * @param [in] value bit value to send + * @return true on success, false on failure */ bool onewire_slave_send_bit(OneWireSlave* bus, bool value); /** - * Send data - * @param bus - * @param data - * @param data_size - * @return bool + * Send one or more bytes of data + * @param [in] bus pointer to OneWireSlave instance + * @param [in] data pointer to the data to send + * @param [in] data_size size of the data to send + * @return true on success, false on failure */ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size); /** - * Receive data - * @param bus - * @param data - * @param data_size - * @return bool + * Receive one or more bytes of data + * @param [in] bus pointer to OneWireSlave instance + * @param [out] data pointer to the receive buffer + * @param [in] data_size number of bytes to receive + * @return true on success, false on failure */ bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size); /** - * Set a callback to be called on each reset - * @param bus - * @param callback - * @param context + * Enable overdrive mode + * @param [in] bus pointer to OneWireSlave instance + * @param [in] set true to turn overdrive on, false to turn it off + */ +void onewire_slave_set_overdrive(OneWireSlave* bus, bool set); + +/** + * Set a callback function to be called on each reset. + * The return value of the callback determines whether the emulated device + * supports the short reset (passed as the is_short parameter). + * In most applications, it should also call onewire_slave_set_overdrive() + * to set the appropriate speed mode. + * + * @param [in] bus pointer to OneWireSlave instance + * @param [in] callback pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_reset_callback( OneWireSlave* bus, @@ -87,10 +104,13 @@ void onewire_slave_set_reset_callback( void* context); /** - * Set a callback to be called on each command - * @param bus - * @param callback - * @param context + * Set a callback function to be called on each command. + * The return value of the callback determines whether further operation + * is possible. As a rule of thumb, return true unless a critical error happened. + * + * @param [in] bus pointer to OneWireSlave instance + * @param [in] callback pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_command_callback( OneWireSlave* bus, @@ -99,9 +119,9 @@ void onewire_slave_set_command_callback( /** * Set a callback to report emulation success - * @param bus - * @param result_cb - * @param context + * @param [in] bus pointer to OneWireSlave instance + * @param [in] result_cb pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_result_callback( OneWireSlave* bus,