ibutton init
This commit is contained in:
		
							parent
							
								
									714d732745
								
							
						
					
					
						commit
						4eeac6579f
					
				| @ -35,6 +35,7 @@ void power_task(void* p); | ||||
| void sd_card_test(void* p); | ||||
| void application_vibro(void* p); | ||||
| void app_gpio_test(void* p); | ||||
| void app_ibutton(void* p); | ||||
| 
 | ||||
| const FlipperStartupApp FLIPPER_STARTUP[] = { | ||||
| #ifdef APP_DISPLAY | ||||
| @ -122,6 +123,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { | ||||
|         .name = "gpio test", | ||||
|         .libs = {1, FURI_LIB{"gui_task"}}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IBUTTON | ||||
|     {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}}, | ||||
| #endif | ||||
|     }; | ||||
| 
 | ||||
| const FlipperStartupApp FLIPPER_APPS[] = { | ||||
| @ -164,4 +169,8 @@ const FlipperStartupApp FLIPPER_APPS[] = { | ||||
| #ifdef BUILD_GPIO_DEMO | ||||
|     {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_IBUTTON | ||||
|     {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}}, | ||||
| #endif | ||||
| }; | ||||
							
								
								
									
										101
									
								
								applications/ibutton/ibutton.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								applications/ibutton/ibutton.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| #include "ibutton.h" | ||||
| #include "ibutton_mode_dallas_read.h" | ||||
| #include "ibutton_mode_dallas_emulate.h" | ||||
| 
 | ||||
| // start app
 | ||||
| void AppiButton::run() { | ||||
|     mode[0] = new AppiButtonModeDallasRead(this); | ||||
|     mode[1] = new AppiButtonModeDallasEmulate(this); | ||||
| 
 | ||||
|     // create pin
 | ||||
|     GpioPin red_led = led_gpio[0]; | ||||
|     GpioPin green_led = led_gpio[1]; | ||||
| 
 | ||||
|     // TODO open record
 | ||||
|     red_led_record = &red_led; | ||||
|     green_led_record = &green_led; | ||||
| 
 | ||||
|     // configure pin
 | ||||
|     gpio_init(red_led_record, GpioModeOutputOpenDrain); | ||||
|     gpio_init(green_led_record, GpioModeOutputOpenDrain); | ||||
| 
 | ||||
|     AppiButtonEvent event; | ||||
|     while(1) { | ||||
|         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100); | ||||
| 
 | ||||
|         if(event_status == osOK) { | ||||
|             if(event.type == AppiButtonEvent::EventTypeKey) { | ||||
|                 // press events
 | ||||
|                 if(event.value.input.state && event.value.input.input == InputBack) { | ||||
|                     printf("[ibutton] bye!\n"); | ||||
|                     // TODO remove all widgets create by app
 | ||||
|                     widget_enabled_set(widget, false); | ||||
|                     furiac_exit(NULL); | ||||
|                 } | ||||
| 
 | ||||
|                 if(event.value.input.state && event.value.input.input == InputLeft) { | ||||
|                     decrease_mode(); | ||||
|                 } | ||||
| 
 | ||||
|                 if(event.value.input.state && event.value.input.input == InputRight) { | ||||
|                     increase_mode(); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             event.type = AppiButtonEvent::EventTypeTick; | ||||
|         } | ||||
| 
 | ||||
|         acquire_state(); | ||||
|         mode[state.mode_index]->event(&event, &state); | ||||
|         release_state(); | ||||
| 
 | ||||
|         widget_update(widget); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| // render app
 | ||||
| void AppiButton::render(CanvasApi* canvas) { | ||||
|     canvas->set_color(canvas, ColorBlack); | ||||
|     canvas->set_font(canvas, FontPrimary); | ||||
|     canvas->draw_str(canvas, 2, 12, "iButton"); | ||||
| 
 | ||||
|     mode[state.mode_index]->render(canvas, &state); | ||||
| } | ||||
| 
 | ||||
| void AppiButton::blink_red() { | ||||
|     gpio_write(red_led_record, 0); | ||||
|     delay(10); | ||||
|     gpio_write(red_led_record, 1); | ||||
| } | ||||
| 
 | ||||
| void AppiButton::blink_green() { | ||||
|     gpio_write(green_led_record, 0); | ||||
|     delay(10); | ||||
|     gpio_write(green_led_record, 1); | ||||
| } | ||||
| 
 | ||||
| void AppiButton::increase_mode() { | ||||
|     acquire_state(); | ||||
|     if(state.mode_index < (modes_count - 1)) { | ||||
|         mode[state.mode_index]->release(); | ||||
|         state.mode_index++; | ||||
|         mode[state.mode_index]->acquire(); | ||||
|     } | ||||
|     release_state(); | ||||
| } | ||||
| 
 | ||||
| void AppiButton::decrease_mode() { | ||||
|     acquire_state(); | ||||
|     if(state.mode_index > 0) { | ||||
|         mode[state.mode_index]->release(); | ||||
|         state.mode_index--; | ||||
|         mode[state.mode_index]->acquire(); | ||||
|     } | ||||
|     release_state(); | ||||
| } | ||||
| 
 | ||||
| // app enter function
 | ||||
| extern "C" void app_ibutton(void* p) { | ||||
|     AppiButton* app = new AppiButton(); | ||||
|     app->run(); | ||||
| } | ||||
							
								
								
									
										54
									
								
								applications/ibutton/ibutton.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/ibutton/ibutton.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
| #include "app-template.h" | ||||
| #include "ibutton_mode_template.h" | ||||
| 
 | ||||
| // event enumeration type
 | ||||
| typedef uint8_t event_t; | ||||
| 
 | ||||
| class AppiButtonState { | ||||
| public: | ||||
|     // state data
 | ||||
|     uint8_t dallas_address[8] = {0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB}; | ||||
|     uint8_t mode_index; | ||||
| 
 | ||||
|     // state initializer
 | ||||
|     AppiButtonState() { | ||||
|         mode_index = 0; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // events class
 | ||||
| class AppiButtonEvent { | ||||
| public: | ||||
|     // events enum
 | ||||
|     static const event_t EventTypeTick = 0; | ||||
|     static const event_t EventTypeKey = 1; | ||||
| 
 | ||||
|     // payload
 | ||||
|     union { | ||||
|         InputEvent input; | ||||
|     } value; | ||||
| 
 | ||||
|     // event type
 | ||||
|     event_t type; | ||||
| }; | ||||
| 
 | ||||
| // our app derived from base AppTemplate class
 | ||||
| // with template variables <state, events>
 | ||||
| class AppiButton : public AppTemplate<AppiButtonState, AppiButtonEvent> { | ||||
| public: | ||||
|     GpioPin* red_led_record; | ||||
|     GpioPin* green_led_record; | ||||
| 
 | ||||
|     static const uint8_t modes_count = 2; | ||||
|     AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count]; | ||||
| 
 | ||||
|     void run(); | ||||
|     void render(CanvasApi* canvas); | ||||
| 
 | ||||
|     void blink_red(); | ||||
|     void blink_green(); | ||||
| 
 | ||||
|     void increase_mode(); | ||||
|     void decrease_mode(); | ||||
| }; | ||||
							
								
								
									
										64
									
								
								applications/ibutton/ibutton_mode_dallas_emulate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								applications/ibutton/ibutton_mode_dallas_emulate.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| #pragma once | ||||
| #include "ibutton.h" | ||||
| #include "one_wire_slave_gpio.h" | ||||
| 
 | ||||
| class AppiButtonModeDallasEmulate : public AppTemplateMode<AppiButtonState, AppiButtonEvent> { | ||||
| public: | ||||
|     const char* name = "dallas emulate"; | ||||
|     AppiButton* app; | ||||
|     OneWireGpioSlave* onewire_slave; | ||||
| 
 | ||||
|     void event(AppiButtonEvent* event, AppiButtonState* state); | ||||
|     void render(CanvasApi* canvas, AppiButtonState* state); | ||||
|     void acquire(); | ||||
|     void release(); | ||||
| 
 | ||||
|     AppiButtonModeDallasEmulate(AppiButton* parent_app) { | ||||
|         app = parent_app; | ||||
| 
 | ||||
|         // TODO open record
 | ||||
|         GpioPin one_wire_pin = {iBTN_GPIO_Port, iBTN_Pin}; | ||||
|         GpioPin* one_wire_pin_record = &one_wire_pin; | ||||
|         onewire_slave = new OneWireGpioSlave(one_wire_pin_record); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* state) { | ||||
|     if(event->type == AppiButtonEvent::EventTypeTick) { | ||||
|         acquire(); | ||||
|         if(onewire_slave->emulate(state->dallas_address, 8)) { | ||||
|             app->blink_green(); | ||||
|         } else { | ||||
|              | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasEmulate::render(CanvasApi* canvas, AppiButtonState* state) { | ||||
|     canvas->set_font(canvas, FontSecondary); | ||||
|     canvas->draw_str(canvas, 2, 25, "< dallas emulate"); | ||||
|     canvas->draw_str(canvas, 2, 37, "give me domophone"); | ||||
|     { | ||||
|         char buf[24]; | ||||
|         sprintf( | ||||
|             buf, | ||||
|             "%x:%x:%x:%x:%x:%x:%x:%x", | ||||
|             state->dallas_address[0], | ||||
|             state->dallas_address[1], | ||||
|             state->dallas_address[2], | ||||
|             state->dallas_address[3], | ||||
|             state->dallas_address[4], | ||||
|             state->dallas_address[5], | ||||
|             state->dallas_address[6], | ||||
|             state->dallas_address[7]); | ||||
|         canvas->draw_str(canvas, 2, 50, buf); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasEmulate::acquire() { | ||||
|     onewire_slave->start(); | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasEmulate::release() { | ||||
|     onewire_slave->stop(); | ||||
| } | ||||
							
								
								
									
										119
									
								
								applications/ibutton/ibutton_mode_dallas_read.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								applications/ibutton/ibutton_mode_dallas_read.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| #pragma once | ||||
| #include "ibutton.h" | ||||
| #include "one_wire_gpio.h" | ||||
| 
 | ||||
| class AppiButtonModeDallasRead : public AppTemplateMode<AppiButtonState, AppiButtonEvent> { | ||||
| public: | ||||
|     const char* name = "dallas read"; | ||||
|     AppiButton* app; | ||||
|     OneWireGpio* onewire; | ||||
| 
 | ||||
|     void event(AppiButtonEvent* event, AppiButtonState* state); | ||||
|     void render(CanvasApi* canvas, AppiButtonState* state); | ||||
|     void acquire(); | ||||
|     void release(); | ||||
| 
 | ||||
|     AppiButtonModeDallasRead(AppiButton* parent_app) { | ||||
|         app = parent_app; | ||||
| 
 | ||||
|         // TODO open record
 | ||||
|         GpioPin one_wire_pin = {iBTN_GPIO_Port, iBTN_Pin}; | ||||
|         GpioPin* one_wire_pin_record = &one_wire_pin; | ||||
|         onewire = new OneWireGpio(one_wire_pin_record); | ||||
|     }; | ||||
| 
 | ||||
|     uint8_t crc_8(uint8_t* buffer, uint8_t count); | ||||
| }; | ||||
| 
 | ||||
| void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* state) { | ||||
|     if(event->type == AppiButtonEvent::EventTypeTick) { | ||||
|         bool result = 0; | ||||
|         uint8_t address[8]; | ||||
| 
 | ||||
|         osKernelLock(); | ||||
|         result = onewire->reset(); | ||||
|         osKernelUnlock(); | ||||
| 
 | ||||
|         if(result) { | ||||
|             printf("device on line\n"); | ||||
| 
 | ||||
|             delay(50); | ||||
|             osKernelLock(); | ||||
|             onewire->write(0x33); | ||||
|             onewire->read_bytes(address, 8); | ||||
|             osKernelUnlock(); | ||||
| 
 | ||||
|             printf("address: %x", address[0]); | ||||
|             for(uint8_t i = 1; i < 8; i++) { | ||||
|                 printf(":%x", address[i]); | ||||
|             } | ||||
|             printf("\n"); | ||||
| 
 | ||||
|             printf("crc8: %x\n", crc_8(address, 7)); | ||||
| 
 | ||||
|             if(crc_8(address, 8) == 0) { | ||||
|                 printf("CRC valid\n"); | ||||
|                 memcpy(app->state.dallas_address, address, 8); | ||||
|                 app->blink_green(); | ||||
|             } else { | ||||
|                 printf("CRC invalid\n"); | ||||
|             } | ||||
|         } else { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasRead::render(CanvasApi* canvas, AppiButtonState* state) { | ||||
|     canvas->set_font(canvas, FontSecondary); | ||||
|     canvas->draw_str(canvas, 2, 25, "dallas read >"); | ||||
|     canvas->draw_str(canvas, 2, 37, "touch me, iButton"); | ||||
|     { | ||||
|         char buf[24]; | ||||
|         sprintf( | ||||
|             buf, | ||||
|             "%x:%x:%x:%x:%x:%x:%x:%x", | ||||
|             state->dallas_address[0], | ||||
|             state->dallas_address[1], | ||||
|             state->dallas_address[2], | ||||
|             state->dallas_address[3], | ||||
|             state->dallas_address[4], | ||||
|             state->dallas_address[5], | ||||
|             state->dallas_address[6], | ||||
|             state->dallas_address[7]); | ||||
|         canvas->draw_str(canvas, 2, 50, buf); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t AppiButtonModeDallasRead::crc_8(uint8_t* buffer, uint8_t count) { | ||||
|     const uint8_t maxim_crc8_table[256] = { | ||||
|         0,   94,  188, 226, 97,  63,  221, 131, 194, 156, 126, 32,  163, 253, 31,  65,  157, 195, | ||||
|         33,  127, 252, 162, 64,  30,  95,  1,   227, 189, 62,  96,  130, 220, 35,  125, 159, 193, | ||||
|         66,  28,  254, 160, 225, 191, 93,  3,   128, 222, 60,  98,  190, 224, 2,   92,  223, 129, | ||||
|         99,  61,  124, 34,  192, 158, 29,  67,  161, 255, 70,  24,  250, 164, 39,  121, 155, 197, | ||||
|         132, 218, 56,  102, 229, 187, 89,  7,   219, 133, 103, 57,  186, 228, 6,   88,  25,  71, | ||||
|         165, 251, 120, 38,  196, 154, 101, 59,  217, 135, 4,   90,  184, 230, 167, 249, 27,  69, | ||||
|         198, 152, 122, 36,  248, 166, 68,  26,  153, 199, 37,  123, 58,  100, 134, 216, 91,  5, | ||||
|         231, 185, 140, 210, 48,  110, 237, 179, 81,  15,  78,  16,  242, 172, 47,  113, 147, 205, | ||||
|         17,  79,  173, 243, 112, 46,  204, 146, 211, 141, 111, 49,  178, 236, 14,  80,  175, 241, | ||||
|         19,  77,  206, 144, 114, 44,  109, 51,  209, 143, 12,  82,  176, 238, 50,  108, 142, 208, | ||||
|         83,  13,  239, 177, 240, 174, 76,  18,  145, 207, 45,  115, 202, 148, 118, 40,  171, 245, | ||||
|         23,  73,  8,   86,  180, 234, 105, 55,  213, 139, 87,  9,   235, 181, 54,  104, 138, 212, | ||||
|         149, 203, 41,  119, 244, 170, 72,  22,  233, 183, 85,  11,  136, 214, 52,  106, 43,  117, | ||||
|         151, 201, 74,  20,  246, 168, 116, 42,  200, 150, 21,  75,  169, 247, 182, 232, 10,  84, | ||||
|         215, 137, 107, 53}; | ||||
| 
 | ||||
|     uint8_t crc = 0; | ||||
| 
 | ||||
|     while(count--) { | ||||
|         crc = maxim_crc8_table[(crc ^ *buffer++)]; | ||||
|     } | ||||
|     return crc; | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasRead::acquire() { | ||||
|     onewire->start(); | ||||
| } | ||||
| 
 | ||||
| void AppiButtonModeDallasRead::release() { | ||||
|     onewire->stop(); | ||||
| } | ||||
							
								
								
									
										11
									
								
								applications/ibutton/ibutton_mode_template.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/ibutton/ibutton_mode_template.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| // template for modes
 | ||||
| template <class TState, class TEvents> class AppTemplateMode { | ||||
| public: | ||||
|     const char* name; | ||||
|     virtual void event(TEvents* event, TState* state) = 0; | ||||
|     virtual void render(CanvasApi* canvas, TState* state) = 0; | ||||
|     virtual void acquire() = 0; | ||||
|     virtual void release() = 0; | ||||
| }; | ||||
							
								
								
									
										130
									
								
								applications/ibutton/one_wire_gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								applications/ibutton/one_wire_gpio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include "one_wire_timings.h" | ||||
| 
 | ||||
| class OneWireGpio { | ||||
| private: | ||||
|     GpioPin* gpio; | ||||
| 
 | ||||
| public: | ||||
|     OneWireGpio(GpioPin* one_wire_gpio); | ||||
|     ~OneWireGpio(); | ||||
|     bool reset(void); | ||||
|     bool read_bit(void); | ||||
|     uint8_t read(void); | ||||
|     void read_bytes(uint8_t* buf, uint16_t count); | ||||
|     void write_bit(bool value); | ||||
|     void write(uint8_t value); | ||||
|     void start(void); | ||||
|     void stop(void); | ||||
| }; | ||||
| 
 | ||||
| OneWireGpio::OneWireGpio(GpioPin* one_wire_gpio) { | ||||
|     gpio = one_wire_gpio; | ||||
| } | ||||
| 
 | ||||
| OneWireGpio::~OneWireGpio() { | ||||
|     stop(); | ||||
| } | ||||
| 
 | ||||
| void OneWireGpio::start(void) { | ||||
|     gpio_init(gpio, GpioModeOutputOpenDrain); | ||||
| } | ||||
| 
 | ||||
| void OneWireGpio::stop(void) { | ||||
|     gpio_init(gpio, GpioModeAnalog); | ||||
| } | ||||
| 
 | ||||
| bool OneWireGpio::reset(void) { | ||||
|     uint8_t r; | ||||
|     uint8_t retries = 125; | ||||
| 
 | ||||
|     // wait until the gpio is high
 | ||||
|     gpio_write(gpio, true); | ||||
|     do { | ||||
|         if(--retries == 0) return 0; | ||||
|         delay_us(2); | ||||
|     } while(!gpio_read(gpio)); | ||||
| 
 | ||||
|     // pre delay
 | ||||
|     delay_us(OneWireTiming::RESET_DELAY_PRE); | ||||
| 
 | ||||
|     // drive low
 | ||||
|     gpio_write(gpio, false); | ||||
|     delay_us(OneWireTiming::RESET_DRIVE); | ||||
| 
 | ||||
|     // release
 | ||||
|     gpio_write(gpio, true); | ||||
|     delay_us(OneWireTiming::RESET_RELEASE); | ||||
| 
 | ||||
|     // read and post delay
 | ||||
|     r = !gpio_read(gpio); | ||||
|     delay_us(OneWireTiming::RESET_DELAY_POST); | ||||
| 
 | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| bool OneWireGpio::read_bit(void) { | ||||
|     bool result; | ||||
| 
 | ||||
|     // drive low
 | ||||
|     gpio_write(gpio, false); | ||||
|     delay_us(OneWireTiming::READ_DRIVE); | ||||
| 
 | ||||
|     // release
 | ||||
|     gpio_write(gpio, true); | ||||
|     delay_us(OneWireTiming::READ_RELEASE); | ||||
| 
 | ||||
|     // read and post delay
 | ||||
|     result = gpio_read(gpio); | ||||
|     delay_us(OneWireTiming::READ_DELAY_POST); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void OneWireGpio::write_bit(bool value) { | ||||
|     if(value) { | ||||
|         // drive low
 | ||||
|         gpio_write(gpio, false); | ||||
|         delay_us(OneWireTiming::WRITE_1_DRIVE); | ||||
| 
 | ||||
|         // release
 | ||||
|         gpio_write(gpio, true); | ||||
|         delay_us(OneWireTiming::WRITE_1_RELEASE); | ||||
|     } else { | ||||
|         // drive low
 | ||||
|         gpio_write(gpio, false); | ||||
|         delay_us(OneWireTiming::WRITE_0_DRIVE); | ||||
| 
 | ||||
|         // release
 | ||||
|         gpio_write(gpio, true); | ||||
|         delay_us(OneWireTiming::WRITE_0_RELEASE); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t OneWireGpio::read(void) { | ||||
|     uint8_t result = 0; | ||||
| 
 | ||||
|     for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { | ||||
|         if(read_bit()) { | ||||
|             result |= bitMask; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void OneWireGpio::read_bytes(uint8_t* buffer, uint16_t count) { | ||||
|     for(uint16_t i = 0; i < count; i++) { | ||||
|         buffer[i] = read(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OneWireGpio::write(uint8_t value) { | ||||
|     uint8_t bitMask; | ||||
| 
 | ||||
|     for(bitMask = 0x01; bitMask; bitMask <<= 1) { | ||||
|         write_bit((bitMask & value) ? 1 : 0); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										179
									
								
								applications/ibutton/one_wire_slave_gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								applications/ibutton/one_wire_slave_gpio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,179 @@ | ||||
| #pragma once | ||||
| #include "flipper.h" | ||||
| #include "flipper_v2.h" | ||||
| #include "one_wire_timings.h" | ||||
| 
 | ||||
| class OneWireGpioSlave { | ||||
| private: | ||||
|     GpioPin* gpio; | ||||
| 
 | ||||
| public: | ||||
|     OneWireGpioSlave(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(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); | ||||
| } | ||||
							
								
								
									
										54
									
								
								applications/ibutton/one_wire_timings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/ibutton/one_wire_timings.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| class __OneWireTiming { | ||||
| public: | ||||
|     constexpr static const uint16_t TIMING_A = 6; | ||||
|     constexpr static const uint16_t TIMING_B = 64; | ||||
|     constexpr static const uint16_t TIMING_C = 60; | ||||
|     constexpr static const uint16_t TIMING_D = 10; | ||||
|     constexpr static const uint16_t TIMING_E = 9; | ||||
|     constexpr static const uint16_t TIMING_F = 55; | ||||
|     constexpr static const uint16_t TIMING_G = 0; | ||||
|     constexpr static const uint16_t TIMING_H = 480; | ||||
|     constexpr static const uint16_t TIMING_I = 70; | ||||
|     constexpr static const uint16_t TIMING_J = 410; | ||||
| }; | ||||
| 
 | ||||
| class OneWireTiming { | ||||
| public: | ||||
|     constexpr static const uint16_t WRITE_1_DRIVE = __OneWireTiming::TIMING_A; | ||||
|     constexpr static const uint16_t WRITE_1_RELEASE = __OneWireTiming::TIMING_B; | ||||
| 
 | ||||
|     constexpr static const uint16_t WRITE_0_DRIVE = __OneWireTiming::TIMING_C; | ||||
|     constexpr static const uint16_t WRITE_0_RELEASE = __OneWireTiming::TIMING_D; | ||||
| 
 | ||||
|     constexpr static const uint16_t READ_DRIVE = __OneWireTiming::TIMING_A; | ||||
|     constexpr static const uint16_t READ_RELEASE = __OneWireTiming::TIMING_E; | ||||
|     constexpr static const uint16_t READ_DELAY_POST = __OneWireTiming::TIMING_F; | ||||
| 
 | ||||
|     constexpr static const uint16_t RESET_DELAY_PRE = __OneWireTiming::TIMING_G; | ||||
|     constexpr static const uint16_t RESET_DRIVE = __OneWireTiming::TIMING_H; | ||||
|     constexpr static const uint16_t RESET_RELEASE = __OneWireTiming::TIMING_I; | ||||
|     constexpr static const uint16_t RESET_DELAY_POST = __OneWireTiming::TIMING_J; | ||||
| }; | ||||
| 
 | ||||
| typedef uint32_t OneWiteTimeType; | ||||
| 
 | ||||
| class OneWireEmulateTiming { | ||||
| public: | ||||
|     constexpr static const OneWiteTimeType RESET_TIMEOUT = {5000}; | ||||
|     constexpr static const OneWiteTimeType RESET_MIN[2] = {430, 48}; | ||||
|     constexpr static const OneWiteTimeType RESET_MAX[2] = {960, 80}; | ||||
| 
 | ||||
|     constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = {20}; | ||||
|     constexpr static const OneWiteTimeType PRESENCE_MIN[2] = {160, 8}; | ||||
|     constexpr static const OneWiteTimeType PRESENCE_MAX[2] = {480, 32}; | ||||
| 
 | ||||
|     constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = {15000}; | ||||
|     constexpr static const OneWiteTimeType SLOT_MAX[2] = {135, 30}; | ||||
| 
 | ||||
|     constexpr static const OneWiteTimeType READ_MIN[2] = {20, 4}; | ||||
|     constexpr static const OneWiteTimeType READ_MAX[2] = {60, 10}; | ||||
|     constexpr static const OneWiteTimeType WRITE_ZERO[2] = {30, 8}; | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrZlo13
						DrZlo13