Modularization, stage 1

This commit is contained in:
2018-07-07 19:55:21 +02:00
parent e5679e90f8
commit a1fa0821cf
105 changed files with 11851 additions and 268 deletions
+129
View File
@@ -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;
}
+18
View File
@@ -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
+59
View File
@@ -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);
}
+60
View File
@@ -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
+223
View File
@@ -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;
}
+84
View File
@@ -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
+129
View File
@@ -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;
}
+83
View File
@@ -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
+68
View File
@@ -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));
}
+246
View File
@@ -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,
};
+79
View File
@@ -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