Blackbox device type 'file' (SITL) considered working when file handler is available
[inav.git] / src / main / drivers / 1-wire / ds2482.c
blobcfe10b4d5cc2dedae4100a8acd06fe11fd03be53
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdint.h>
21 #include "platform.h"
23 #include "build/debug.h"
25 #include "drivers/1-wire.h"
26 #include "drivers/1-wire/ds_crc.h"
27 #include "drivers/1-wire/ds2482.h"
28 #include "drivers/time.h"
31 #define DS2482_STATUS_REG_ADDR 0xF0
32 #define DS2482_READ_DATA_REG_ADDR 0xE1
33 #define DS2482_CONFIG_REG_ADDR 0xC3
35 #define DS2482_CONFIG_REG_APU (1<<0) // Active pull-up
36 #define DS2482_CONFIG_REG_SPU (1<<2) // Strong pull-up
37 #define DS2482_CONFIG_REG_WS (1<<3) // 1-Wire speed
39 #define DS2482_STATUS_REG_1WB_POS 0 // 1-Wire busy
40 #define DS2482_STATUS_REG_PPD_POS 1 // Presense-pulse detect
41 #define DS2482_STATUS_REG_SD_POS 2 // Short detected
42 #define DS2482_STATUS_REG_LL_POS 3 // Logic level
43 #define DS2482_STATUS_REG_RST_POS 4 // Device reset
44 #define DS2482_STATUS_REG_SBR_POS 5 // Single bit result
45 #define DS2482_STATUS_REG_TSB_POS 6 // Triplet second bit
46 #define DS2482_STATUS_REG_DIR_POS 7 // Branch direction taken
48 #define DS2482_1WIRE_BUSY(status) (status & (1 << DS2482_STATUS_REG_1WB_POS))
49 #define DS2482_DEVICE_PRESENT(status) (status & (1 << DS2482_STATUS_REG_PPD_POS)) // True if a device have been detected on the bus after a bus reset
50 #define DS2482_RESET(status) (status & (1 << DS2482_STATUS_REG_RST_POS))
51 #define DS2482_LOGIC_LEVEL(status) (status & (1 << DS2482_STATUS_REG_LL_POS))
52 #define DS2482_SHORT_DETECTED(status) (status & (1 << DS2482_STATUS_REG_SD_POS))
53 #define DS2482_SBR_VALUE(status) ((status >> DS2482_STATUS_REG_SBR_POS) & 1) // Extract single bit read value or triplet first bit from status register value
54 #define DS2482_TSB_VALUE(status) ((status >> DS2482_STATUS_REG_TSB_POS) & 1) // Extract triplet second bit value from status register value
55 #define DS2482_DIR_VALUE(status) ((status >> DS2482_STATUS_REG_DIR_POS) & 1) // Extract triplet chosen direction bit value from status register value
57 #define DS2482_1WIRE_SINGLE_BIT_WRITE0 0
58 #define DS2482_1WIRE_SINGLE_BIT_WRITE1_READ (1<<7)
60 #define DS2482_CONFIG_WRITE_BYTE(config) (config | ((~config & 0xF) << 4)) // Config's upper nibble should be the one's complement of lower nibble when writing
62 #define DS2482_RESET_CMD 0xF0
63 #define DS2482_SET_READ_PTR_CMD 0xE1
64 #define DS2482_WRITE_CONFIG_CMD 0xD2
65 #define DS2482_1WIRE_RESET_CMD 0xB4
66 #define DS2482_1WIRE_SINGLE_BIT_CMD 0x87
67 #define DS2482_1WIRE_WRITE_BYTE_CMD 0xA5
68 #define DS2482_1WIRE_READ_BYTE_CMD 0x96
69 #define DS2482_1WIRE_TRIPLET_CMD 0x78
71 #define _1WIRE_SEARCH_ROM_CMD 0xF0
72 #define _1WIRE_READ_ROM_CMD 0x33
73 #define _1WIRE_MATCH_ROM_CMD 0x55
74 #define _1WIRE_SKIP_ROM_CMD 0xCC
77 #if defined(USE_1WIRE) && defined(USE_1WIRE_DS2482)
80 static bool ds2482Reset(owDev_t *owDev)
82 return busWrite(owDev->busDev, 0xFF, DS2482_RESET_CMD);
85 static bool ds2482SetReadPtr(owDev_t *owDev, uint8_t reg)
87 return busWrite(owDev->busDev, DS2482_SET_READ_PTR_CMD, reg);
90 static bool ds2482ReadReg(owDev_t *owDev, uint8_t reg, uint8_t *byte)
92 bool ack = ds2482SetReadPtr(owDev, reg);
93 if (!ack) return false;
94 return busRead(owDev->busDev, 0xFF, byte);
97 static bool ds2482ReadByte(owDev_t *owDev, uint8_t *byte)
99 return ds2482ReadReg(owDev, DS2482_READ_DATA_REG_ADDR, byte);
102 static bool ds2482ReadConfig(owDev_t *owDev, uint8_t *config)
104 return ds2482ReadReg(owDev, DS2482_CONFIG_REG_ADDR, config);
107 static bool ds2482WriteConfig(owDev_t *owDev, uint8_t config)
109 return busWrite(owDev->busDev, DS2482_WRITE_CONFIG_CMD, DS2482_CONFIG_WRITE_BYTE(config));
112 static bool ds2482ReadStatus(owDev_t *owDev, uint8_t *status)
114 bool ack = ds2482ReadReg(owDev, DS2482_STATUS_REG_ADDR, &owDev->status);
115 if (!ack) return false;
116 *status = owDev->status;
117 return true;
120 static uint8_t ds2482GetStatus(owDev_t *owDev)
122 return owDev->status;
125 static bool ds2482Poll(owDev_t *owDev, bool waitForBus, uint8_t *status)
127 do {
128 bool ack = busRead(owDev->busDev, 0xFF, &owDev->status);
129 if (!ack) return false;
130 } while (waitForBus && DS2482_1WIRE_BUSY(owDev->status));
131 if (status) *status = owDev->status;
132 return true;
135 static bool ds2482WaitForBus(owDev_t *owDev)
137 return ds2482Poll(owDev, true, NULL);
140 static bool ds2482OwBusReady(owDev_t *owDev)
142 bool ack = busRead(owDev->busDev, 0xFF, &owDev->status);
143 if (!ack) return false;
144 return !DS2482_1WIRE_BUSY(owDev->status);
147 static bool ds2482OwResetCommand(owDev_t *owDev)
149 return busWrite(owDev->busDev, 0xFF, DS2482_1WIRE_RESET_CMD);
152 static bool ds2482OwReset(owDev_t *owDev)
154 bool ack = ds2482OwResetCommand(owDev);
155 if (!ack) return false;
156 return ds2482WaitForBus(owDev);
159 static bool ds2482OwWriteByteCommand(owDev_t *owDev, uint8_t byte)
161 return busWrite(owDev->busDev, DS2482_1WIRE_WRITE_BYTE_CMD, byte);
164 static bool ds2482OwWriteByte(owDev_t *owDev, uint8_t byte)
166 bool ack = ds2482OwWriteByteCommand(owDev, byte);
167 if (!ack) return false;
168 return ds2482WaitForBus(owDev);
171 static bool ds2482OwWriteBuf(owDev_t *owDev, const uint8_t *buf, uint8_t len)
173 for (uint8_t index = 0; index < len; ++index) {
174 bool ack = ds2482OwWriteByte(owDev, buf[index]);
175 if (!ack) return false;
177 return true;
180 static bool ds2482OwReadByteCommand(owDev_t *owDev)
182 return busWrite(owDev->busDev, 0xFF, DS2482_1WIRE_READ_BYTE_CMD);
185 static bool ds2482OwReadByte(owDev_t *owDev, uint8_t *result)
187 bool ack = ds2482OwReadByteCommand(owDev);
188 if (!ack) return false;
190 ack = ds2482WaitForBus(owDev);
191 if (!ack) return false;
193 return ds2482ReadByte(owDev, result);
196 static bool ds2482OwReadBuf(owDev_t *owDev, uint8_t *buf, uint8_t len)
198 for (uint8_t index = 0; index < len; ++index) {
199 bool ack = ds2482OwReadByte(owDev, buf + index);
200 if (!ack) return false;
202 return true;
205 static bool ds2482OwSingleBitCommand(owDev_t *owDev, uint8_t type)
207 return busWrite(owDev->busDev, DS2482_1WIRE_SINGLE_BIT_CMD, type);
210 static bool ds2482OwSingleBitResult(owDev_t *owDev)
212 return DS2482_SBR_VALUE(owDev->status);
215 static bool ds2482OwSingleBit(owDev_t *owDev, uint8_t type, bool *result)
217 bool ack = ds2482OwSingleBitCommand(owDev, type);
219 ack = ds2482WaitForBus(owDev);
220 if (!ack) return false;
222 if (result) *result = ds2482OwSingleBitResult(owDev);
223 return true;
226 static bool ds2482OwTripletCommand(owDev_t *owDev, uint8_t direction)
228 return busWrite(owDev->busDev, DS2482_1WIRE_TRIPLET_CMD, direction << 7);
231 static uint8_t ds2482OwTripletResult(owDev_t *owDev)
233 return owDev->status >> 5;
236 static bool ds2482OwTriplet(owDev_t *owDev, uint8_t direction, uint8_t *result)
238 bool ack = ds2482OwTripletCommand(owDev, direction << 7);
239 if (!ack) return false;
240 ack = ds2482Poll(owDev, true, NULL);
241 if (!ack) return false;
242 *result = ds2482OwTripletResult(owDev);
243 return true;
246 static bool ds2482OwSkipRomCommand(owDev_t *owDev)
248 return ds2482OwWriteByte(owDev, _1WIRE_SKIP_ROM_CMD);
251 static bool ds2482OwSkipRom(owDev_t *owDev)
253 bool ack = ds2482OwReset(owDev);
254 if (!ack) return false;
256 ack = ds2482OwSkipRomCommand(owDev);
257 if (!ack) return false;
259 return ds2482WaitForBus(owDev);
262 static bool ds2482OwMatchRomCommand(owDev_t *owDev)
264 return ds2482OwWriteByteCommand(owDev, _1WIRE_MATCH_ROM_CMD);
267 static bool ds2482OwMatchRom(owDev_t *owDev, uint64_t rom)
269 bool ack = ds2482OwReset(owDev);
270 if (!ack) return false;
272 ack = ds2482OwMatchRomCommand(owDev);
273 if (!ack) return false;
275 ack = ds2482WaitForBus(owDev);
276 if (!ack) return false;
278 for (uint8_t romByteIndex = 0; romByteIndex < 8; ++romByteIndex) {
279 ack = ds2482OwWriteByte(owDev, ((uint8_t *)&rom)[romByteIndex]);
280 if (!ack) return false;
283 return true;
286 static bool ds2482OwSearchRom(owDev_t *owDev, uint8_t family_code, uint64_t *rom_table, uint8_t *rom_table_len)
288 bool ack;
289 uint8_t last_collision_index = 0, rom_index = 0;
291 do {
293 uint8_t rom_byte_index = 0, rom_bit_index = 1, rom_byte_mask = 1;
294 uint8_t dir_zero_last_index = 0; // Bit index where the 0 direction has been chosen after collision
295 uint8_t *rom = (uint8_t *)&rom_table[rom_index];
297 ack = ds2482OwReset(owDev);
298 if (!ack) goto ds2482SearchRomReturn;
300 ack = ds2482Poll(owDev, true, NULL);
301 if (!ack) goto ds2482SearchRomReturn;
303 if (!DS2482_DEVICE_PRESENT(owDev->status))
304 goto ds2482SearchRomReturn;
306 ack = ds2482OwWriteByte(owDev, _1WIRE_SEARCH_ROM_CMD);
307 if (!ack) goto ds2482SearchRomReturn;
309 do {
311 uint8_t direction;
312 if (family_code && (rom_bit_index < 9)) {
313 direction = (family_code >> (rom_bit_index - 1)) & 1;
314 } else if ((rom_index > 0) && (rom_bit_index < last_collision_index)) {
315 const uint8_t *previous_rom = (uint8_t *)&rom_table[rom_index-1];
316 direction = (previous_rom[rom_byte_index] & rom_byte_mask) > 0;
317 } else {
318 direction = rom_bit_index == last_collision_index;
321 ack = ds2482OwTripletCommand(owDev, direction);
322 if (!ack) goto ds2482SearchRomReturn;
324 ack = ds2482Poll(owDev, true, NULL);
325 if (!ack) goto ds2482SearchRomReturn;
327 uint8_t triplet_sbr = DS2482_SBR_VALUE(owDev->status);
328 uint8_t triplet_tsb = DS2482_TSB_VALUE(owDev->status);
329 uint8_t triplet_dir = DS2482_DIR_VALUE(owDev->status);
331 if (triplet_sbr && triplet_tsb) break; // Error, the device have been disconnected during the search, restart
333 if (family_code && (rom_bit_index < 9) && (triplet_dir != direction))
334 goto ds2482SearchRomReturn;
336 if (triplet_dir)
337 rom[rom_byte_index] |= rom_byte_mask;
338 else {
339 if (!(triplet_sbr || triplet_tsb)) dir_zero_last_index = rom_bit_index; // Collision
340 rom[rom_byte_index] &= ~rom_byte_mask;
343 rom_bit_index += 1;
345 if (!(rom_byte_mask <<= 1)) {
346 rom_byte_index += 1;
347 rom_byte_mask = 1;
350 } while (rom_byte_index < 8);
352 if ((rom_bit_index > 64) && (rom[7] == ds_crc8(rom, 7))) {
353 rom_index += 1;
354 last_collision_index = dir_zero_last_index;
355 if (!last_collision_index) break; // All the devices have been found
358 } while (rom_index < *rom_table_len);
360 ds2482SearchRomReturn:
362 *rom_table_len = rom_index;
364 return ack;
369 static bool ds2482Init(owDev_t *owDev)
371 return ds2482WriteConfig(owDev, DS2482_CONFIG_REG_APU);
374 #define DETECTION_MAX_RETRY_COUNT 5
375 static bool deviceDetect(owDev_t *owDev)
377 for (int retryCount = 0; retryCount < DETECTION_MAX_RETRY_COUNT; retryCount++) {
378 delay(10);
379 if (ds2482Reset(owDev)) return true;
382 return false;
385 bool ds2482Detect(owDev_t *owDev)
387 owDev->busDev = busDeviceInit(BUSTYPE_I2C, DEVHW_DS2482, 0, OWNER_1WIRE);
388 if (owDev->busDev == NULL) {
389 return false;
392 if (!deviceDetect(owDev)) {
393 busDeviceDeInit(owDev->busDev);
394 return false;
397 ds2482Init(owDev);
399 owDev->reset = ds2482Reset;
400 owDev->owResetCommand = ds2482OwResetCommand;
401 owDev->owReset = ds2482OwReset;
402 owDev->waitForBus = ds2482WaitForBus;
403 owDev->readConfig = ds2482ReadConfig;
404 owDev->writeConfig = ds2482WriteConfig;
405 owDev->readStatus = ds2482ReadStatus;
406 owDev->getStatus = ds2482GetStatus;
407 owDev->poll = ds2482Poll;
408 owDev->owBusReady = ds2482OwBusReady;
410 owDev->owSearchRom = ds2482OwSearchRom;
411 owDev->owMatchRomCommand = ds2482OwMatchRomCommand;
412 owDev->owMatchRom = ds2482OwMatchRom;
413 owDev->owSkipRomCommand = ds2482OwSkipRomCommand;
414 owDev->owSkipRom = ds2482OwSkipRom;
416 owDev->owWriteByteCommand = ds2482OwWriteByteCommand;
417 owDev->owWriteByte = ds2482OwWriteByte;
418 owDev->owWriteBuf = ds2482OwWriteBuf;
419 owDev->owReadByteCommand = ds2482OwReadByteCommand;
420 owDev->owReadByteResult = ds2482ReadByte;
421 owDev->owReadByte = ds2482OwReadByte;
422 owDev->owReadBuf = ds2482OwReadBuf;
423 owDev->owSingleBitCommand = ds2482OwSingleBitCommand;
424 owDev->owSingleBitResult = ds2482OwSingleBitResult;
425 owDev->owSingleBit = ds2482OwSingleBit;
426 owDev->owTripletCommand = ds2482OwTripletCommand;
427 owDev->owTripletResult = ds2482OwTripletResult;
428 owDev->owTriplet = ds2482OwTriplet;
430 return true;
433 #endif /* defined(USE_1WIRE) && defined(USE_1WIRE_DS2482) */