[FL-3179] 1-Wire Overdrive Mode (#2522)

* 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: あく <alleteam@gmail.com>
This commit is contained in:
Georgii Surkov 2023-03-22 17:54:06 +03:00 committed by GitHub
parent 1f236ede0e
commit 8b224ecb15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 397 additions and 227 deletions

View File

@ -19,9 +19,12 @@
#include <one_wire/maxim_crc.h> #include <one_wire/maxim_crc.h>
#include <one_wire/one_wire_host.h> #include <one_wire/one_wire_host.h>
#include <furi_hal_power.h>
#define UPDATE_PERIOD_MS 1000UL #define UPDATE_PERIOD_MS 1000UL
#define TEXT_STORE_SIZE 64U #define TEXT_STORE_SIZE 64U
#define DS18B20_CMD_SKIP_ROM 0xccU
#define DS18B20_CMD_CONVERT 0x44U #define DS18B20_CMD_CONVERT 0x44U
#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU #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. /* After the reset, a ROM operation must follow.
If there is only one device connected, the "Skip ROM" command is most appropriate 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).*/ (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. /* After the ROM operation, a device-specific command is issued.
In this case, it's a request to start measuring the temperature. */ In this case, it's a request to start measuring the temperature. */
onewire_host_write(onewire, DS18B20_CMD_CONVERT); 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. /* After the reset, a ROM operation must follow.
If there is only one device connected, the "Skip ROM" command is most appropriate 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).*/ (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. /* After the ROM operation, a device-specific command is issued.
This time, it will be the "Read Scratchpad" command which will 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 */ /* Starts the reader thread and handles the input */
static void example_thermo_run(ExampleThermoContext* context) { static void example_thermo_run(ExampleThermoContext* context) {
/* Enable power on external pins */
furi_hal_power_enable_otg();
/* Configure the hardware in host mode */ /* Configure the hardware in host mode */
onewire_host_start(context->onewire); onewire_host_start(context->onewire);
@ -299,6 +305,9 @@ static void example_thermo_run(ExampleThermoContext* context) {
/* Reset the hardware */ /* Reset the hardware */
onewire_host_stop(context->onewire); onewire_host_stop(context->onewire);
/* Disable power on external pins */
furi_hal_power_disable_otg();
} }
/******************** Initialisation & startup *****************************/ /******************** Initialisation & startup *****************************/

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,19.0,, Version,+,20.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.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/mlib/m-variant.h,,
Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/maxim_crc.h,,
Header,+,lib/one_wire/one_wire_host.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/one_wire/one_wire_slave.h,,
Header,+,lib/print/wrappers.h,, Header,+,lib/print/wrappers.h,,
Header,+,lib/toolbox/args.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_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t"
Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset,_Bool,OneWireHost*
Function,+,onewire_host_reset_search,void,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost*
Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode"
Function,+,onewire_host_skip,void,OneWireHost* Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool"
Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_start,void,OneWireHost*
Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost*
Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" 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,_Bool,"OneWireSlave*, const uint8_t*, size_t"
Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool"
Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" 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_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*"
Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*"
Function,+,onewire_slave_start,void,OneWireSlave* Function,+,onewire_slave_start,void,OneWireSlave*

1 entry status name type params
2 Version + 19.0 20.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
153 Header + lib/mlib/m-variant.h
154 Header + lib/one_wire/maxim_crc.h
155 Header + lib/one_wire/one_wire_host.h
Header + lib/one_wire/one_wire_host_timing.h
156 Header + lib/one_wire/one_wire_slave.h
157 Header + lib/print/wrappers.h
158 Header + lib/toolbox/args.h
1480 Function + onewire_host_read_bytes void OneWireHost*, uint8_t*, uint16_t
1481 Function + onewire_host_reset _Bool OneWireHost*
1482 Function + onewire_host_reset_search void OneWireHost*
1483 Function + onewire_host_search uint8_t _Bool OneWireHost*, uint8_t*, OneWireHostSearchMode
1484 Function + onewire_host_skip onewire_host_set_overdrive void OneWireHost* OneWireHost*, _Bool
1485 Function + onewire_host_start void OneWireHost*
1486 Function + onewire_host_stop void OneWireHost*
1487 Function + onewire_host_target_search void OneWireHost*, uint8_t
1495 Function + onewire_slave_send _Bool OneWireSlave*, const uint8_t*, size_t
1496 Function + onewire_slave_send_bit _Bool OneWireSlave*, _Bool
1497 Function + onewire_slave_set_command_callback void OneWireSlave*, OneWireSlaveCommandCallback, void*
1498 Function + onewire_slave_set_overdrive void OneWireSlave*, _Bool
1499 Function + onewire_slave_set_reset_callback void OneWireSlave*, OneWireSlaveResetCallback, void*
1500 Function + onewire_slave_set_result_callback void OneWireSlave*, OneWireSlaveResultCallback, void*
1501 Function + onewire_slave_start void OneWireSlave*

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,19.0,, Version,+,20.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.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/nfc/nfc_device.h,,
Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/maxim_crc.h,,
Header,+,lib/one_wire/one_wire_host.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/one_wire/one_wire_slave.h,,
Header,+,lib/print/wrappers.h,, Header,+,lib/print/wrappers.h,,
Header,+,lib/subghz/blocks/const.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_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t"
Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset,_Bool,OneWireHost*
Function,+,onewire_host_reset_search,void,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost*
Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode"
Function,+,onewire_host_skip,void,OneWireHost* Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool"
Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_start,void,OneWireHost*
Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost*
Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" 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,_Bool,"OneWireSlave*, const uint8_t*, size_t"
Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool"
Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" 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_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*"
Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*"
Function,+,onewire_slave_start,void,OneWireSlave* Function,+,onewire_slave_start,void,OneWireSlave*

1 entry status name type params
2 Version + 19.0 20.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
172 Header + lib/nfc/nfc_device.h
173 Header + lib/one_wire/maxim_crc.h
174 Header + lib/one_wire/one_wire_host.h
Header + lib/one_wire/one_wire_host_timing.h
175 Header + lib/one_wire/one_wire_slave.h
176 Header + lib/print/wrappers.h
177 Header + lib/subghz/blocks/const.h
2061 Function + onewire_host_read_bytes void OneWireHost*, uint8_t*, uint16_t
2062 Function + onewire_host_reset _Bool OneWireHost*
2063 Function + onewire_host_reset_search void OneWireHost*
2064 Function + onewire_host_search uint8_t _Bool OneWireHost*, uint8_t*, OneWireHostSearchMode
2065 Function + onewire_host_skip onewire_host_set_overdrive void OneWireHost* OneWireHost*, _Bool
2066 Function + onewire_host_start void OneWireHost*
2067 Function + onewire_host_stop void OneWireHost*
2068 Function + onewire_host_target_search void OneWireHost*, uint8_t
2076 Function + onewire_slave_send _Bool OneWireSlave*, const uint8_t*, size_t
2077 Function + onewire_slave_send_bit _Bool OneWireSlave*, _Bool
2078 Function + onewire_slave_set_command_callback void OneWireSlave*, OneWireSlaveCommandCallback, void*
2079 Function + onewire_slave_set_overdrive void OneWireSlave*, _Bool
2080 Function + onewire_slave_set_reset_callback void OneWireSlave*, OneWireSlaveResetCallback, void*
2081 Function + onewire_slave_set_result_callback void OneWireSlave*, OneWireSlaveResultCallback, void*
2082 Function + onewire_slave_start void OneWireSlave*

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#include <flipper_format.h>
#include <one_wire/one_wire_host.h> #include <one_wire/one_wire_host.h>
#include <one_wire/one_wire_slave.h> #include <one_wire/one_wire_slave.h>
#include <flipper_format/flipper_format.h>
#define DALLAS_COMMON_MANUFACTURER_NAME "Dallas" #define DALLAS_COMMON_MANUFACTURER_NAME "Dallas"
#define DALLAS_COMMON_CMD_READ_ROM 0x33U #define DALLAS_COMMON_CMD_READ_ROM 0x33U

View File

@ -2,11 +2,11 @@
#include "../protocol_common_i.h" #include "../protocol_common_i.h"
#include <flipper_format.h>
#include <one_wire/one_wire_host.h> #include <one_wire/one_wire_host.h>
#include <one_wire/one_wire_slave.h> #include <one_wire/one_wire_slave.h>
#include <flipper_format/flipper_format.h>
typedef bool (*iButtonProtocolDallasReadWriteFunc)(OneWireHost*, iButtonProtocolData*); typedef bool (*iButtonProtocolDallasReadWriteFunc)(OneWireHost*, iButtonProtocolData*);
typedef void (*iButtonProtocolDallasEmulateFunc)(OneWireSlave*, iButtonProtocolData*); typedef void (*iButtonProtocolDallasEmulateFunc)(OneWireSlave*, iButtonProtocolData*);
typedef bool (*iButtonProtocolDallasSaveFunc)(FlipperFormat*, const iButtonProtocolData*); typedef bool (*iButtonProtocolDallasSaveFunc)(FlipperFormat*, const iButtonProtocolData*);

View File

@ -53,7 +53,7 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1971 = {
.name = DS1971_FAMILY_NAME, .name = DS1971_FAMILY_NAME,
.read = dallas_ds1971_read, .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, .write_copy = dallas_ds1971_write_copy,
.emulate = dallas_ds1971_emulate, .emulate = dallas_ds1971_emulate,
.save = dallas_ds1971_save, .save = dallas_ds1971_save,
@ -76,7 +76,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d
DS1971ProtocolData* data = protocol_data; DS1971ProtocolData* data = protocol_data;
onewire_host_reset(host); onewire_host_reset(host);
onewire_host_skip(host); onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM);
// Starting writing from address 0x0000 // Starting writing from address 0x0000
onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH); onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH);
onewire_host_write(host, 0x00); onewire_host_write(host, 0x00);
@ -87,7 +87,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d
bool pad_valid = false; bool pad_valid = false;
if(onewire_host_reset(host)) { if(onewire_host_reset(host)) {
pad_valid = true; 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, DALLAS_COMMON_CMD_READ_SCRATCH);
onewire_host_write(host, 0x00); 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 // Copy scratchpad to memory and confirm
if(pad_valid) { if(pad_valid) {
if(onewire_host_reset(host)) { 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, DALLAS_COMMON_CMD_COPY_SCRATCH);
onewire_host_write(host, DS1971_CMD_FINALIZATION); onewire_host_write(host, DS1971_CMD_FINALIZATION);
@ -114,10 +114,16 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d
return pad_valid; 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); furi_assert(context);
DS1971ProtocolData* data = 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) { static bool dallas_ds1971_command_callback(uint8_t command, void* context) {

View File

@ -67,6 +67,14 @@ bool dallas_ds1990_write_blank(OneWireHost* host, iButtonProtocolData* protocol_
tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); 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) { static bool dallas_ds1990_command_callback(uint8_t command, void* context) {
furi_assert(context); furi_assert(context);
DS1990ProtocolData* data = context; DS1990ProtocolData* data = context;
@ -92,7 +100,7 @@ void dallas_ds1990_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data
DS1990ProtocolData* data = protocol_data; DS1990ProtocolData* data = protocol_data;
data->state.bus = bus; 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); onewire_slave_set_command_callback(bus, dallas_ds1990_command_callback, protocol_data);
} }

View File

@ -87,10 +87,16 @@ bool dallas_ds1992_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d
DS1992_SRAM_DATA_SIZE); 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); furi_assert(context);
DS1992ProtocolData* data = 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) { static bool dallas_ds1992_command_callback(uint8_t command, void* context) {

View File

@ -63,24 +63,54 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1996 = {
bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) { bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) {
DS1996ProtocolData* data = protocol_data; DS1996ProtocolData* data = protocol_data;
return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data) && bool success = false;
dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE);
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) { bool dallas_ds1996_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) {
DS1996ProtocolData* data = protocol_data; DS1996ProtocolData* data = protocol_data;
return dallas_common_write_mem( bool success = false;
host,
DS1996_COPY_SCRATCH_TIMEOUT_US, do {
DS1996_SRAM_PAGE_SIZE, if(!onewire_host_reset(host)) break;
data->sram_data,
DS1996_SRAM_DATA_SIZE); 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); furi_assert(context);
DS1996ProtocolData* data = context; DS1996ProtocolData* data = context;
data->state.command_state = DallasCommonCommandStateIdle; 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) { 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) { } else if(data->state.command_state == DallasCommonCommandStateRomCmd) {
data->state.command_state = DallasCommonCommandStateMemCmd; data->state.command_state = DallasCommonCommandStateMemCmd;
dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); return dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE);
return false;
} else { } else {
return false; return false;
@ -120,8 +149,17 @@ static bool dallas_ds1996_command_callback(uint8_t command, void* context) {
} }
case DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM: 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: case DALLAS_COMMON_CMD_OVERDRIVE_MATCH_ROM:
/* TODO: Overdrive mode support */ /* TODO: Match ROM command support */
default: default:
return false; return false;
} }

View File

@ -61,6 +61,14 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat
return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); 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) { static bool ds_generic_command_callback(uint8_t command, void* context) {
furi_assert(context); furi_assert(context);
DallasGenericProtocolData* data = context; DallasGenericProtocolData* data = context;
@ -85,7 +93,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) {
DallasGenericProtocolData* data = protocol_data; DallasGenericProtocolData* data = protocol_data;
data->state.bus = bus; 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); onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data);
} }

View File

@ -8,7 +8,6 @@ env.Append(
"#/lib/one_wire", "#/lib/one_wire",
], ],
SDK_HEADERS=[ SDK_HEADERS=[
File("one_wire_host_timing.h"),
File("one_wire_host.h"), File("one_wire_host.h"),
File("one_wire_slave.h"), File("one_wire_slave.h"),
File("maxim_crc.h"), File("maxim_crc.h"),

View File

@ -1,10 +1,54 @@
#include <furi.h> #include <furi.h>
/**
* 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.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 { struct OneWireHost {
const GpioPin* gpio_pin; const GpioPin* gpio_pin;
const OneWireHostTimings* timings;
unsigned char saved_rom[8]; /** < global search state */ unsigned char saved_rom[8]; /** < global search state */
uint8_t last_discrepancy; uint8_t last_discrepancy;
uint8_t last_family_discrepancy; uint8_t last_family_discrepancy;
@ -15,6 +59,7 @@ OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin) {
OneWireHost* host = malloc(sizeof(OneWireHost)); OneWireHost* host = malloc(sizeof(OneWireHost));
host->gpio_pin = gpio_pin; host->gpio_pin = gpio_pin;
onewire_host_reset_search(host); onewire_host_reset_search(host);
onewire_host_set_overdrive(host, false);
return host; return host;
} }
@ -27,6 +72,8 @@ bool onewire_host_reset(OneWireHost* host) {
uint8_t r; uint8_t r;
uint8_t retries = 125; uint8_t retries = 125;
const OneWireHostTimings* timings = host->timings;
// wait until the gpio is high // wait until the gpio is high
furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_write(host->gpio_pin, true);
do { do {
@ -35,19 +82,19 @@ bool onewire_host_reset(OneWireHost* host) {
} while(!furi_hal_gpio_read(host->gpio_pin)); } while(!furi_hal_gpio_read(host->gpio_pin));
// pre delay // pre delay
furi_delay_us(OWH_RESET_DELAY_PRE); furi_delay_us(timings->g);
// drive low // drive low
furi_hal_gpio_write(host->gpio_pin, false); furi_hal_gpio_write(host->gpio_pin, false);
furi_delay_us(OWH_RESET_DRIVE); furi_delay_us(timings->h);
// release // release
furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_write(host->gpio_pin, true);
furi_delay_us(OWH_RESET_RELEASE); furi_delay_us(timings->i);
// read and post delay // read and post delay
r = !furi_hal_gpio_read(host->gpio_pin); r = !furi_hal_gpio_read(host->gpio_pin);
furi_delay_us(OWH_RESET_DELAY_POST); furi_delay_us(timings->j);
return r; return r;
} }
@ -55,17 +102,19 @@ bool onewire_host_reset(OneWireHost* host) {
bool onewire_host_read_bit(OneWireHost* host) { bool onewire_host_read_bit(OneWireHost* host) {
bool result; bool result;
const OneWireHostTimings* timings = host->timings;
// drive low // drive low
furi_hal_gpio_write(host->gpio_pin, false); furi_hal_gpio_write(host->gpio_pin, false);
furi_delay_us(OWH_READ_DRIVE); furi_delay_us(timings->a);
// release // release
furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_write(host->gpio_pin, true);
furi_delay_us(OWH_READ_RELEASE); furi_delay_us(timings->e);
// read and post delay // read and post delay
result = furi_hal_gpio_read(host->gpio_pin); result = furi_hal_gpio_read(host->gpio_pin);
furi_delay_us(OWH_READ_DELAY_POST); furi_delay_us(timings->f);
return result; 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) { void onewire_host_write_bit(OneWireHost* host, bool value) {
const OneWireHostTimings* timings = host->timings;
if(value) { if(value) {
// drive low // drive low
furi_hal_gpio_write(host->gpio_pin, false); furi_hal_gpio_write(host->gpio_pin, false);
furi_delay_us(OWH_WRITE_1_DRIVE); furi_delay_us(timings->a);
// release // release
furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_write(host->gpio_pin, true);
furi_delay_us(OWH_WRITE_1_RELEASE); furi_delay_us(timings->b);
} else { } else {
// drive low // drive low
furi_hal_gpio_write(host->gpio_pin, false); furi_hal_gpio_write(host->gpio_pin, false);
furi_delay_us(OWH_WRITE_0_DRIVE); furi_delay_us(timings->c);
// release // release
furi_hal_gpio_write(host->gpio_pin, true); 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) { void onewire_host_start(OneWireHost* host) {
furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_write(host->gpio_pin, true);
furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); 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; 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 id_bit_number;
uint8_t last_zero, rom_byte_number, search_result; uint8_t last_zero, rom_byte_number, search_result;
uint8_t id_bit, cmp_id_bit; 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; return search_result;
} }
void onewire_host_set_overdrive(OneWireHost* host, bool set) {
host->timings = set ? &onewire_host_timings_overdrive : &onewire_host_timings_normal;
}

View File

@ -15,114 +15,115 @@ extern "C" {
typedef enum { typedef enum {
OneWireHostSearchModeConditional = 0, /**< Search for alarmed device */ OneWireHostSearchModeConditional = 0, /**< Search for alarmed device */
OneWireHostSearchModeNormal = 1, /**< Search all devices */ OneWireHostSearchModeNormal = 1, /**< Search for all devices */
} OneWireHostSearchMode; } OneWireHostSearchMode;
typedef struct OneWireHost OneWireHost; typedef struct OneWireHost OneWireHost;
/** /**
* Allocate onewire host bus * Allocate OneWireHost instance
* @param pin * @param [in] gpio_pin connection pin
* @return OneWireHost* * @return pointer to OneWireHost instance
*/ */
OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin); OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin);
/** /**
* Deallocate onewire host bus * Destroy OneWireHost instance, free resources
* @param host * @param [in] host pointer to OneWireHost instance
*/ */
void onewire_host_free(OneWireHost* host); void onewire_host_free(OneWireHost* host);
/** /**
* Reset bus * Reset the 1-Wire bus
* @param host * @param [in] host pointer to OneWireHost instance
* @return bool * @return true if presence was detected, false otherwise
*/ */
bool onewire_host_reset(OneWireHost* host); bool onewire_host_reset(OneWireHost* host);
/** /**
* Read one bit * Read one bit
* @param host * @param [in] host pointer to OneWireHost instance
* @return bool * @return received bit value
*/ */
bool onewire_host_read_bit(OneWireHost* host); bool onewire_host_read_bit(OneWireHost* host);
/** /**
* Read one byte * Read one byte
* @param host * @param [in] host pointer to OneWireHost instance
* @return uint8_t * @return received byte value
*/ */
uint8_t onewire_host_read(OneWireHost* host); uint8_t onewire_host_read(OneWireHost* host);
/** /**
* Read many bytes * Read one or more bytes
* @param host * @param [in] host pointer to OneWireHost instance
* @param buffer * @param [out] buffer received data buffer
* @param count * @param [in] count number of bytes to read
*/ */
void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count); void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count);
/** /**
* Write one bit * Write one bit
* @param host * @param [in] host pointer to OneWireHost instance
* @param value * @param value bit value to write
*/ */
void onewire_host_write_bit(OneWireHost* host, bool value); void onewire_host_write_bit(OneWireHost* host, bool value);
/** /**
* Write one byte * Write one byte
* @param host * @param [in] host pointer to OneWireHost instance
* @param value * @param value byte value to write
*/ */
void onewire_host_write(OneWireHost* host, uint8_t value); void onewire_host_write(OneWireHost* host, uint8_t value);
/** /**
* Write many bytes * Write one or more bytes
* @param host * @param [in] host pointer to OneWireHost instance
* @param buffer * @param [in] buffer pointer to the data to write
* @param count * @param [in] count size of the data to write
*/ */
void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t count); 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 * Start working with the bus
* @param host * @param [in] host pointer to OneWireHost instance
*/ */
void onewire_host_start(OneWireHost* host); void onewire_host_start(OneWireHost* host);
/** /**
* Stop working with the bus * Stop working with the bus
* @param host * @param [in] host pointer to OneWireHost instance
*/ */
void onewire_host_stop(OneWireHost* host); void onewire_host_stop(OneWireHost* host);
/** /**
* * Reset previous search results
* @param host * @param [in] host pointer to OneWireHost instance
*/ */
void onewire_host_reset_search(OneWireHost* host); void onewire_host_reset_search(OneWireHost* host);
/** /**
* * Set the family code to search for
* @param host * @param [in] host pointer to OneWireHost instance
* @param family_code * @param [in] family_code device family code
*/ */
void onewire_host_target_search(OneWireHost* host, uint8_t family_code); void onewire_host_target_search(OneWireHost* host, uint8_t family_code);
/** /**
* * Search for devices on the 1-Wire bus
* @param host * @param [in] host pointer to OneWireHost instance
* @param newAddr * @param [out] new_addr pointer to the buffer to contain the unique ROM of the found device
* @param mode * @param [in] mode search mode
* @return uint8_t * @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 #ifdef __cplusplus
} }

View File

@ -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

View File

@ -3,20 +3,7 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#define ONEWIRE_TRSTL_MIN 270 /* Minimum Reset Low time */ #define TH_TIMEOUT_MAX 15000 /* Maximum time before general timeout */
#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 */
typedef enum { typedef enum {
OneWireSlaveErrorNone = 0, OneWireSlaveErrorNone = 0,
@ -26,10 +13,29 @@ typedef enum {
OneWireSlaveErrorTimeout, OneWireSlaveErrorTimeout,
} OneWireSlaveError; } 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 { struct OneWireSlave {
const GpioPin* gpio_pin; const GpioPin* gpio_pin;
const OneWireSlaveTimings* timings;
OneWireSlaveError error; OneWireSlaveError error;
bool is_first_reset;
bool is_short_reset;
OneWireSlaveResetCallback reset_callback; OneWireSlaveResetCallback reset_callback;
OneWireSlaveCommandCallback command_callback; OneWireSlaveCommandCallback command_callback;
OneWireSlaveResultCallback result_callback; OneWireSlaveResultCallback result_callback;
@ -39,42 +45,72 @@ struct OneWireSlave {
void* command_callback_context; 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 ***********************/ /*********************** PRIVATE ***********************/
static uint32_t static bool
onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) { onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time_us, const bool pin_value) {
uint32_t start = DWT->CYCCNT; const uint32_t time_start = DWT->CYCCNT;
uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond(); const uint32_t time_ticks = time_us * furi_hal_cortex_instructions_per_microsecond();
uint32_t time_captured;
uint32_t time_elapsed;
do { //-V1044 do { //-V1044
time_captured = DWT->CYCCNT; time_elapsed = DWT->CYCCNT - time_start;
if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) { if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) {
uint32_t remaining_time = time_ticks - (time_captured - start); return time_ticks >= time_elapsed;
remaining_time /= furi_hal_cortex_instructions_per_microsecond();
return remaining_time;
} }
} 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) // 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 // wait while master delay presence check
furi_delay_us(ONEWIRE_TPDH_TYP); furi_delay_us(timings->tpdh_typ);
// show presence // show presence
furi_hal_gpio_write(bus->gpio_pin, false); 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); furi_hal_gpio_write(bus->gpio_pin, true);
// somebody also can show presence // 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 // 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; bus->error = OneWireSlaveErrorPresenceConflict;
return false; 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) { static inline bool onewire_slave_receive_and_process_command(OneWireSlave* bus) {
/* Reset condition detected, send a presence pulse and reset protocol state */ /* Reset condition detected, send a presence pulse and reset protocol state */
if(bus->error == OneWireSlaveErrorResetInProgress) { if(bus->error == OneWireSlaveErrorResetInProgress) {
if(onewire_slave_show_presence(bus)) { if(!bus->is_first_reset) {
bus->error = OneWireSlaveErrorNone; /* 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) { furi_assert(bus->reset_callback);
bus->reset_callback(bus->reset_callback_context);
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) { } else if(bus->error == OneWireSlaveErrorNone) {
uint8_t command; uint8_t command;
if(!onewire_slave_receive(bus, &command, 1)) { if(onewire_slave_receive(bus, &command, sizeof(command))) {
/* Upon failure, request an additional iteration to furi_assert(bus->command_callback);
choose the appropriate action by checking bus->error */ if(bus->command_callback(command, bus->command_callback_context)) {
return true; return true;
} else if(bus->command_callback) { }
return bus->command_callback(command, bus->command_callback_context);
} else {
bus->error = OneWireSlaveErrorInvalidCommand;
} }
return (bus->error == OneWireSlaveErrorResetInProgress);
} }
return false; return false;
@ -115,9 +160,6 @@ static inline bool onewire_slave_bus_start(OneWireSlave* bus) {
FURI_CRITICAL_ENTER(); FURI_CRITICAL_ENTER();
furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); 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)) 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 = const uint32_t pulse_length =
(DWT->CYCCNT - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); (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); const bool result = onewire_slave_bus_start(bus);
if(result && bus->result_callback != NULL) { if(result && bus->result_callback != NULL) {
@ -158,6 +208,7 @@ OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) {
OneWireSlave* bus = malloc(sizeof(OneWireSlave)); OneWireSlave* bus = malloc(sizeof(OneWireSlave));
bus->gpio_pin = gpio_pin; bus->gpio_pin = gpio_pin;
bus->timings = &onewire_slave_timings_normal;
bus->error = OneWireSlaveErrorNone; bus->error = OneWireSlaveErrorNone;
return bus; return bus;
@ -205,52 +256,45 @@ void onewire_slave_set_result_callback(
} }
bool onewire_slave_receive_bit(OneWireSlave* bus) { bool onewire_slave_receive_bit(OneWireSlave* bus) {
const OneWireSlaveTimings* timings = bus->timings;
// wait while bus is low // wait while bus is low
uint32_t time = ONEWIRE_TSLOT_MAX; if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) {
time = onewire_slave_wait_while_gpio_is(bus, time, false);
if(time == 0) {
bus->error = OneWireSlaveErrorResetInProgress; bus->error = OneWireSlaveErrorResetInProgress;
return false; return false;
} }
// wait while bus is high // wait while bus is high
time = ONEWIRE_TH_TIMEOUT; if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) {
time = onewire_slave_wait_while_gpio_is(bus, time, true);
if(time == 0) {
bus->error = OneWireSlaveErrorTimeout; bus->error = OneWireSlaveErrorTimeout;
return false; return false;
} }
// wait a time of zero // wait a time of zero
time = ONEWIRE_TW1L_MAX; return onewire_slave_wait_while_gpio_is(bus, timings->tw1l_max, false);
time = onewire_slave_wait_while_gpio_is(bus, time, false);
return (time > 0);
} }
bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
const OneWireSlaveTimings* timings = bus->timings;
// wait while bus is low // wait while bus is low
uint32_t time = ONEWIRE_TSLOT_MAX; if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) {
time = onewire_slave_wait_while_gpio_is(bus, time, false);
if(time == 0) {
bus->error = OneWireSlaveErrorResetInProgress; bus->error = OneWireSlaveErrorResetInProgress;
return false; return false;
} }
// wait while bus is high // wait while bus is high
time = ONEWIRE_TH_TIMEOUT; if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) {
time = onewire_slave_wait_while_gpio_is(bus, time, true);
if(time == 0) {
bus->error = OneWireSlaveErrorTimeout; bus->error = OneWireSlaveErrorTimeout;
return false; return false;
} }
// choose write time // choose write time
uint32_t time;
if(!value) { if(!value) {
furi_hal_gpio_write(bus->gpio_pin, false); furi_hal_gpio_write(bus->gpio_pin, false);
time = ONEWIRE_TRL_TMSR_MAX; time = timings->trl_tmsr_max;
} else { } else {
time = ONEWIRE_TSLOT_MIN; time = timings->tslot_min;
} }
// hold line for ZERO or ONE time // 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; 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;
}
}

View File

@ -18,68 +18,85 @@ extern "C" {
typedef struct OneWireDevice OneWireDevice; typedef struct OneWireDevice OneWireDevice;
typedef struct OneWireSlave OneWireSlave; typedef struct OneWireSlave OneWireSlave;
typedef void (*OneWireSlaveResetCallback)(void* context); typedef bool (*OneWireSlaveResetCallback)(bool is_short, void* context);
typedef void (*OneWireSlaveResultCallback)(void* context);
typedef bool (*OneWireSlaveCommandCallback)(uint8_t command, void* context); typedef bool (*OneWireSlaveCommandCallback)(uint8_t command, void* context);
typedef void (*OneWireSlaveResultCallback)(void* context);
/** /**
* Allocate onewire slave * Allocate OneWireSlave instance
* @param gpio_pin * @param [in] gpio_pin connection pin
* @return OneWireSlave* * @return pointer to OneWireSlave instance
*/ */
OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin); OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin);
/** /**
* Free onewire slave * Destroy OneWireSlave instance, free resources
* @param bus * @param [in] bus pointer to OneWireSlave instance
*/ */
void onewire_slave_free(OneWireSlave* bus); void onewire_slave_free(OneWireSlave* bus);
/** /**
* Start working with the bus * Start working with the bus
* @param bus * @param [in] bus pointer to OneWireSlave instance
*/ */
void onewire_slave_start(OneWireSlave* bus); void onewire_slave_start(OneWireSlave* bus);
/** /**
* Stop working with the bus * Stop working with the bus
* @param bus * @param [in] bus pointer to OneWireSlave instance
*/ */
void onewire_slave_stop(OneWireSlave* bus); 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); 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); bool onewire_slave_send_bit(OneWireSlave* bus, bool value);
/** /**
* Send data * Send one or more bytes of data
* @param bus * @param [in] bus pointer to OneWireSlave instance
* @param data * @param [in] data pointer to the data to send
* @param data_size * @param [in] data_size size of the data to send
* @return bool * @return true on success, false on failure
*/ */
bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size); bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size);
/** /**
* Receive data * Receive one or more bytes of data
* @param bus * @param [in] bus pointer to OneWireSlave instance
* @param data * @param [out] data pointer to the receive buffer
* @param data_size * @param [in] data_size number of bytes to receive
* @return bool * @return true on success, false on failure
*/ */
bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size); bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size);
/** /**
* Set a callback to be called on each reset * Enable overdrive mode
* @param bus * @param [in] bus pointer to OneWireSlave instance
* @param callback * @param [in] set true to turn overdrive on, false to turn it off
* @param context */
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( void onewire_slave_set_reset_callback(
OneWireSlave* bus, OneWireSlave* bus,
@ -87,10 +104,13 @@ void onewire_slave_set_reset_callback(
void* context); void* context);
/** /**
* Set a callback to be called on each command * Set a callback function to be called on each command.
* @param bus * The return value of the callback determines whether further operation
* @param callback * is possible. As a rule of thumb, return true unless a critical error happened.
* @param context *
* @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( void onewire_slave_set_command_callback(
OneWireSlave* bus, OneWireSlave* bus,
@ -99,9 +119,9 @@ void onewire_slave_set_command_callback(
/** /**
* Set a callback to report emulation success * Set a callback to report emulation success
* @param bus * @param [in] bus pointer to OneWireSlave instance
* @param result_cb * @param [in] result_cb pointer to a callback function
* @param context * @param [in] context additional parameter to be passed to the callback
*/ */
void onewire_slave_set_result_callback( void onewire_slave_set_result_callback(
OneWireSlave* bus, OneWireSlave* bus,