Modularization, stage 1
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_1wire.h"
|
||||
|
||||
// 1WIRE master
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_commands.h"
|
||||
#include "_ow_low_level.h"
|
||||
|
||||
/* Check presence of any devices on the bus */
|
||||
error_t UU_1WIRE_CheckPresence(Unit *unit, bool *presence)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
||||
// reset
|
||||
*presence = ow_reset(unit);
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/* Read address of a lone device on the bus */
|
||||
error_t UU_1WIRE_ReadAddress(Unit *unit, uint64_t *address)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
||||
*address = 0;
|
||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
||||
|
||||
// command
|
||||
ow_write_u8(unit, OW_ROM_READ);
|
||||
|
||||
// read the ROM code
|
||||
*address = ow_read_u64(unit);
|
||||
|
||||
const uint8_t *addr_as_bytes = (void*)address;
|
||||
if (0 != ow_checksum(addr_as_bytes, 8)) {
|
||||
*address = 0;
|
||||
return E_CHECKSUM_MISMATCH; // checksum mismatch
|
||||
}
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/* Write bytes to a device */
|
||||
error_t UU_1WIRE_Write(Unit *unit, uint64_t address, const uint8_t *buff, uint32_t len)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
||||
|
||||
// MATCH_ROM+addr, or SKIP_ROM
|
||||
if (address != 0) {
|
||||
ow_write_u8(unit, OW_ROM_MATCH);
|
||||
ow_write_u64(unit, address);
|
||||
} else {
|
||||
ow_write_u8(unit, OW_ROM_SKIP);
|
||||
}
|
||||
|
||||
// write the payload;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
ow_write_u8(unit, *buff++);
|
||||
}
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/* Write a request to a device and read a response */
|
||||
error_t UU_1WIRE_Read(Unit *unit, uint64_t address,
|
||||
const uint8_t *request_buff, uint32_t request_len,
|
||||
uint8_t *response_buff, uint32_t response_len, bool check_crc)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
||||
|
||||
uint8_t *rb = response_buff;
|
||||
|
||||
// MATCH_ROM+addr, or SKIP_ROM
|
||||
if (address != 0) {
|
||||
ow_write_u8(unit, OW_ROM_MATCH);
|
||||
ow_write_u64(unit, address);
|
||||
} else {
|
||||
ow_write_u8(unit, OW_ROM_SKIP);
|
||||
}
|
||||
|
||||
// write the payload;
|
||||
for (uint32_t i = 0; i < request_len; i++) {
|
||||
ow_write_u8(unit, *request_buff++);
|
||||
}
|
||||
|
||||
// read the requested number of bytes
|
||||
for (uint32_t i = 0; i < response_len; i++) {
|
||||
*rb++ = ow_read_u8(unit);
|
||||
}
|
||||
|
||||
if (check_crc) {
|
||||
if (0 != ow_checksum(response_buff, response_len)) {
|
||||
return E_CHECKSUM_MISMATCH;
|
||||
}
|
||||
}
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/* Perform the search algorithm (start or continue) */
|
||||
error_t UU_1WIRE_Search(Unit *unit, bool with_alarm, bool restart,
|
||||
uint64_t *buffer, uint32_t capacity, uint32_t *real_count,
|
||||
bool *have_more)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (restart) {
|
||||
uint8_t search_cmd = (uint8_t) (with_alarm ? OW_ROM_ALM_SEARCH : OW_ROM_SEARCH);
|
||||
ow_search_init(unit, search_cmd, true);
|
||||
}
|
||||
|
||||
*real_count = ow_search_run(unit, (ow_romcode_t *) buffer, capacity);
|
||||
|
||||
// resolve the code
|
||||
switch (priv->searchState.status) {
|
||||
case OW_SEARCH_MORE:
|
||||
*have_more = priv->searchState.status == OW_SEARCH_MORE;
|
||||
|
||||
case OW_SEARCH_DONE:
|
||||
return E_SUCCESS;
|
||||
|
||||
case OW_SEARCH_FAILED:
|
||||
return priv->searchState.error;
|
||||
}
|
||||
|
||||
return E_INTERNAL_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/01/29.
|
||||
//
|
||||
|
||||
#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
|
||||
#define OW_ROM_SKIP 0xCC
|
||||
#define OW_ROM_ALM_SEARCH 0xEC
|
||||
|
||||
#endif //GEX_F072_OW_COMMANDS_H
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t OW_preInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
// some defaults
|
||||
priv->pin_number = 0;
|
||||
priv->port_name = 'A';
|
||||
priv->parasitic = false;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t OW_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// --- Parse config ---
|
||||
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
|
||||
priv->port = hw_port2periph(priv->port_name, &suc);
|
||||
Resource rsc = rsc_portpin2rsc(priv->port_name, priv->pin_number, &suc);
|
||||
if (!suc) return E_BAD_CONFIG;
|
||||
|
||||
// --- Claim resources ---
|
||||
TRY(rsc_claim(unit, rsc));
|
||||
|
||||
// --- Init hardware ---
|
||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin, LL_GPIO_OUTPUT_PUSHPULL);
|
||||
LL_GPIO_SetPinSpeed(priv->port, priv->ll_pin, LL_GPIO_SPEED_FREQ_HIGH);
|
||||
LL_GPIO_SetPinPull(priv->port, priv->ll_pin, LL_GPIO_PULL_UP); // pull-up for OD state
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Tear down the unit */
|
||||
void OW_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// Release all resources
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/01/29.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_OW_INTERNAL_H
|
||||
#define GEX_F072_OW_INTERNAL_H
|
||||
|
||||
#ifndef OW_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "_ow_search.h"
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
char port_name;
|
||||
uint8_t pin_number;
|
||||
bool parasitic;
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
uint32_t ll_pin;
|
||||
|
||||
TimerHandle_t busyWaitTimer; // timer used to wait for ds1820 measurement completion
|
||||
bool busy; // flag used when the timer is running
|
||||
uint32_t busyStart;
|
||||
TF_ID busyRequestId;
|
||||
struct ow_search_state searchState;
|
||||
};
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void OW_loadBinary(Unit *unit, PayloadParser *pp);
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void OW_writeBinary(Unit *unit, PayloadBuilder *pb);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t OW_loadIni(Unit *unit, const char *key, const char *value);
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void OW_writeIni(Unit *unit, IniWriter *iw);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t OW_preInit(Unit *unit);
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t OW_init(Unit *unit);
|
||||
|
||||
/** Tear down the unit */
|
||||
void OW_deInit(Unit *unit);
|
||||
|
||||
/** Callback for the FreeRTOS timer used to wait for device ready */
|
||||
void OW_TimerCb(TimerHandle_t xTimer);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
#endif //GEX_F072_OW_INTERNAL_H
|
||||
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/01/29.
|
||||
//
|
||||
// 1-Wire unit low level functions
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_low_level.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, uint32_t len)
|
||||
{
|
||||
uint8_t cksum = 0;
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
cksum = crc8_add(cksum, buff[i]);
|
||||
}
|
||||
return cksum;
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
static inline void ow_pull_high(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
LL_GPIO_SetOutputPin(priv->port, priv->ll_pin);
|
||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
||||
}
|
||||
|
||||
static inline void ow_pull_low(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
LL_GPIO_ResetOutputPin(priv->port, priv->ll_pin);
|
||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
||||
}
|
||||
|
||||
static inline void ow_release_line(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_INPUT);
|
||||
}
|
||||
|
||||
static inline bool ow_sample_line(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
return (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the 1-wire bus
|
||||
*/
|
||||
bool ow_reset(Unit *unit)
|
||||
{
|
||||
ow_pull_low(unit);
|
||||
PTIM_MicroDelay(500);
|
||||
|
||||
bool presence;
|
||||
vPortEnterCritical();
|
||||
{
|
||||
// Strong pull-up (for parasitive power)
|
||||
ow_pull_high(unit);
|
||||
PTIM_MicroDelay(2);
|
||||
|
||||
// switch to open-drain
|
||||
ow_release_line(unit);
|
||||
PTIM_MicroDelay(118);
|
||||
|
||||
presence = !ow_sample_line(unit);
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
PTIM_MicroDelay(130);
|
||||
return presence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a bit to the 1-wire bus
|
||||
*/
|
||||
void ow_write_bit(Unit *unit, bool bit)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
{
|
||||
// start mark
|
||||
ow_pull_low(unit);
|
||||
PTIM_MicroDelay(2);
|
||||
|
||||
if (bit) ow_pull_high(unit);
|
||||
PTIM_MicroDelay(70);
|
||||
|
||||
// Strong pull-up (for parasitive power)
|
||||
ow_pull_high(unit);
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
PTIM_MicroDelay(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a bit from the 1-wire bus
|
||||
*/
|
||||
bool ow_read_bit(Unit *unit)
|
||||
{
|
||||
bool bit;
|
||||
|
||||
vPortEnterCritical();
|
||||
{
|
||||
// start mark
|
||||
ow_pull_low(unit);
|
||||
PTIM_MicroDelay(2);
|
||||
|
||||
ow_release_line(unit);
|
||||
PTIM_MicroDelay(20);
|
||||
|
||||
bit = ow_sample_line(unit);
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
PTIM_MicroDelay(40);
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u8(Unit *unit, uint8_t byte)
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ow_write_bit(unit, 0 != (byte & (1 << i)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a halfword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u16(Unit *unit, uint16_t halfword)
|
||||
{
|
||||
ow_write_u8(unit, (uint8_t) (halfword & 0xFF));
|
||||
ow_write_u8(unit, (uint8_t) ((halfword >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a word to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u32(Unit *unit, uint32_t word)
|
||||
{
|
||||
ow_write_u16(unit, (uint16_t) (word));
|
||||
ow_write_u16(unit, (uint16_t) (word >> 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a doubleword to the 1-wire bus
|
||||
*/
|
||||
void ow_write_u64(Unit *unit, uint64_t dword)
|
||||
{
|
||||
ow_write_u32(unit, (uint32_t) (dword));
|
||||
ow_write_u32(unit, (uint32_t) (dword >> 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte form the 1-wire bus
|
||||
*/
|
||||
uint8_t ow_read_u8(Unit *unit)
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
buf |= (1 & ow_read_bit(unit)) << i;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a halfword form the 1-wire bus
|
||||
*/
|
||||
uint16_t ow_read_u16(Unit *unit)
|
||||
{
|
||||
uint16_t acu = 0;
|
||||
acu |= ow_read_u8(unit);
|
||||
acu |= ow_read_u8(unit) << 8;
|
||||
return acu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a word form the 1-wire bus
|
||||
*/
|
||||
uint32_t ow_read_u32(Unit *unit)
|
||||
{
|
||||
uint32_t acu = 0;
|
||||
acu |= ow_read_u16(unit);
|
||||
acu |= (uint32_t)ow_read_u16(unit) << 16;
|
||||
return acu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a doubleword form the 1-wire bus
|
||||
*/
|
||||
uint64_t ow_read_u64(Unit *unit)
|
||||
{
|
||||
uint64_t acu = 0;
|
||||
acu |= ow_read_u32(unit);
|
||||
acu |= (uint64_t)ow_read_u32(unit) << 32;
|
||||
return acu;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/01.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_OW_LOW_LEVEL_H
|
||||
#define GEX_F072_OW_LOW_LEVEL_H
|
||||
|
||||
#ifndef OW_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "_ow_low_level.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, uint32_t len);
|
||||
|
||||
/**
|
||||
* 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,129 @@
|
||||
//
|
||||
// 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_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->error = E_SUCCESS;
|
||||
state->command = command;
|
||||
state->first = true;
|
||||
state->test_checksums = test_checksums;
|
||||
}
|
||||
|
||||
uint32_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint32_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;
|
||||
|
||||
uint32_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;
|
||||
state->error = E_HW_TIMEOUT;
|
||||
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;
|
||||
state->error = E_BUS_FAULT;
|
||||
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) {
|
||||
if (0 != ow_checksum(code, 8)) {
|
||||
state->status = OW_SEARCH_FAILED;
|
||||
state->error = E_CHECKSUM_MISMATCH;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// 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,83 @@
|
||||
//
|
||||
// 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;
|
||||
error_t error;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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`,
|
||||
* possible error code in `status->error`
|
||||
*/
|
||||
uint32_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint32_t capacity);
|
||||
|
||||
#endif //GEX_F072_OW_SEARCH_H
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void OW_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->port_name = pp_char(pp);
|
||||
priv->pin_number = pp_u8(pp);
|
||||
priv->parasitic = pp_bool(pp);
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void OW_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 0); // version
|
||||
|
||||
pb_char(pb, priv->port_name);
|
||||
pb_u8(pb, priv->pin_number);
|
||||
pb_bool(pb, priv->parasitic);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t OW_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "pin")) {
|
||||
suc = cfg_portpin_parse(value, &priv->port_name, &priv->pin_number);
|
||||
}
|
||||
else if (streq(key, "parasitic")) {
|
||||
priv->parasitic = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else {
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
if (!suc) return E_BAD_VALUE;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void OW_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Data pin");
|
||||
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
||||
|
||||
iw_comment(iw, "Parasitic (bus-powered) mode");
|
||||
iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/01/29.
|
||||
//
|
||||
|
||||
#include "comm/messages.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_1wire.h"
|
||||
|
||||
// 1WIRE master
|
||||
#define OW_INTERNAL
|
||||
#include "_ow_internal.h"
|
||||
#include "_ow_low_level.h"
|
||||
|
||||
/** Callback for sending a poll_ready success / failure report */
|
||||
static void OW_TimerRespCb(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
assert_param(unit);
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
bool success = (bool) job->data1;
|
||||
|
||||
if (success) {
|
||||
com_respond_ok(priv->busyRequestId);
|
||||
} else {
|
||||
com_respond_error(priv->busyRequestId, E_HW_TIMEOUT);
|
||||
}
|
||||
priv->busy = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1-Wire timer callback, used for the 'wait_ready' function.
|
||||
*
|
||||
* - In parasitic mode, this is a simple 750ms wait, after which a SUCCESS response is sent.
|
||||
* - In 3-wire mode, the callback is fired periodically and performs a Read operation on the bus.
|
||||
* The unit responds with 0 while the operation is ongoing. On receiving 1 a SUCCESS response is sent.
|
||||
* The polling is abandoned after a timeout, sending a TIMEOUT response.
|
||||
*
|
||||
* @param xTimer
|
||||
*/
|
||||
void OW_tickHandler(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
if(!priv->busy) {
|
||||
dbg("ow tick should be disabled now!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->parasitic) {
|
||||
// this is the end of the 750ms measurement time
|
||||
goto halt_ok;
|
||||
} else {
|
||||
bool ready = ow_read_bit(unit);
|
||||
if (ready) {
|
||||
goto halt_ok;
|
||||
}
|
||||
|
||||
uint32_t time = PTIM_GetTime();
|
||||
if (time - priv->busyStart > 1000) {
|
||||
unit->tick_interval = 0;
|
||||
unit->_tick_cnt = 0;
|
||||
|
||||
Job j = {
|
||||
.unit = unit,
|
||||
.data1 = 0, // failure
|
||||
.cb = OW_TimerRespCb,
|
||||
};
|
||||
scheduleJob(&j);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
halt_ok:
|
||||
unit->tick_interval = 0;
|
||||
unit->_tick_cnt = 0;
|
||||
|
||||
Job j = {
|
||||
.unit = unit,
|
||||
.data1 = 1, // success
|
||||
.cb = OW_TimerRespCb,
|
||||
};
|
||||
scheduleJob(&j);
|
||||
}
|
||||
|
||||
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_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_WRITE = 10, // write multiple bytes using the SKIP_ROM command
|
||||
CMD_READ = 11, // write multiple bytes using a ROM address
|
||||
|
||||
CMD_POLL_FOR_1 = 20,
|
||||
};
|
||||
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
bool presence;
|
||||
uint64_t addr;
|
||||
uint32_t remain;
|
||||
const uint8_t *tail;
|
||||
|
||||
if (priv->busy) return E_BUSY;
|
||||
|
||||
bool with_alarm = false;
|
||||
bool search_reset = false;
|
||||
|
||||
switch (command) {
|
||||
/**
|
||||
* This is the delay function for DS1820 measurements.
|
||||
*
|
||||
* Parasitic: Returns success after the required 750ms
|
||||
* Non-parasitic: Returns SUCCESS after device responds '1', HW_TIMEOUT after 1s
|
||||
*/
|
||||
case CMD_POLL_FOR_1:
|
||||
// This can't be exposed via the UU API, due to being async
|
||||
unit->_tick_cnt = 0;
|
||||
unit->tick_interval = 750;
|
||||
if (priv->parasitic) {
|
||||
unit->tick_interval = 750;
|
||||
} else {
|
||||
unit->tick_interval = 10;
|
||||
}
|
||||
priv->busy = true;
|
||||
priv->busyStart = PTIM_GetTime();
|
||||
priv->busyRequestId = frame_id;
|
||||
return E_SUCCESS; // We will respond when the timer expires
|
||||
|
||||
/** Search devices with alarm. No payload, restarts the search. */
|
||||
case CMD_SEARCH_ALARM:
|
||||
with_alarm = true;
|
||||
// fall-through
|
||||
/** Search all devices. No payload, restarts the search. */
|
||||
case CMD_SEARCH_ADDR:
|
||||
search_reset = true;
|
||||
// fall-through
|
||||
/** Continue a previously begun search. */
|
||||
case CMD_SEARCH_CONTINUE:;
|
||||
uint32_t found_count = 0;
|
||||
bool have_more = false;
|
||||
if (!search_reset && priv->searchState.status != OW_SEARCH_MORE) {
|
||||
dbg("Search not ongoing!");
|
||||
return E_PROTOCOL_BREACH;
|
||||
}
|
||||
|
||||
TRY(UU_1WIRE_Search(unit, with_alarm, search_reset,
|
||||
(void *) unit_tmp512, UNIT_TMP_LEN/8, &found_count,
|
||||
&have_more));
|
||||
|
||||
// use multipart to avoid allocating extra buffer
|
||||
uint8_t status_code = (uint8_t) have_more;
|
||||
TF_Msg msg = {
|
||||
.frame_id = frame_id,
|
||||
.type = MSG_SUCCESS,
|
||||
.len = (TF_LEN) (found_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, found_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:
|
||||
TRY(UU_1WIRE_CheckPresence(unit, &presence));
|
||||
|
||||
com_respond_u8(frame_id, (uint8_t) presence);
|
||||
return E_SUCCESS;
|
||||
|
||||
/** Read address of the single device on the bus - returns u64 */
|
||||
case CMD_READ_ADDR:
|
||||
TRY(UU_1WIRE_ReadAddress(unit, &addr));
|
||||
|
||||
// build response
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
pb_u64(&pb, addr);
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Write payload to the bus, no confirmation (unless requested).
|
||||
*
|
||||
* Payload:
|
||||
* addr:u64, rest:write_data
|
||||
* if addr is 0, use SKIP_ROM
|
||||
*/
|
||||
case CMD_WRITE:
|
||||
addr = pp_u64(pp);
|
||||
tail = pp_tail(pp, &remain);
|
||||
TRY(UU_1WIRE_Write(unit, addr, tail, remain));
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Write and read.
|
||||
*
|
||||
* Payload:
|
||||
* addr:u64, read_len:u16, rest:write_data
|
||||
* if addr is 0, use SKIP_ROM
|
||||
*/
|
||||
case CMD_READ:
|
||||
addr = pp_u64(pp);
|
||||
uint16_t rcount = pp_u16(pp);
|
||||
bool test_crc = pp_bool(pp);
|
||||
tail = pp_tail(pp, &remain);
|
||||
|
||||
TRY(UU_1WIRE_Read(unit, addr,
|
||||
tail, remain,
|
||||
(uint8_t *) unit_tmp512, rcount,
|
||||
test_crc));
|
||||
|
||||
// build response
|
||||
com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, rcount);
|
||||
return E_SUCCESS;
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Unit template */
|
||||
const UnitDriver UNIT_1WIRE = {
|
||||
.name = "1WIRE",
|
||||
.description = "1-Wire master",
|
||||
// Settings
|
||||
.preInit = OW_preInit,
|
||||
.cfgLoadBinary = OW_loadBinary,
|
||||
.cfgWriteBinary = OW_writeBinary,
|
||||
.cfgLoadIni = OW_loadIni,
|
||||
.cfgWriteIni = OW_writeIni,
|
||||
// Init
|
||||
.init = OW_init,
|
||||
.deInit = OW_deInit,
|
||||
// Function
|
||||
.handleRequest = OW_handleRequest,
|
||||
.updateTick = OW_tickHandler,
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/01/02.
|
||||
//
|
||||
// Dallas 1-Wire master unit
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_UNIT_1WIRE_H
|
||||
#define GEX_F072_UNIT_1WIRE_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_1WIRE;
|
||||
|
||||
/**
|
||||
* Check if there are any units present on the bus
|
||||
*
|
||||
* @param[in,out] unit
|
||||
* @param[out] presence - any devices present
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_1WIRE_CheckPresence(Unit *unit, bool *presence);
|
||||
|
||||
/**
|
||||
* Read a device's address (use only with a single device attached)
|
||||
*
|
||||
* @param[in,out] unit
|
||||
* @param[out] address - the device's address, 0 on error or CRC mismatch
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_1WIRE_ReadAddress(Unit *unit, uint64_t *address);
|
||||
|
||||
/**
|
||||
* Write bytes to a device / devices
|
||||
*
|
||||
* @param[in,out] unit
|
||||
* @param[in] address - device address, 0 to skip match (single device or broadcast)
|
||||
* @param[in] buff - bytes to write
|
||||
* @param[in] len - buffer length
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_1WIRE_Write(Unit *unit, uint64_t address, const uint8_t *buff, uint32_t len);
|
||||
|
||||
/**
|
||||
* Read bytes from a device / devices, first writing a query
|
||||
*
|
||||
* @param[in,out] unit
|
||||
* @param[in] address - device address, 0 to skip match (single device ONLY!)
|
||||
* @param[in] request_buff - bytes to write before reading a response
|
||||
* @param[in] request_len - number of bytes to write
|
||||
* @param[out] response_buff - buffer for storing the read response
|
||||
* @param[in] response_len - number of bytes to read
|
||||
* @param[in] check_crc - verify CRC
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_1WIRE_Read(Unit *unit, uint64_t address,
|
||||
const uint8_t *request_buff, uint32_t request_len,
|
||||
uint8_t *response_buff, uint32_t response_len, bool check_crc);
|
||||
|
||||
/**
|
||||
* Perform a ROM search operation.
|
||||
* The algorithm is on a depth-first search without backtracking,
|
||||
* taking advantage of the open-drain topology.
|
||||
*
|
||||
* This function either starts the search, or continues it.
|
||||
*
|
||||
* @param[in,out] unit
|
||||
* @param[in] with_alarm - true to match only devices in alarm state
|
||||
* @param[in] restart - true to restart the search (search from the lowest address)
|
||||
* @param[out] buffer - buffer for storing found addresses
|
||||
* @param[in] capacity - buffer capacity in address entries (8 bytes)
|
||||
* @param[out] real_count - real number of found addresses (for which the CRC matched)
|
||||
* @param[out] have_more - flag indicating there are more devices to be found
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_1WIRE_Search(Unit *unit, bool with_alarm, bool restart,
|
||||
uint64_t *buffer, uint32_t capacity, uint32_t *real_count,
|
||||
bool *have_more);
|
||||
|
||||
#endif //GEX_F072_UNIT_1WIRE_H
|
||||
Reference in New Issue
Block a user