flipperzero-firmware/applications/ibutton/one_wire_slave_gpio.h
DrZlo13 a96f23af9b
fix multithread logic in template app, update gpio HAL (#250)
* fix multithread logic
* more buffer for dallas id string
* update apps to use new logic
* delay_us small speedup
* add consant qualifier to gpio records and some core api
* fix some apps to use simpler method of getting gpio record
* fix ibutton app, stupid stack problem
2020-11-19 15:25:32 +03:00

177 lines
4.7 KiB
C++

#pragma once
#include "flipper.h"
#include "flipper_v2.h"
#include "one_wire_timings.h"
class OneWireGpioSlave {
private:
const GpioPin* gpio;
public:
OneWireGpioSlave(const GpioPin* one_wire_gpio);
~OneWireGpioSlave();
void start(void);
void stop(void);
bool emulate(uint8_t* buffer, uint8_t length);
bool check_reset(void);
bool show_presence(void);
bool receive_and_process_cmd(void);
bool receive(uint8_t* data, const uint8_t data_length);
bool receiveBit(void);
bool overdrive_mode = false;
OneWiteTimeType wait_while_gpio(volatile OneWiteTimeType retries, const bool pin_value);
};
OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) {
gpio = one_wire_gpio;
}
OneWireGpioSlave::~OneWireGpioSlave() {
stop();
}
void OneWireGpioSlave::start(void) {
gpio_init(gpio, GpioModeOutputOpenDrain);
}
void OneWireGpioSlave::stop(void) {
gpio_init(gpio, GpioModeAnalog);
}
bool OneWireGpioSlave::emulate(uint8_t* buffer, uint8_t length) {
if(!check_reset()) {
printf("reset error\n");
return false;
}
if(!show_presence()) {
printf("presence error\n");
return false;
}
if(!receive_and_process_cmd()) {
printf("receive_and_process_cmd error\n");
return false;
}
printf("ok\n");
return true;
}
OneWiteTimeType OneWireGpioSlave::wait_while_gpio(OneWiteTimeType time, const bool pin_value) {
uint32_t start = DWT->CYCCNT;
uint32_t time_ticks = time * (SystemCoreClock / 1000000.0f);
while(((DWT->CYCCNT - start) < time_ticks)) {
if(gpio_read(gpio) != pin_value) {
uint32_t time = (DWT->CYCCNT - start);
time /= (SystemCoreClock / 1000000.0f);
return time;
}
}
return 0;
}
bool OneWireGpioSlave::check_reset(void) {
while(gpio_read(gpio) == true) {
}
/*if(wait_while_gpio(OneWireEmulateTiming::RESET_TIMEOUT * 20, true) == 0) {
printf("RESET_TIMEOUT\n");
return false;
}*/
const OneWiteTimeType time_remaining =
wait_while_gpio(OneWireEmulateTiming::RESET_MAX[0], false);
if(time_remaining == 0) {
return false;
}
if(overdrive_mode && ((OneWireEmulateTiming::RESET_MAX[0] -
OneWireEmulateTiming::RESET_MIN[0]) <= time_remaining)) {
// normal reset detected
overdrive_mode = false;
};
bool result = (time_remaining <= OneWireEmulateTiming::RESET_MAX[0]) &&
time_remaining >= OneWireEmulateTiming::RESET_MIN[overdrive_mode];
return result;
}
bool OneWireGpioSlave::show_presence(void) {
wait_while_gpio(OneWireEmulateTiming::PRESENCE_TIMEOUT, true);
gpio_write(gpio, false);
delay_us(OneWireEmulateTiming::PRESENCE_MIN[overdrive_mode]);
gpio_write(gpio, true);
/*OneWiteTimeType wait_time = OneWireEmulateTiming::PRESENCE_MAX[overdrive_mode] -
OneWireEmulateTiming::PRESENCE_MIN[overdrive_mode];
if(wait_while_gpio(wait_time, false) == 0) {
return false;
}*/
return true;
}
bool OneWireGpioSlave::receive_and_process_cmd(void) {
uint8_t cmd;
receive(&cmd, 1);
printf("cmd %x\n", cmd);
return false;
}
bool OneWireGpioSlave::receiveBit(void) {
// wait while bus is HIGH
OneWiteTimeType time = OneWireEmulateTiming::SLOT_MAX[overdrive_mode];
time = wait_while_gpio(time, true);
if(time == 0) {
printf("RESET_IN_PROGRESS\n");
return false;
}
/*while ((DIRECT_READ(pin_baseReg, pin_bitMask) == 0) && (--retries != 0));
if (retries == 0)
{
_error = Error::RESET_IN_PROGRESS;
return false;
}*/
// wait while bus is LOW
time = OneWireEmulateTiming::MSG_HIGH_TIMEOUT;
time = wait_while_gpio(time, false);
if(time == 0) {
printf("TIMEOUT_HIGH\n");
return false;
}
/*while ((DIRECT_READ(pin_baseReg, pin_bitMask) != 0) && (--retries != 0));
if (retries == 0)
{
_error = Error::AWAIT_TIMESLOT_TIMEOUT_HIGH;
return false;
}*/
// wait a specific time to do a read (data is valid by then), // first difference to inner-loop of write()
time = OneWireEmulateTiming::READ_MIN[overdrive_mode];
time = wait_while_gpio(time, true);
//while ((DIRECT_READ(pin_baseReg, pin_bitMask) == 0) && (--retries != 0));
return (time > 0);
}
bool OneWireGpioSlave::receive(uint8_t* data, const uint8_t data_length) {
uint8_t bytes_received = 0;
for(; bytes_received < data_length; ++bytes_received) {
uint8_t value = 0;
for(uint8_t bitMask = 0x01; bitMask != 0; bitMask <<= 1) {
if(receiveBit()) value |= bitMask;
}
data[bytes_received] = value;
}
return (bytes_received != data_length);
}