added 1wire search algorithm
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "_ow_checksum.h"
|
||||
|
||||
static inline uint8_t crc8_bits(uint8_t data)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
if(data & 1) crc ^= 0x5e;
|
||||
if(data & 2) crc ^= 0xbc;
|
||||
if(data & 4) crc ^= 0x61;
|
||||
if(data & 8) crc ^= 0xc2;
|
||||
if(data & 0x10) crc ^= 0x9d;
|
||||
if(data & 0x20) crc ^= 0x23;
|
||||
if(data & 0x40) crc ^= 0x46;
|
||||
if(data & 0x80) crc ^= 0x8c;
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint8_t crc8_add(uint8_t cksum, uint8_t byte)
|
||||
{
|
||||
return crc8_bits(byte ^ cksum);
|
||||
}
|
||||
|
||||
uint8_t ow_checksum(const uint8_t *buff, uint16_t len)
|
||||
{
|
||||
uint8_t cksum = 0;
|
||||
for(uint16_t i = 0; i < len; i++) {
|
||||
cksum = crc8_add(cksum, buff[i]);
|
||||
}
|
||||
return cksum;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_OW_CHECKSUM_H
|
||||
#define GEX_F072_OW_CHECKSUM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Compute a 1-wire type checksum.
|
||||
* If the buffer includes the checksum, the result should be 0.
|
||||
*
|
||||
* (this function may be used externally, or you can delete the implementation
|
||||
* from the c file if another implementation is already available)
|
||||
*
|
||||
* @param[in] buf - buffer of bytes to verify
|
||||
* @param[in] len - buffer length
|
||||
* @return checksum
|
||||
*/
|
||||
uint8_t ow_checksum(const uint8_t *buf, uint16_t len);
|
||||
|
||||
#endif //GEX_F072_OW_CHECKSUM_H
|
||||
@@ -5,10 +5,6 @@
|
||||
#ifndef GEX_F072_OW_COMMANDS_H
|
||||
#define GEX_F072_OW_COMMANDS_H
|
||||
|
||||
#ifndef OW_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#define OW_ROM_SEARCH 0xF0
|
||||
#define OW_ROM_READ 0x33
|
||||
#define OW_ROM_MATCH 0x55
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "_ow_commands.h"
|
||||
#include "_ow_search.h"
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
@@ -24,63 +24,9 @@ struct priv {
|
||||
bool busy; // flag used when the timer is running
|
||||
uint32_t busyStart;
|
||||
TF_ID busyRequestId;
|
||||
struct ow_search_state searchState;
|
||||
};
|
||||
|
||||
// Prototypes
|
||||
|
||||
/**
|
||||
* Reset the 1-wire bus
|
||||
*/
|
||||
bool ow_reset(Unit *unit);
|
||||
|
||||
/**
|
||||
* Write a bit to the 1-wire bus
|
||||
*/
|
||||
void ow_write_bit(Unit *unit, bool bit);
|
||||
|
||||
/**
|
||||
* Read a bit from the 1-wire bus
|
||||
*/
|
||||
bool ow_read_bit(Unit *unit);
|
||||
|
||||
/**
|
||||
* Write a byte to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u8(Unit *unit, uint8_t byte);
|
||||
|
||||
/**
|
||||
* Write a halfword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u16(Unit *unit, uint16_t halfword);
|
||||
|
||||
/**
|
||||
* Write a word to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u32(Unit *unit, uint32_t word);
|
||||
|
||||
/**
|
||||
* Write a doubleword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u64(Unit *unit, uint64_t dword);
|
||||
|
||||
/**
|
||||
* Read a byte form the 1-wire bus
|
||||
*/
|
||||
uint8_t ow_read_u8(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a halfword form the 1-wire bus
|
||||
*/
|
||||
uint16_t ow_read_u16(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a word form the 1-wire bus
|
||||
*/
|
||||
uint32_t ow_read_u32(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a doubleword form the 1-wire bus
|
||||
*/
|
||||
uint64_t ow_read_u64(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_OW_INTERNAL_H
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_low_level.h"
|
||||
|
||||
static inline void ow_pull_high(Unit *unit)
|
||||
{
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_OW_LOW_LEVEL_H
|
||||
#define GEX_F072_OW_LOW_LEVEL_H
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "_ow_low_level.h"
|
||||
|
||||
/**
|
||||
* Reset the 1-wire bus
|
||||
*/
|
||||
bool ow_reset(Unit *unit);
|
||||
|
||||
/**
|
||||
* Write a bit to the 1-wire bus
|
||||
*/
|
||||
void ow_write_bit(Unit *unit, bool bit);
|
||||
|
||||
/**
|
||||
* Read a bit from the 1-wire bus
|
||||
*/
|
||||
bool ow_read_bit(Unit *unit);
|
||||
|
||||
/**
|
||||
* Write a byte to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u8(Unit *unit, uint8_t byte);
|
||||
|
||||
/**
|
||||
* Write a halfword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u16(Unit *unit, uint16_t halfword);
|
||||
|
||||
/**
|
||||
* Write a word to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u32(Unit *unit, uint32_t word);
|
||||
|
||||
/**
|
||||
* Write a doubleword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u64(Unit *unit, uint64_t dword);
|
||||
|
||||
/**
|
||||
* Read a byte form the 1-wire bus
|
||||
*/
|
||||
uint8_t ow_read_u8(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a halfword form the 1-wire bus
|
||||
*/
|
||||
uint16_t ow_read_u16(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a word form the 1-wire bus
|
||||
*/
|
||||
uint32_t ow_read_u32(Unit *unit);
|
||||
|
||||
/**
|
||||
* Read a doubleword form the 1-wire bus
|
||||
*/
|
||||
uint64_t ow_read_u64(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_OW_LOW_LEVEL_H
|
||||
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_1wire.h"
|
||||
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_search.h"
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_low_level.h"
|
||||
#include "_ow_checksum.h"
|
||||
#include "_ow_commands.h"
|
||||
|
||||
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums)
|
||||
{
|
||||
if (unit->driver != &UNIT_1WIRE)
|
||||
trap("Wrong unit type - %s", unit->driver->name);
|
||||
|
||||
assert_param(command == OW_ROM_SEARCH || command == OW_ROM_ALM_SEARCH);
|
||||
|
||||
struct priv *priv = unit->data;
|
||||
struct ow_search_state *state = &priv->searchState;
|
||||
|
||||
state->prev_last_fork = 64;
|
||||
memset(state->prev_code, 0, 8);
|
||||
state->status = OW_SEARCH_MORE;
|
||||
state->command = command;
|
||||
state->first = true;
|
||||
state->test_checksums = test_checksums;
|
||||
}
|
||||
|
||||
uint16_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint16_t capacity)
|
||||
{
|
||||
if (unit->driver != &UNIT_1WIRE)
|
||||
trap("Wrong unit type - %s", unit->driver->name);
|
||||
|
||||
assert_param(codes);
|
||||
|
||||
struct priv *priv = unit->data;
|
||||
struct ow_search_state *state = &priv->searchState;
|
||||
|
||||
if (state->status != OW_SEARCH_MORE) return 0;
|
||||
|
||||
uint16_t found_devices = 0;
|
||||
|
||||
while (found_devices < capacity) {
|
||||
uint8_t index = 0;
|
||||
ow_romcode_t code = {};
|
||||
int8_t last_fork = -1;
|
||||
|
||||
// Start a new transaction. Devices respond to reset
|
||||
if (!ow_reset(unit)) {
|
||||
state->status = OW_SEARCH_FAILED;
|
||||
goto done;
|
||||
}
|
||||
// Send the search command (SEARCH_ROM, SEARCH_ALARM)
|
||||
ow_write_u8(unit, state->command);
|
||||
|
||||
uint8_t *code_byte = &code[0];
|
||||
|
||||
bool p, n;
|
||||
while (index != 64) {
|
||||
// Read a bit and its complement
|
||||
p = ow_read_bit(unit);
|
||||
n = ow_read_bit(unit);
|
||||
|
||||
if (!p && !n) {
|
||||
// A fork: there are devices on the bus with different bit value
|
||||
// (the bus is open-drain, in both cases one device pulls it low)
|
||||
if ((found_devices > 0 || !state->first) && index < state->prev_last_fork) {
|
||||
// earlier than the last fork, take the same turn as before
|
||||
p = ow_code_getbit(state->prev_code, index);
|
||||
if (!p) last_fork = index; // remember for future runs, 1 not explored yet
|
||||
}
|
||||
else if (index == state->prev_last_fork) {
|
||||
p = 1; // both forks are now exhausted
|
||||
}
|
||||
else { // a new fork
|
||||
last_fork = index;
|
||||
}
|
||||
}
|
||||
else if (p && n) {
|
||||
// No devices left connected - this doesn't normally happen
|
||||
state->status = OW_SEARCH_FAILED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// All devices have a matching bit here, or it was resolved in a fork
|
||||
if (p) *code_byte |= (1 << (index & 7));
|
||||
ow_write_bit(unit, p);
|
||||
|
||||
index++;
|
||||
if((index & 7) == 0) {
|
||||
code_byte++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(state->prev_code, code, 8);
|
||||
|
||||
if (!state->test_checksums || 0 == ow_checksum(code, 8)) {
|
||||
// Record a found address
|
||||
memcpy(codes[found_devices], code, 8);
|
||||
found_devices++;
|
||||
}
|
||||
|
||||
// Stop condition
|
||||
if (last_fork == -1) {
|
||||
state->status = OW_SEARCH_DONE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
state->prev_last_fork = last_fork;
|
||||
}
|
||||
|
||||
done:
|
||||
state->first = false;
|
||||
return found_devices;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_OW_SEARCH_H
|
||||
#define GEX_F072_OW_SEARCH_H
|
||||
|
||||
#ifndef OW_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "unit_base.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Data type holding a romcode
|
||||
*/
|
||||
typedef uint8_t ow_romcode_t[8];
|
||||
|
||||
/**
|
||||
* Get a single bit from a romcode
|
||||
*/
|
||||
#define ow_code_getbit(code, index) (bool)((code)[(index) >> 3] & (1 << ((index) & 7)))
|
||||
|
||||
/**
|
||||
* Convert to unsigned 64-bit integer
|
||||
* (works only on little-endian systems - eg. OK on x86/x86_64, not on PowerPC)
|
||||
*/
|
||||
#define ow_romcode_to_u64(code) (*((uint64_t *) (void *)(code)))
|
||||
|
||||
/**
|
||||
* States of the search algorithm
|
||||
*/
|
||||
enum ow_search_result {
|
||||
OW_SEARCH_DONE = 0,
|
||||
OW_SEARCH_MORE = 1,
|
||||
OW_SEARCH_FAILED = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal state of the search algorithm.
|
||||
* Check status to see if more remain to be read or an error occurred.
|
||||
*/
|
||||
struct ow_search_state {
|
||||
int8_t prev_last_fork;
|
||||
ow_romcode_t prev_code;
|
||||
uint8_t command;
|
||||
enum ow_search_result status;
|
||||
bool first;
|
||||
bool test_checksums;
|
||||
};
|
||||
|
||||
/**
|
||||
* Init the search algorithm state structure
|
||||
*
|
||||
* @param[out] state - inited struct
|
||||
* @param[in] command - command to send for requesting the search (e.g. SEARCH_ROM)
|
||||
* @param[in] test_checksums - verify checksums of all read romcodes
|
||||
*/
|
||||
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums);
|
||||
|
||||
/**
|
||||
* Perform a search of the 1-wire bus, with a state struct pre-inited
|
||||
* using ow_search_init().
|
||||
*
|
||||
* Romcodes are stored in the provided array in a numerically ascending order.
|
||||
*
|
||||
* This function may be called repeatedly to retrieve more addresses than could fit
|
||||
* in the address buffer.
|
||||
*
|
||||
* @param[in,out] state - search state, used for multiple calls with limited buffer size
|
||||
* @param[out] codes - buffer for found romcodes
|
||||
* @param[in] capacity - buffer capacity
|
||||
* @return number of romcodes found. Search status is stored in state->status
|
||||
*/
|
||||
uint16_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint16_t capacity);
|
||||
|
||||
#endif //GEX_F072_OW_SEARCH_H
|
||||
+39
-10
@@ -10,6 +10,10 @@
|
||||
// 1WIRE master
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_commands.h"
|
||||
#include "_ow_search.h"
|
||||
#include "_ow_checksum.h"
|
||||
#include "_ow_low_level.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -176,7 +180,8 @@ enum PinCmd_ {
|
||||
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
|
||||
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
|
||||
CMD_SEARCH_ALARM = 2, // like normal scan, but retrieve only devices with alarm
|
||||
CMD_READ_ADDR = 3, // read the ROM code from a single device (for single-device bus)
|
||||
CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices
|
||||
CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus)
|
||||
|
||||
CMD_SKIP_WRITE = 10, // write multiple bytes using the SKIP_ROM command
|
||||
CMD_SKIP_READ = 11, // write and read multiple bytes using the SKIP_ROM command
|
||||
@@ -213,14 +218,38 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
|
||||
if (priv->busy) return E_BUSY;
|
||||
|
||||
uint8_t search_cmd = OW_ROM_SEARCH;
|
||||
switch (command) {
|
||||
case CMD_SEARCH_ADDR:
|
||||
// TODO
|
||||
return E_NOT_IMPLEMENTED;
|
||||
|
||||
case CMD_SEARCH_ALARM:
|
||||
// TODO
|
||||
return E_NOT_IMPLEMENTED;
|
||||
search_cmd = OW_ROM_ALM_SEARCH;
|
||||
// pass-through
|
||||
case CMD_SEARCH_ADDR:
|
||||
ow_search_init(unit, search_cmd, true);
|
||||
// pass through
|
||||
case CMD_SEARCH_CONTINUE:;
|
||||
ow_romcode_t *codes = (void *) unit_tmp512;
|
||||
uint16_t count = ow_search_run(unit, codes, UNIT_TMP_LEN/8);
|
||||
|
||||
if (priv->searchState.status == OW_SEARCH_FAILED) {
|
||||
return E_HW_FAULT;
|
||||
}
|
||||
|
||||
// First byte of the response is a flag whether there are more devices
|
||||
// to be found using CMD_SEARCH_CONTINUE
|
||||
uint8_t status_code = (uint8_t) (priv->searchState.status == OW_SEARCH_MORE);
|
||||
|
||||
TF_Msg msg = {
|
||||
.frame_id = frame_id,
|
||||
.type = MSG_SUCCESS,
|
||||
.len = (TF_LEN) (count * 8 + 1),
|
||||
};
|
||||
TF_Respond_Multipart(comm, &msg);
|
||||
TF_Multipart_Payload(comm, &status_code, 1);
|
||||
// the codes are back-to-back stored inside the buffer, we send it directly
|
||||
// (it's already little-endian, as if built by PayloadBuilder)
|
||||
TF_Multipart_Payload(comm, (uint8_t *) unit_tmp512, (uint32_t) (count * 8));
|
||||
TF_Multipart_Close(comm);
|
||||
return E_SUCCESS;
|
||||
|
||||
/** Simply check presence of any devices on the bus. Responds with SUCCESS or HW_TIMEOUT */
|
||||
case CMD_CHECK_PRESENCE:
|
||||
@@ -234,7 +263,7 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
case CMD_READ_ADDR:
|
||||
// reset
|
||||
presence = ow_reset(unit);
|
||||
if (!presence) return E_HW_TIMEOUT;
|
||||
if (!presence) return E_HW_FAULT;
|
||||
|
||||
// command
|
||||
ow_write_u8(unit, OW_ROM_READ);
|
||||
@@ -259,7 +288,7 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
case CMD_SKIP_WRITE:
|
||||
// reset
|
||||
presence = ow_reset(unit);
|
||||
if (!presence) return E_HW_TIMEOUT;
|
||||
if (!presence) return E_HW_FAULT;
|
||||
|
||||
// MATCH_ROM+addr, or SKIP_ROM
|
||||
cmd_match_skip(unit, command, pp);
|
||||
@@ -282,7 +311,7 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
case CMD_SKIP_READ:;
|
||||
// reset
|
||||
presence = ow_reset(unit);
|
||||
if (!presence) return E_HW_TIMEOUT;
|
||||
if (!presence) return E_HW_FAULT;
|
||||
|
||||
// MATCH_ROM+addr, or SKIP_ROM
|
||||
cmd_match_skip(unit, command, pp);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
X(MALFORMED_COMMAND, NULL) \
|
||||
X(NOT_APPLICABLE, NULL) \
|
||||
X(HW_TIMEOUT, NULL) \
|
||||
X(HW_FAULT, NULL) \
|
||||
X(NO_SUCH_UNIT, NULL) \
|
||||
X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \
|
||||
X(BAD_UNIT_TYPE, NULL) \
|
||||
|
||||
Reference in New Issue
Block a user