LCOV - code coverage report
Current view: top level - AP_HAL - Device.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 22 43 51.2 %
Date: 2026-09-09 11:02:08 Functions: 9 23 39.1 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2015-2016  Intel Corporation. All rights reserved.
       3             :  *
       4             :  * This file is free software: you can redistribute it and/or modify it
       5             :  * under the terms of the GNU General Public License as published by the
       6             :  * Free Software Foundation, either version 3 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This file is distributed in the hope that it will be useful, but
      10             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      12             :  * See the GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License along
      15             :  * with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : #pragma once
      18             : 
      19             : #include <inttypes.h>
      20             : 
      21             : #include "AP_HAL_Namespace.h"
      22             : #include "utility/functor.h"
      23             : #include "AP_HAL_Boards.h"
      24             : 
      25             : #if CONFIG_HAL_BOARD != HAL_BOARD_QURT
      26             : // we need utility for std::move, but not on QURT due to a include error in hexagon SDK
      27             : #include <utility>
      28             : #endif
      29             : 
      30             : /*
      31             :  * This is an interface abstracting I2C and SPI devices
      32             :  */
      33             : class AP_HAL::Device {
      34             : public:
      35             :     enum BusType {
      36             :         BUS_TYPE_UNKNOWN = 0,
      37             :         BUS_TYPE_I2C     = 1,
      38             :         BUS_TYPE_SPI     = 2,
      39             :         BUS_TYPE_UAVCAN  = 3,
      40             :         BUS_TYPE_SITL    = 4,
      41             :         BUS_TYPE_MSP     = 5,
      42             :         BUS_TYPE_SERIAL  = 6,
      43             :         BUS_TYPE_WSPI    = 7,
      44             :     };
      45             : 
      46             :     enum Speed {
      47             :         SPEED_HIGH,
      48             :         SPEED_LOW,
      49             :     };
      50             : 
      51             :     // Used for comms with devices that support wide SPI
      52             :     // like quad spi
      53             :     struct CommandHeader {
      54             :         uint32_t  cmd; //Command phase data.
      55             :         uint32_t  cfg; //Transfer configuration field.
      56             :         uint32_t  addr; //Address phase data.
      57             :         uint32_t  alt; // Alternate phase data.
      58             :         uint32_t  dummy; // Number of dummy cycles to be inserted.
      59             :     };
      60             : 
      61             :     FUNCTOR_TYPEDEF(PeriodicCb, void);
      62             :     typedef void* PeriodicHandle;
      63             : 
      64             :     // Register Read Write Callback
      65             :     // returns: void parameters: register address, register data, register datasize, direction R:false, W:true
      66             :     FUNCTOR_TYPEDEF(RegisterRWCb, void, uint8_t, uint8_t*, uint32_t, bool);
      67             :     typedef void* RegisterRWHandle;
      68             : 
      69             :     FUNCTOR_TYPEDEF(BankSelectCb, bool, uint8_t);
      70             : 
      71       46288 :     Device(enum BusType type)
      72       46288 :     {
      73       46288 :         _bus_id.devid_s.bus_type = type;
      74       46288 :     }
      75             : 
      76             :     // return bus type
      77           0 :     enum BusType bus_type(void) const {
      78           0 :         return _bus_id.devid_s.bus_type;
      79             :     }
      80             : 
      81             :     // return bus number
      82           1 :     uint8_t bus_num(void) const {
      83           1 :         return _bus_id.devid_s.bus;
      84             :     }
      85             : 
      86             :     // return 24 bit bus identifier
      87          14 :     uint32_t get_bus_id(void) const {
      88          14 :         return _bus_id.devid;
      89             :     }
      90             : 
      91             :     // return address on bus
      92           1 :     uint8_t get_bus_address(void) const {
      93           1 :         return _bus_id.devid_s.address;
      94             :     }
      95             : 
      96             :     // set device type within a device class (eg. AP_COMPASS_TYPE_LSM303D)
      97             :     void set_device_type(uint8_t devtype);
      98             : 
      99       39874 :     virtual ~Device() {
     100       39874 :         delete[] _checked.regs;
     101       39874 :     }
     102             : 
     103             :     /*
     104             :      * Change device address. Note that this is the 7 bit address, it
     105             :      * does not include the bit for read/write. Only works on I2C
     106             :      */
     107           0 :     virtual void set_address(uint8_t address) {};
     108             :     
     109             :     /*
     110             :      * Set the speed of future transfers. Depending on the bus the speed may
     111             :      * be shared for all devices on the same bus.
     112             :      *
     113             :      * Return: true if speed was successfully set or platform doesn't implement
     114             :      * it; false otherwise.
     115             :      */
     116             :     virtual bool set_speed(Speed speed)  = 0;
     117             : 
     118             :     /*
     119             :      * This does a single bus transaction which sends send_len bytes, 
     120             :      * then receives recv_len bytes back from the slave. Operation is
     121             :      * half-duplex independent of bus type.
     122             :      *
     123             :      * Return: true on a successful transfer, false on failure.
     124             :      */
     125             :     virtual bool transfer(const uint8_t *send, uint32_t send_len,
     126             :                           uint8_t *recv, uint32_t recv_len) = 0;
     127             : 
     128             :     /*
     129             :      * Core transfer function. This does a single bus transaction which
     130             :      * sends len bytes and receives len bytes back from the slave.
     131             :      * On full-duplex buses (e.g. SPI), the transfer is full-duplex,
     132             :      * unlike `transfer`.
     133             :      * DMA-optimized on some implementations
     134             :      *
     135             :      * Return: true on a successful transfer, false on failure.
     136             :      */
     137           0 :     virtual bool transfer_fullduplex(uint8_t *send_recv, uint32_t len) {
     138           0 :         return transfer(send_recv, len, send_recv, len);
     139             :     }
     140             : 
     141             :     /*
     142             :      * Sets the required flags before transaction starts
     143             :      * this is to be used by Wide SPI communication interfaces like
     144             :      * Dual/Quad/Octo SPI
     145             :      */
     146           0 :     virtual void set_cmd_header(const CommandHeader& cmd_hdr) {}
     147             : 
     148             :     /*
     149             :      * Sets up peripheral for execution in place mode
     150             :      * Only relevant for Wide SPI setup.
     151             :      */
     152           0 :     virtual bool enter_xip_mode(void** map_ptr) { return false; }
     153           0 :     virtual bool exit_xip_mode() { return false; }
     154             : 
     155             :     /**
     156             :      * Wrapper function over #transfer() to read recv_len registers, starting
     157             :      * by first_reg, into the array pointed by recv. The read flag passed to
     158             :      * #set_read_flag(uint8_t) is ORed with first_reg before performing the
     159             :      * transfer.
     160             :      *
     161             :      * Return: true on a successful transfer, false on failure.
     162             :      */
     163             :     bool read_registers(uint8_t first_reg, uint8_t *recv, uint32_t recv_len);
     164             : 
     165             :     /**
     166             :      * Wrapper function over #transfer() to write a byte to the register reg.
     167             :      * The transfer is done by sending reg and val in that order.
     168             :      *
     169             :      * Return: true on a successful transfer, false on failure.
     170             :      */
     171             :     bool write_register(uint8_t reg, uint8_t val, bool checked=false);
     172             :     
     173             :     /*
     174             :      * Sets a callback to be called when a register is read or written.
     175             :      */
     176           0 :     virtual void set_register_rw_callback(RegisterRWCb register_rw_callback) {
     177           0 :         _register_rw_callback = register_rw_callback;
     178           0 :     }
     179             : 
     180             :     /**
     181             :      * Wrapper function over #transfer() to call bank selection callback
     182             :      * and then invoke the transfer call
     183             :      *
     184             :      * Return: true on a successful transfer, false on failure.
     185             :      */
     186             :     bool transfer_bank(uint8_t bank, const uint8_t *send, uint32_t send_len,
     187             :                           uint8_t *recv, uint32_t recv_len);
     188             : 
     189             :     /**
     190             :      * Wrapper function over #transfer_bank() to read recv_len registers, starting
     191             :      * by first_reg, into the array pointed by recv. The read flag passed to
     192             :      * #set_read_flag(uint8_t) is ORed with first_reg before performing the
     193             :      * transfer.
     194             :      *
     195             :      * Return: true on a successful transfer, false on failure.
     196             :      */
     197             :     bool read_bank_registers(uint8_t bank, uint8_t first_reg, uint8_t *recv, uint32_t recv_len);
     198             : 
     199             :     /**
     200             :      * Wrapper function over #transfer_bank() to write a byte to the register reg.
     201             :      * The transfer is done by sending reg and val in that order.
     202             :      *
     203             :      * Return: true on a successful transfer, false on failure.
     204             :      */
     205             :     bool write_bank_register(uint8_t bank, uint8_t reg, uint8_t val, bool checked=false);
     206             : 
     207             :     /**
     208             :      * set a value for a checked register in a bank
     209             :      */
     210             :     void set_checked_register(uint8_t bank, uint8_t reg, uint8_t val);
     211             : 
     212             :     /**
     213             :      * set a value for a checked register
     214             :      */
     215             :     void set_checked_register(uint8_t reg, uint8_t val);
     216             : 
     217             :     /**
     218             :      * setup for register value checking. Frequency is how often to check registers. If set to 10 then
     219             :      * every 10th call to check_next_register will check a register
     220             :      */
     221             :     bool setup_checked_registers(uint8_t num_regs, uint8_t frequency=10);
     222             : 
     223             :     /**
     224             :      * check next register value for correctness. Return false if value is incorrect
     225             :      * or register checking has not been setup
     226             :      */
     227             :     bool check_next_register(void);
     228             : 
     229             :     // checked registers
     230             :     struct checkreg {
     231             :         uint8_t bank;
     232             :         uint8_t regnum;
     233             :         uint8_t value;
     234             :     };
     235             :     
     236             :     /**
     237             :      * check next register value for correctness, with return of
     238             :      * failure value. Return false if value is incorrect or register
     239             :      * checking has not been setup
     240             :      */
     241             :     bool check_next_register(struct checkreg &fail);
     242             :     
     243             :     /**
     244             :      * Wrapper function over #transfer() to read a sequence of bytes from
     245             :      * device. No value is written, differently from the #read_registers()
     246             :      * method and hence doesn't include the read flag set by #set_read_flag()
     247             :      */
     248       76858 :     bool read(uint8_t *recv, uint32_t recv_len)
     249             :     {
     250       76858 :         return transfer(nullptr, 0, recv, recv_len);
     251             :     }
     252             : 
     253             :     /*
     254             :      * Get the semaphore for the bus this device is in.  This is intended for
     255             :      * drivers to use during initialization phase only.
     256             :      */
     257             :     virtual AP_HAL::Semaphore *get_semaphore() = 0;
     258             : 
     259             :     /*
     260             :      * Register a periodic callback for this bus. All callbacks on the
     261             :      * same bus are made from the same thread with lock already taken. In
     262             :      * other words, the callback is not executed on the main thread (or the
     263             :      * thread which registered the callback), but in a separate per-bus
     264             :      * thread.
     265             :      *
     266             :      * After registering the periodic callback, the other functions should not
     267             :      * be used anymore from other contexts. If it really needs to be done, the
     268             :      * lock must be taken.
     269             :      *
     270             :      * Return: A handle for this periodic callback. To cancel the callback
     271             :      * call #unregister_callback() or return false on the callback.
     272             :      */
     273             :     virtual PeriodicHandle register_periodic_callback(uint32_t period_usec, PeriodicCb) = 0;
     274             : 
     275             :     /*
     276             :      * Adjust the time for the periodic callback registered with
     277             :      * #register_periodic_callback. Note that the time will be re-calculated
     278             :      * from the moment this call is made and expire after @period_usec.
     279             :      *
     280             :      * Return: true if periodic callback was successfully adjusted, false otherwise.
     281             :      */
     282             :     virtual bool adjust_periodic_callback(PeriodicHandle h, uint32_t period_usec) = 0;
     283             : 
     284             :     /*
     285             :      * Cancel a periodic callback on this bus.
     286             :      *
     287             :      * Return: true if callback was successfully unregistered, false
     288             :      * otherwise.
     289             :      */
     290           0 :     virtual bool unregister_callback(PeriodicHandle h) { return false; }
     291             : 
     292             :     /*
     293             :      * Sets a bank_select callback to be used for bank selection during register check
     294             :      */
     295           0 :     virtual void setup_bankselect_callback(BankSelectCb bank_select) {
     296           0 :         _bank_select = bank_select;
     297           0 :     }
     298             : 
     299             :     /*
     300             :      * Sets a bank_select callback to be used for bank selection during register check
     301             :      */
     302           0 :     virtual void deregister_bankselect_callback() {
     303           0 :         _bank_select = nullptr;
     304           0 :     }
     305             : 
     306             : 
     307             :     /*
     308             :         allows to set callback that will be called after DMA transfer complete.
     309             :         if this callback is set then any read/write operation will return directly after transfer setup and
     310             :         bus semaphore must not be released until register_completion_callback(0) called from callback itself
     311             :     */
     312           0 :     virtual void register_completion_callback(AP_HAL::MemberProc proc) {}
     313           0 :     virtual void register_completion_callback(AP_HAL::Proc proc) {}
     314             :     
     315             :     /*
     316             :      * support for direct control of SPI chip select. Needed for
     317             :      * devices with unusual SPI transfer patterns that include
     318             :      * specific delays
     319             :      */
     320      147198 :     virtual bool set_chip_select(bool set) { return false; }
     321             : 
     322             :     /**
     323             :      * Some devices connected on the I2C or SPI bus require a bit to be set on
     324             :      * the register address in order to perform a read operation. This sets a
     325             :      * flag to be used by #read_registers(). The flag's default value is zero.
     326             :      */
     327             :     void set_read_flag(uint8_t flag);
     328             : 
     329             :     /**
     330             :      * make a bus id given bus type, bus number, bus address and
     331             :      * device type This is for use by devices that do not use one of
     332             :      * the standard HAL Device types, such as UAVCAN devices
     333             :      */
     334             :     static uint32_t make_bus_id(enum BusType bus_type, uint8_t bus, uint8_t address, uint8_t devtype);
     335             : 
     336             :     /**
     337             :      * return a new bus ID for the same bus connection but a new device type.
     338             :      * This is used for auxiliary bus connections
     339             :      */
     340             :     static uint32_t change_bus_id(uint32_t old_id, uint8_t devtype);
     341             : 
     342             :     /**
     343             :      * return bus ID with a new devtype
     344             :      */
     345             :     uint32_t get_bus_id_devtype(uint8_t devtype) const;
     346             : 
     347             :     /**
     348             :      * get bus type
     349             :      */
     350             :     static enum BusType devid_get_bus_type(uint32_t dev_id);
     351             : 
     352             :     static uint8_t devid_get_bus(uint32_t dev_id);
     353             : 
     354             :     static uint8_t devid_get_address(uint32_t dev_id);
     355             : 
     356             :     static uint8_t devid_get_devtype(uint32_t dev_id);
     357             : 
     358             : 
     359             :     /* set number of retries on transfers */
     360           0 :     virtual void set_retries(uint8_t retries) {};
     361             : 
     362             : protected:
     363             :     uint8_t _read_flag = 0;
     364             : 
     365             :     /*
     366             :       broken out device elements. The bitfields are used to keep
     367             :       the overall value small enough to fit in a float accurately,
     368             :       which makes it possible to transport over the MAVLink
     369             :       parameter protocol without loss of information.
     370             :      */
     371             :     struct DeviceStructure {
     372             :         enum BusType bus_type : 3;
     373             :         uint8_t bus: 5;    // which instance of the bus type
     374             :         uint8_t address;   // address on the bus (eg. I2C address)
     375             :         uint8_t devtype;   // device class specific device type
     376             :     };
     377             : 
     378             :     union DeviceId {
     379             :         struct DeviceStructure devid_s;
     380             :         uint32_t devid;
     381             :     };
     382             : 
     383             :     union DeviceId _bus_id;
     384             : 
     385             :     // set device address (eg. i2c bus address or spi CS)
     386       46288 :     void set_device_address(uint8_t address) {
     387       46288 :         _bus_id.devid_s.address = address;
     388       46288 :     }
     389             : 
     390             :     // set device bus number
     391       46288 :     void set_device_bus(uint8_t bus) {
     392       46288 :         _bus_id.devid_s.bus = bus;
     393       46288 :     }
     394             : 
     395             : private:
     396             :     BankSelectCb _bank_select;
     397             :     RegisterRWCb _register_rw_callback;
     398             :     struct {
     399             :         uint8_t n_allocated;
     400             :         uint8_t n_set;
     401             :         uint8_t next;
     402             :         uint8_t frequency;
     403             :         uint8_t counter;
     404             :         struct checkreg last_reg_fail;
     405             :         struct checkreg *regs;
     406             :     } _checked;
     407             : };

Generated by: LCOV version 1.14