Skip to content

Commit

Permalink
refactor the whole thing to get rid of static-ness. also clang examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ladyada committed Jan 8, 2025
1 parent cc66c42 commit 8a32dc7
Show file tree
Hide file tree
Showing 12 changed files with 410 additions and 301 deletions.
60 changes: 32 additions & 28 deletions Adafruit_GenericDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,77 @@

#include "Adafruit_GenericDevice.h"

/*! @brief Create a Generic device with the provided read/write functions
@param read_func Function pointer for reading raw data
@param write_func Function pointer for writing raw data
@param readreg_func Function pointer for reading registers (optional)
@param writereg_func Function pointer for writing registers (optional) */
/*!
* @brief Create a Generic device with the provided read/write functions
* @param obj Pointer to object instance
* @param read_func Function pointer for reading raw data
* @param write_func Function pointer for writing raw data
* @param readreg_func Function pointer for reading registers (optional)
* @param writereg_func Function pointer for writing registers (optional) */
Adafruit_GenericDevice::Adafruit_GenericDevice(
busio_genericdevice_read_t read_func,
void *obj, busio_genericdevice_read_t read_func,
busio_genericdevice_write_t write_func,
busio_genericdevice_readreg_t readreg_func,
busio_genericdevice_writereg_t writereg_func) {
_obj = obj;
_read_func = read_func;
_write_func = write_func;
_readreg_func = readreg_func;
_writereg_func = writereg_func;
_begun = false;
}

/*! @brief Initializes the device
@return true if initialization was successful, otherwise false */
/*! @brief Simple begin function (doesn't do much at this time)
@return true always
*/
bool Adafruit_GenericDevice::begin(void) {
_begun = true;
return true;
}

/*! @brief Write a buffer of data
@param buffer Pointer to buffer of data to write
@param len Number of bytes to write
@return true if write was successful, otherwise false */
@param buffer Pointer to buffer of data to write
@param len Number of bytes to write
@return true if write was successful, otherwise false */
bool Adafruit_GenericDevice::write(const uint8_t *buffer, size_t len) {
if (!_begun)
return false;
return _write_func(buffer, len);
return _write_func(_obj, buffer, len);
}

/*! @brief Read data into a buffer
@param buffer Pointer to buffer to read data into
@param len Number of bytes to read
@return true if read was successful, otherwise false */
@param buffer Pointer to buffer to read data into
@param len Number of bytes to read
@return true if read was successful, otherwise false */
bool Adafruit_GenericDevice::read(uint8_t *buffer, size_t len) {
if (!_begun)
return false;
return _read_func(buffer, len);
return _read_func(_obj, buffer, len);
}

/*! @brief Read from a register location
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer to store read data
@param bufsiz Size of data to read in bytes
@return true if read was successful, otherwise false */
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer to store read data
@param bufsiz Size of data to read in bytes
@return true if read was successful, otherwise false */
bool Adafruit_GenericDevice::readRegister(uint8_t *addr_buf, uint8_t addrsiz,
uint8_t *buf, uint16_t bufsiz) {
if (!_begun || !_readreg_func)
return false;
return _readreg_func(addr_buf, addrsiz, buf, bufsiz);
return _readreg_func(_obj, addr_buf, addrsiz, buf, bufsiz);
}

/*! @brief Write to a register location
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer containing data to write
@param bufsiz Size of data to write in bytes
@return true if write was successful, otherwise false */
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer containing data to write
@param bufsiz Size of data to write in bytes
@return true if write was successful, otherwise false */
bool Adafruit_GenericDevice::writeRegister(uint8_t *addr_buf, uint8_t addrsiz,
const uint8_t *buf,
uint16_t bufsiz) {
if (!_begun || !_writereg_func)
return false;
return _writereg_func(addr_buf, addrsiz, buf, bufsiz);
return _writereg_func(_obj, addr_buf, addrsiz, buf, bufsiz);
}
23 changes: 14 additions & 9 deletions Adafruit_GenericDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@

#include <Arduino.h>

typedef bool (*busio_genericdevice_read_t)(uint8_t *buffer, size_t len);
typedef bool (*busio_genericdevice_write_t)(const uint8_t *buffer, size_t len);
typedef bool (*busio_genericdevice_readreg_t)(uint8_t *addr_buf,
uint8_t addrsiz, uint8_t *buf,
uint16_t bufsiz);
typedef bool (*busio_genericdevice_writereg_t)(uint8_t *addr_buf,
typedef bool (*busio_genericdevice_read_t)(void *obj, uint8_t *buffer,
size_t len);
typedef bool (*busio_genericdevice_write_t)(void *obj, const uint8_t *buffer,
size_t len);
typedef bool (*busio_genericdevice_readreg_t)(void *obj, uint8_t *addr_buf,
uint8_t addrsiz, uint8_t *data,
uint16_t datalen);
typedef bool (*busio_genericdevice_writereg_t)(void *obj, uint8_t *addr_buf,
uint8_t addrsiz,
const uint8_t *buf,
uint16_t bufsiz);
const uint8_t *data,
uint16_t datalen);

/*!
* @brief Class for communicating with a device via generic read/write functions
*/
class Adafruit_GenericDevice {
public:
Adafruit_GenericDevice(
busio_genericdevice_read_t read_func,
void *obj, busio_genericdevice_read_t read_func,
busio_genericdevice_write_t write_func,
busio_genericdevice_readreg_t readreg_func = nullptr,
busio_genericdevice_writereg_t writereg_func = nullptr);
Expand All @@ -45,6 +47,9 @@ class Adafruit_GenericDevice {

bool _begun; ///< whether we have initialized yet (in case the function needs
///< to do something)

private:
void *_obj; ///< Pointer to object instance
};

#endif // ADAFRUIT_GENERICDEVICE_H
97 changes: 35 additions & 62 deletions examples/genericdevice_uartregtest/genericdevice_uartregtest.ino
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/*
Advanced example of using bstracted transport for reading and writing
Advanced example of using bstracted transport for reading and writing
register data from a UART-based device such as a TMC2209
Written with help by Claude! https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c
(at this time chats are not shareable :(
Written with help by Claude!
https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c (at this time
chats are not shareable :(
*/


#include "Adafruit_BusIO_Register.h"
#include "Adafruit_GenericDevice.h"

// Debugging macros
//#define DEBUG_SERIAL Serial
#define DEBUG_SERIAL Serial

#ifdef DEBUG_SERIAL
#define DEBUG_PRINT(x) DEBUG_SERIAL.print(x)
Expand All @@ -29,36 +29,17 @@
#define DEBUG_PRINT_HEX(x)
#endif

// Add IOIN register definition
#define TMC2209_IOIN 0x06

class TMC2209_UART {
private:
static TMC2209_UART *_instance;
Stream *_uart_stream;
uint8_t _addr;

static bool uart_read_impl(uint8_t *buffer, size_t len) {
return _instance->uart_read_fn(buffer, len);
}

static bool uart_write_impl(const uint8_t *buffer, size_t len) {
return _instance->uart_write_fn(buffer, len);
}

static bool uart_readreg_impl(uint8_t *addr_buf, uint8_t addrsiz,
uint8_t *data, uint16_t datalen) {
return _instance->uart_readreg_fn(addr_buf, addrsiz, data, datalen);
}

static bool uart_writereg_impl(uint8_t *addr_buf, uint8_t addrsiz,
const uint8_t *data, uint16_t datalen) {
return _instance->uart_writereg_fn(addr_buf, addrsiz, data, datalen);
}

bool uart_read_fn(uint8_t *buffer, size_t len) {
static bool uart_read(void *thiz, uint8_t *buffer, size_t len) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
uint16_t timeout = 100;
while (_uart_stream->available() < len && timeout--) {
while (dev->_uart_stream->available() < len && timeout--) {
delay(1);
}
if (timeout == 0) {
Expand All @@ -68,39 +49,41 @@ private:

DEBUG_PRINT("Reading: ");
for (size_t i = 0; i < len; i++) {
buffer[i] = _uart_stream->read();
buffer[i] = dev->_uart_stream->read();
DEBUG_PRINT_HEX(buffer[i]);
}
DEBUG_PRINTLN("");

return true;
}

bool uart_write_fn(const uint8_t *buffer, size_t len) {
static bool uart_write(void *thiz, const uint8_t *buffer, size_t len) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
DEBUG_PRINT("Writing: ");
for (size_t i = 0; i < len; i++) {
DEBUG_PRINT_HEX(buffer[i]);
}
DEBUG_PRINTLN("");

_uart_stream->write(buffer, len);
dev->_uart_stream->write(buffer, len);
return true;
}

bool uart_readreg_fn(uint8_t *addr_buf, uint8_t addrsiz, uint8_t *data,
uint16_t datalen) {
while (_uart_stream->available())
_uart_stream->read();
static bool uart_readreg(void *thiz, uint8_t *addr_buf, uint8_t addrsiz,
uint8_t *data, uint16_t datalen) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
while (dev->_uart_stream->available())
dev->_uart_stream->read();

uint8_t packet[4] = {0x05, uint8_t(_addr << 1), addr_buf[0], 0x00};
uint8_t packet[4] = {0x05, uint8_t(dev->_addr << 1), addr_buf[0], 0x00};

packet[3] = calcCRC(packet, 3);
if (!uart_write_impl(packet, 4))
if (!uart_write(thiz, packet, 4))
return false;

// Read back echo
uint8_t echo[4];
if (!uart_read_impl(echo, 4))
if (!uart_read(thiz, echo, 4))
return false;

// Verify echo
Expand All @@ -112,7 +95,7 @@ private:
}

uint8_t response[8]; // sync + 0xFF + reg + 4 data bytes + CRC
if (!uart_read_impl(response, 8))
if (!uart_read(thiz, response, 8))
return false;

// Verify response
Expand All @@ -121,38 +104,34 @@ private:
return false;
}

// Verify 0xFF address byte
if (response[1] != 0xFF) {
DEBUG_PRINTLN("Invalid reply address");
return false;
}

// Verify register address matches our request
if (response[2] != addr_buf[0]) {
DEBUG_PRINTLN("Register mismatch");
return false;
}

// Verify CRC
uint8_t crc = calcCRC(response, 7); // Calculate CRC of all but last byte
uint8_t crc = calcCRC(response, 7);
if (crc != response[7]) {
DEBUG_PRINTLN("CRC mismatch");
return false;
}

// Copy the data bytes
memcpy(data, &response[3], 4);

return true;
}

bool uart_writereg_fn(uint8_t *addr_buf, uint8_t addrsiz, const uint8_t *data,
uint16_t datalen) {
while (_uart_stream->available())
_uart_stream->read();
static bool uart_writereg(void *thiz, uint8_t *addr_buf, uint8_t addrsiz,
const uint8_t *data, uint16_t datalen) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
while (dev->_uart_stream->available())
dev->_uart_stream->read();

uint8_t packet[8] = {0x05,
uint8_t(_addr << 1),
uint8_t(dev->_addr << 1),
uint8_t(addr_buf[0] | 0x80),
data[0],
data[1],
Expand All @@ -161,15 +140,13 @@ private:
0x00};

packet[7] = calcCRC(packet, 7);
if (!uart_write_impl(packet, 8))
if (!uart_write(thiz, packet, 8))
return false;

// Read and verify echo
uint8_t echo[8];
if (!uart_read_impl(echo, 8))
if (!uart_read(thiz, echo, 8))
return false;

// Verify echo matches what we sent
for (uint8_t i = 0; i < 8; i++) {
if (echo[i] != packet[i]) {
DEBUG_PRINTLN("Write echo mismatch");
Expand Down Expand Up @@ -198,18 +175,14 @@ private:

public:
TMC2209_UART(Stream *serial, uint8_t addr)
: _uart_stream(serial), _addr(addr) {
_instance = this;
}
: _uart_stream(serial), _addr(addr) {}

Adafruit_GenericDevice *createDevice() {
return new Adafruit_GenericDevice(uart_read_impl, uart_write_impl,
uart_readreg_impl, uart_writereg_impl);
return new Adafruit_GenericDevice(this, uart_read, uart_write, uart_readreg,
uart_writereg);
}
};

TMC2209_UART *TMC2209_UART::_instance = nullptr;

void setup() {
Serial.begin(115200);
while (!Serial)
Expand All @@ -232,7 +205,7 @@ void setup() {
Serial.print("IOIN = 0x");
Serial.println(ioin_reg.read(), HEX);

// Create RegisterBits for VERSION field (bits 28:24)
// Create RegisterBits for VERSION field (bits 31:24)
Adafruit_BusIO_RegisterBits version_bits(
&ioin_reg, 8, 24); // 8 bits wide, starting at bit 24

Expand All @@ -243,4 +216,4 @@ void setup() {
Serial.println(version, HEX);
}

void loop() { delay(1000); }
void loop() { delay(1000); }
Loading

0 comments on commit 8a32dc7

Please sign in to comment.