aboutsummaryrefslogtreecommitdiff
path: root/lib/onewire_slave.c
blob: bf5ab0d4d91fee84dbe033c77a1d5669a4a440d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/* This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
/** library for 1-wire protocol as master (code)
 *  @file onewire_slave.c
 *  @author King Kévin <kingkevin@cuvoodoo.info>
 *  @date 2017
 *  @note peripherals used: GPIO and timer @ref onewire_slave_timer, GPIO @ref onewire_slave_gpio
 *  @note overdrive mode is not supported
 *  @implements 1-Wire protocol description from Book of iButton Standards
 */

/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean type
#include <stddef.h> // NULL definition

/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/timer.h> // timer library
#include <libopencm3/stm32/exti.h> // external interrupt library

/* own libraries */
#include "global.h" // help macros
#include "onewire_slave.h" // own definitions

/** @defgroup onewire_slave_timer timer used to measure 1-wire signal timing
 *  @{
 */
#define ONEWIRE_SLAVE_TIMER 2 /**< timer ID */
/** @} */

/** @defgroup onewire_slave_gpio GPIO used for 1-wire signal
 *  @warning ensure no same pin number on other parts are used for external interrupts
 *  @note external pull-up resistor on pin is required (< 5 kOhm), generally provided by the master
 *  @{
 */
#define ONEWIRE_SLAVE_PORT A /**< GPIO port */
#define ONEWIRE_SLAVE_PIN 4 /**< GPIO pin */
/** @} */

/** state of 1-Wire communication */
static volatile enum {
	ONEWIRE_STATE_IDLE, /**< no current communication */
	ONEWIRE_STATE_RESET, /**< reset pulse has been detected */
	ONEWIRE_STATE_WAIT_PRESENCE, /**< waiting before sending the presence pulse */
	ONEWIRE_STATE_PULSE_PRESENCE, /**< sending the presence pulse */
	ONEWIRE_STATE_ROM_COMMAND, /**< slave is reading ROM command bits */
	ONEWIRE_STATE_ROM_READ, /**< slave is sending ROM code in response to ROM command READ ROM */
	ONEWIRE_STATE_ROM_MATCH, /**< master is sending ROM code to select slave */
	ONEWIRE_STATE_ROM_SEARCH_TRUE, /**< master is searching ROM code, slave will send first bit (not negated) */
	ONEWIRE_STATE_ROM_SEARCH_FALSE, /**< master is searching ROM code, slave will send first bit (not negated) */
	ONEWIRE_STATE_ROM_SEARCH_SELECT, /**< master is searching ROM code, slave will read selected bit */
	ONEWIRE_STATE_FUNCTION_COMMAND, /**< slave is reading function command bits */
	ONEWIRE_STATE_FUNCTION_DATA, /**< waiting for user to provide data to transfer */
	ONEWIRE_STATE_FUNCTION_READ, /**< slave is reading bits */
	ONEWIRE_STATE_FUNCTION_WRITE, /**< slave is writing bits */
	ONEWIRE_MAX /** to count the number of possible states */
} onewire_slave_state = ONEWIRE_STATE_IDLE;

static uint8_t onewire_slave_rom_code[8] = {0}; /**< slave ROM code */

volatile bool onewire_slave_function_code_received = false;
volatile uint8_t onewire_slave_function_code = 0;
volatile bool onewire_slave_transfer_complete = false;

static volatile uint8_t bits_buffer = 0; /**< buffer for the incoming bits (up to one byte) */
static volatile uint32_t bits_bit = 0; /**< number of incoming bits */
static volatile uint8_t* onewire_slave_transfer_data = NULL; /**< data to transfer (read or write) */
static volatile uint32_t onewire_slave_transfer_bits = 0; /**< number of bits to transfer */

/** compute CRC for 1-Wire
 *  @note this CRC-8 uses normal polynomial 0x31, reverse polynomial 0x8C, start value 0x00
 *  @param[in] data bytes on which to calculate CRC checksum on
 *  @param[in] length number of bytes in data
 *  @return computed CRC checksum
 */
static uint8_t onewire_slave_crc(uint8_t* data, uint32_t length)
{
	if (NULL==data || 0==length) { // check input
		return 0; // wrong input
	}
	
	uint8_t crc = 0x00; // initial value
	for (uint8_t i=0; i<length; i++) { // go through every byte
		crc ^= data[i]; // XOR byte
		for (uint8_t b=0; b<8; b++) { // go through every bit
			if (crc&0x01) { // least significant bit is set (we are using the reverse way)
				crc = (crc>>1)^0x8C; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
			} else {
				crc >>= 1; // just shift right (for the next bit)
			}
		}
	}
	return crc;
}

void onewire_slave_setup(uint8_t family, uint64_t serial)
{
	// save ROM code (LSB first)
	onewire_slave_rom_code[0] = family;
	onewire_slave_rom_code[1] = serial >> 40;
	onewire_slave_rom_code[2] = serial >> 32;
	onewire_slave_rom_code[3] = serial >> 24;
	onewire_slave_rom_code[4] = serial >> 16;
	onewire_slave_rom_code[5] = serial >> 8;
	onewire_slave_rom_code[6] = serial >> 0;
	onewire_slave_rom_code[7] = onewire_slave_crc(onewire_slave_rom_code, 7); // calculate CRC
	
	// setup timer to generate/measure signal timing
	rcc_periph_clock_enable(RCC_TIM(ONEWIRE_SLAVE_TIMER)); // enable clock for timer peripheral
	timer_reset(TIM(ONEWIRE_SLAVE_TIMER)); // reset timer state
	timer_set_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
	timer_set_prescaler(TIM(ONEWIRE_SLAVE_TIMER), 1-1); // don't use prescale since this 16 bits timer allows to wait > 480 us used for the reset pulse ( 1/(72E6/1/(2**16))=910us )

	// use comparator to time signal (without using the output), starting at slot start
	timer_set_period(TIM(ONEWIRE_SLAVE_TIMER), 480*(rcc_ahb_frequency/1000000)-1-1300); // minimum time needed for a reset pulse (480 < Trst), plus hand tuning
	timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, TIM_OCM_FROZEN);
	timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, 16*(rcc_ahb_frequency/1000000)-1); // time to wait before sending the presence pulse, after the rising edge of the reset pulse (15 < Tpdh < 60)
	timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, TIM_OCM_FROZEN);
	timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, 45*(rcc_ahb_frequency/1000000)-1-350); // time to sample the bit after being set (1 < Tlow1 < 15, 60 < Tslot < 120), or stop sending the bit use compare function to detect slave presence (15 = Trdv + 0 < Trelease < 45), plus hand tuning
	timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC3, 90*(rcc_ahb_frequency/1000000)-1); // time to stop the presence pulse (60 < Tpdl < 120)
	timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all interrupt flags
	timer_update_on_overflow(TIM(ONEWIRE_SLAVE_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
	timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
	nvic_enable_irq(NVIC_TIM_IRQ(ONEWIRE_SLAVE_TIMER)); // catch interrupt in service routine

	onewire_slave_function_code_received = false; // reset state
	onewire_slave_state = ONEWIRE_STATE_IDLE; // reset state
	onewire_slave_transfer_complete = false; // reset state

	// setup GPIO with external interrupt
	rcc_periph_clock_enable(RCC_GPIO(ONEWIRE_SLAVE_PORT)); // enable clock for GPIO peripheral
	gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // idle is high (using pull-up resistor)
	gpio_set_mode(GPIO(ONEWIRE_SLAVE_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_SLAVE_PIN)); // control output using open drain (this mode also allows to read the input signal)
	rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
	exti_select_source(EXTI(ONEWIRE_SLAVE_PIN), GPIO(ONEWIRE_SLAVE_PORT)); // mask external interrupt of this pin only for this port
	exti_set_trigger(EXTI(ONEWIRE_SLAVE_PIN), EXTI_TRIGGER_BOTH); // trigger on signal change
	exti_enable_request(EXTI(ONEWIRE_SLAVE_PIN)); // enable external interrupt
	nvic_enable_irq(NVIC_EXTI_IRQ(ONEWIRE_SLAVE_PIN)); // enable interrupt
}

bool onewire_slave_function_read(uint8_t* data, size_t size)
{
	if (NULL==data || 0==size) { // verify input
		return false;
	}
	if (UINT32_MAX/8<size) { // too many bits to transfer
		return false;
	}
	if (onewire_slave_state!=ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
		return false;
	}
	onewire_slave_transfer_data = data; // save buffer to write to
	onewire_slave_transfer_bits = size*8; // number of bits to read
	onewire_slave_transfer_complete = false; // reset state
	bits_bit = 0; // reset number of bits read
	onewire_slave_state = ONEWIRE_STATE_FUNCTION_READ; // read data
	return true;
}

bool onewire_slave_function_write(const uint8_t* data, size_t size)
{
	if (NULL==data || 0==size) { // verify input
		return false;
	}
	if (onewire_slave_state!=ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
		return false;
	}
	if (UINT32_MAX/8<size) { // too many bits to transfer
		return false;
	}
	onewire_slave_transfer_data = (uint8_t*)data; // save buffer to read from
	onewire_slave_transfer_bits = size*8; // number of bits to write
	onewire_slave_transfer_complete = false; // reset state
	bits_bit = 0; // reset number of bits written
	bits_buffer = onewire_slave_transfer_data[0]; // prepare byte to write
	onewire_slave_state = ONEWIRE_STATE_FUNCTION_WRITE; // write data
	return true;
}

/** interrupt service routine called when 1-Wire signal changes */
void EXTI_ISR(ONEWIRE_SLAVE_PIN)(void)
{
	exti_reset_request(EXTI(ONEWIRE_SLAVE_PIN)); // reset interrupt
	if (gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // it's a rising edge
		switch (onewire_slave_state) {
			 case ONEWIRE_STATE_RESET: // reset pulse has ended
				timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
				timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
				timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
				timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE); // enable compare interrupt for presence pulse
				timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to generate timing
				onewire_slave_state = ONEWIRE_STATE_WAIT_PRESENCE; // set new stated
				break;
			case ONEWIRE_STATE_PULSE_PRESENCE: // we stopped sending the presence pulse
				onewire_slave_state = ONEWIRE_STATE_ROM_COMMAND; // we now expect a ROM command
				bits_bit = 0; // reset buffer bit count
				break; // no need to stop the time, the reset will be checked correctly
			default: // rising edge is not important is the other cases
				break; // nothing to do
		}
	} else { // it's a falling edge, the beginning of a new signal
		timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
		timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
		timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
		switch (onewire_slave_state) {
			case ONEWIRE_STATE_PULSE_PRESENCE: // we started sending the presence pulse
				timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC3IE); // enable timer for end of pulse
				break;
			case ONEWIRE_STATE_ROM_COMMAND: // read ROM command bits
			case ONEWIRE_STATE_ROM_MATCH: // read ROM code bits
			case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command bits
			case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
			case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
				timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
				break;
			case ONEWIRE_STATE_ROM_READ: // send ROM code bit
			case ONEWIRE_STATE_ROM_SEARCH_TRUE: // send ROM code bit while searching ROM, not negated
			case ONEWIRE_STATE_ROM_SEARCH_FALSE: // send ROM code bit while searching ROM, already negated
			case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
				timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
				if (0==(bits_buffer&(1<<(bits_bit%8)))) { // need to send a 0 bit
					gpio_clear(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // hold low to send 0 bit
				}
				break;
			case ONEWIRE_STATE_IDLE: // we only expect a reset
			default: // we don't expect any falling edge in other states
				onewire_slave_state = ONEWIRE_STATE_IDLE; // unexpected signal, reset to idle state
				break; // the timer overflow will confirm detect reset pulses
		}
		timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flags
		timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to measure the configured timeouts
	}
}

/** interrupt service routine called for timer */
void TIM_ISR(ONEWIRE_SLAVE_TIMER)(void)
{
	if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF)) { // reset timer triggered, verify if it's a reset
		if (0==gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // signal it still low, thus it must be a reset
			onewire_slave_state = ONEWIRE_STATE_RESET; // update state
		}
		timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer since there is nothing more to measure
		timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
		timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flag (I have no idea why the others are get too, even when the interrupt is not enabled)
	}
	if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF)) { // wait for presence pulse timer triggered
		timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
		if (ONEWIRE_STATE_WAIT_PRESENCE==onewire_slave_state) { // we can now send the pulse
			onewire_slave_state = ONEWIRE_STATE_PULSE_PRESENCE; // save new state
			gpio_clear(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // send presence pulse (will also trigger the timer start)
		}
	}
	if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF)) { // time to read the bit, or stop writing it
		// read/write bit depending on bit
		switch (onewire_slave_state) {
			case ONEWIRE_STATE_ROM_COMMAND: // read ROM command code bit
			case ONEWIRE_STATE_ROM_MATCH: // read ROM code
			case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command code bit
			case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
			case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
				if (gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // bit is set to 1
					bits_buffer |= (1<<(bits_bit%8)); // set bit
				} else { // bit is set to 0
					bits_buffer &= ~(1<<(bits_bit%8)); // clear bit
				}
				bits_bit++; // go to next bit
				break;
			case ONEWIRE_STATE_ROM_READ: // write ROM code
			case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
				gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending bit
				bits_bit++; // go to next bit
				break;
			case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is sent
			case ONEWIRE_STATE_ROM_SEARCH_FALSE: // ROM code bit is sent
				gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending bit
				break;
			default: // these states don't need read/write
				break;
		}
		static uint8_t rom_code_byte; // which byte of the ROM code is processed
		// act on bit count
		switch (onewire_slave_state) {
			case ONEWIRE_STATE_ROM_COMMAND: // read ROM command
				if (bits_bit>7) { // complete ROM command code received
					bits_bit = 0; // reset buffer
					rom_code_byte = 0; // reset ROM code byte index
					switch (bits_buffer) { // act depending on ROM command code
						case 0x33: // READ ROM
							bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to send the first byte
							onewire_slave_state = ONEWIRE_STATE_ROM_READ; // write ROM code
							break;
						case 0xcc: // SKIP ROM
							onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
							break;
						case 0x55: // MATCH ROM
							onewire_slave_state = ONEWIRE_STATE_ROM_MATCH; // read ROM code
							break;
						case 0xf0: // SEARCH ROM
							bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to search code
							onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to start sending first new bit
							break;
						default: // unknown ROM code
							onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
							break;
					}
				}
				break;
			case ONEWIRE_STATE_ROM_READ: // send ROM code
				if (bits_bit>7) { // complete byte transmitted
					rom_code_byte++; // go to next ROM code byte
					if (rom_code_byte>LENGTH(onewire_slave_rom_code)) { // complete ROM code send
						onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
					} else {
						bits_bit = 0; // reset buffer
						bits_buffer = onewire_slave_rom_code[rom_code_byte]; // send next ROM code byte
					}
				}
				break;
			case ONEWIRE_STATE_ROM_MATCH: // compare ROM code
				if (bits_bit>7) { // complete byte received
					if (bits_buffer==onewire_slave_rom_code[rom_code_byte]) { // ROM code byte matches
						bits_bit = 0; // reset buffer
						rom_code_byte++; // go to next ROM code byte
						if (rom_code_byte>=LENGTH(onewire_slave_rom_code)) { // complete ROM code matches
							onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
						}
					} else { // ROM code does not match
						 onewire_slave_state = ONEWIRE_STATE_IDLE; // stop comparing and go back to idle
					}
				}
				break;		
			case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is send, prepare to send negated version
				bits_buffer ^= (1<<bits_bit); // negate bit
				onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_FALSE; // send negated version
				break;
			case ONEWIRE_STATE_ROM_SEARCH_FALSE: // negated ROM code bit is send, prepare to read selected bit
				onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_SELECT; // read selected
				break;
			case ONEWIRE_STATE_ROM_SEARCH_SELECT: // check if we are selected
				if ((bits_buffer&(1<<(bits_bit-1)))==(onewire_slave_rom_code[rom_code_byte]&(1<<(bits_bit-1)))) { // we have been selected
					onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to compare next bit
				} else { // we are no selected
					onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to idle
				}
				if (bits_bit>7) { // complete byte searched
					bits_bit = 0; // reset buffer
					rom_code_byte++; // go to next ROM code byte
					if (rom_code_byte>=LENGTH(onewire_slave_rom_code)) { // complete ROM code search
						onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
					} else {
						bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare next ROM code byte
					}
				}
				break;		
			case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command
				if (bits_bit>7) { // complete function command code received
					onewire_slave_function_code = bits_buffer; // save function command code to user buffer
					onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer data
					onewire_slave_function_code_received = true; // notify user
				}
				break;
			case ONEWIRE_STATE_FUNCTION_READ: // save function data bit
				if (0==bits_bit%8) { // complete byte received
					onewire_slave_transfer_data[(bits_bit-1)/8] = bits_buffer; // save received bytes
				}
				if (bits_bit>=onewire_slave_transfer_bits) { // read transfer complete
					onewire_slave_transfer_data[(bits_bit-1)/8] = bits_buffer; // save last bits
					onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
					onewire_slave_transfer_complete = true; // notify user
				}
				break;
			case ONEWIRE_STATE_FUNCTION_WRITE: // update function data bit to write
				if (0==bits_bit%8) { // complete byte transfer
					bits_buffer = onewire_slave_transfer_data[bits_bit/8]; // prepare next byte to write
				}
				if (bits_bit>=onewire_slave_transfer_bits) { // write transfer complete
					onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
					onewire_slave_transfer_complete = true; // notify user
				}
				break;
			default: // no action needed
				break;
		}
		timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF); // clear flag
	}
	if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF)) { // end of presence pulse timer triggered
		timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF); // clear flag
		if (ONEWIRE_STATE_PULSE_PRESENCE==onewire_slave_state) {
			gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending presence pulse
			// if the pin stays low the reset timer will catch it
		}
	}
}