2021-01-28 09:09:11 +01:00

278 lines
8.2 KiB
C++

/****************************************************************************
*
* Copyright (c) 2012-2017 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file Device.hpp
*
* Definitions for the generic base classes in the device framework.
*/
#ifndef _DEVICE_DEVICE_HPP
#define _DEVICE_DEVICE_HPP
/*
* Includes here should only cover the needs of the framework definitions.
*/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/posix.h>
#include <drivers/drv_sensor.h>
#define DEVICE_LOG(FMT, ...) PX4_LOG_NAMED(_name, FMT, ##__VA_ARGS__)
#define DEVICE_DEBUG(FMT, ...) PX4_LOG_NAMED_COND(_name, _debug_enabled, FMT, ##__VA_ARGS__)
/**
* Namespace encapsulating all device framework classes, functions and data.
*/
namespace device
{
/**
* Fundamental base class for all physical drivers (I2C, SPI).
*
* This class provides the basic driver template for I2C and SPI devices
*/
class __EXPORT Device
{
public:
// no copy, assignment, move, move assignment
Device(const Device &) = delete;
Device &operator=(const Device &) = delete;
Device(Device &&) = delete;
Device &operator=(Device &&) = delete;
/**
* Destructor.
*
* Public so that anonymous devices can be destroyed.
*/
virtual ~Device() = default;
/*
* Direct access methods.
*/
/**
* Initialise the driver and make it ready for use.
*
* @return OK if the driver initialized OK, negative errno otherwise;
*/
virtual int init() { return PX4_OK; }
/**
* Read directly from the device.
*
* The actual size of each unit quantity is device-specific.
*
* @param offset The device address at which to start reading
* @param data The buffer into which the read values should be placed.
* @param count The number of items to read.
* @return The number of items read on success, negative errno otherwise.
*/
virtual int read(unsigned address, void *data, unsigned count) { return -ENODEV; }
/**
* Write directly to the device.
*
* The actual size of each unit quantity is device-specific.
*
* @param address The device address at which to start writing.
* @param data The buffer from which values should be read.
* @param count The number of items to write.
* @return The number of items written on success, negative errno otherwise.
*/
virtual int write(unsigned address, void *data, unsigned count) { return -ENODEV; }
/**
* Read a register from the device.
*
* @param The register to read.
* @return The value that was read.
*/
virtual uint8_t read_reg(unsigned reg) { return -ENODEV; }
/**
* Write a register in the device.
*
* @param reg The register to write.
* @param value The new value to write.
* @return OK on success, negative errno otherwise.
*/
virtual int write_reg(unsigned reg, uint8_t value) { return -ENODEV; }
/**
* Perform a device-specific operation.
*
* @param operation The operation to perform.
* @param arg An argument to the operation.
* @return Negative errno on error, OK or positive value on success.
*/
virtual int ioctl(unsigned operation, unsigned &arg) { return -ENODEV; }
/** Device bus types for DEVID */
enum DeviceBusType {
DeviceBusType_UNKNOWN = 0,
DeviceBusType_I2C = 1,
DeviceBusType_SPI = 2,
DeviceBusType_UAVCAN = 3,
DeviceBusType_SIMULATION = 4,
DeviceBusType_SERIAL = 5,
DeviceBusType_MAVLINK = 6,
};
/*
broken out device elements. The bitfields are used to keep
the overall value small enough to fit in a float accurately,
which makes it possible to transport over the MAVLink
parameter protocol without loss of information.
*/
struct DeviceStructure {
DeviceBusType bus_type : 3;
uint8_t bus: 5; // which instance of the bus type
uint8_t address; // address on the bus (eg. I2C address)
uint8_t devtype; // device class specific device type
};
union DeviceId {
struct DeviceStructure devid_s;
uint32_t devid;
};
uint32_t get_device_id() const { return _device_id.devid; }
/**
* Return the bus type the device is connected to.
*
* @return The bus type
*/
DeviceBusType get_device_bus_type() const { return _device_id.devid_s.bus_type; }
void set_device_bus_type(DeviceBusType bus_type) { _device_id.devid_s.bus_type = bus_type; }
static const char *get_device_bus_string(DeviceBusType bus)
{
switch (bus) {
case DeviceBusType_I2C:
return "I2C";
case DeviceBusType_SPI:
return "SPI";
case DeviceBusType_UAVCAN:
return "UAVCAN";
case DeviceBusType_SIMULATION:
return "SIMULATION";
case DeviceBusType_SERIAL:
return "SERIAL";
case DeviceBusType_MAVLINK:
return "MAVLINK";
case DeviceBusType_UNKNOWN:
default:
return "UNKNOWN";
}
}
/**
* Return the bus ID the device is connected to.
*
* @return The bus ID
*/
uint8_t get_device_bus() const { return _device_id.devid_s.bus; }
void set_device_bus(uint8_t bus) { _device_id.devid_s.bus = bus; }
/**
* Return the bus address of the device.
*
* @return The bus address
*/
uint8_t get_device_address() const { return _device_id.devid_s.address; }
void set_device_address(int address) { _device_id.devid_s.address = address; }
/**
* Return the device type
*
* @return The device type
*/
uint8_t get_device_type() const { return _device_id.devid_s.devtype; }
void set_device_type(uint8_t devtype) { _device_id.devid_s.devtype = devtype; }
/**
* Print decoded device id string to a buffer.
*
* @param buffer buffer to write to
* @param length buffer length
* @param id The device id.
* @param return number of bytes written
*/
static int device_id_print_buffer(char *buffer, int length, uint32_t id)
{
DeviceId dev_id{};
dev_id.devid = id;
int num_written = snprintf(buffer, length, "Type: 0x%02X, %s:%d (0x%02X)", dev_id.devid_s.devtype,
get_device_bus_string(dev_id.devid_s.bus_type), dev_id.devid_s.bus, dev_id.devid_s.address);
buffer[length - 1] = 0; // ensure 0-termination
return num_written;
}
virtual bool external() const { return false; }
protected:
union DeviceId _device_id {}; /**< device identifier information */
const char *_name{nullptr}; /**< driver name */
bool _debug_enabled{false}; /**< if true, debug messages are printed */
Device() = delete;
explicit Device(const char *name) : _name(name) {}
Device(uint8_t devtype, const char *name, DeviceBusType bus_type, uint8_t bus, uint8_t address) : _name(name)
{
set_device_type(devtype);
_device_id.devid_s.bus_type = bus_type;
_device_id.devid_s.bus = bus;
set_device_address(address);
}
};
} // namespace device
#endif /* _DEVICE_DEVICE_HPP */