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 sd_card_test(void* p); | ||||||
| void application_vibro(void* p); | void application_vibro(void* p); | ||||||
| void app_gpio_test(void* p); | void app_gpio_test(void* p); | ||||||
|  | void app_ibutton(void* p); | ||||||
| 
 | 
 | ||||||
| const FlipperStartupApp FLIPPER_STARTUP[] = { | const FlipperStartupApp FLIPPER_STARTUP[] = { | ||||||
| #ifdef APP_DISPLAY | #ifdef APP_DISPLAY | ||||||
| @ -122,6 +123,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { | |||||||
|         .name = "gpio test", |         .name = "gpio test", | ||||||
|         .libs = {1, FURI_LIB{"gui_task"}}, |         .libs = {1, FURI_LIB{"gui_task"}}, | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef APP_IBUTTON | ||||||
|  |     {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}}, | ||||||
|  | #endif | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| const FlipperStartupApp FLIPPER_APPS[] = { | const FlipperStartupApp FLIPPER_APPS[] = { | ||||||
| @ -164,4 +169,8 @@ const FlipperStartupApp FLIPPER_APPS[] = { | |||||||
| #ifdef BUILD_GPIO_DEMO | #ifdef BUILD_GPIO_DEMO | ||||||
|     {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}}, |     {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}}, | ||||||
| #endif | #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