LCOV - code coverage report
Current view: top level - AP_HAL_SITL - SPIDevice.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 58 80 72.5 %
Date: 2026-09-09 11:02:08 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2021  Peter Barker. 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             : 
      18             : #include "SPIDevice.h"
      19             : 
      20             : #include <AP_HAL/AP_HAL.h>
      21             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL && !defined(HAL_BUILD_AP_PERIPH)
      22             : 
      23             : #include <SITL/SITL.h>
      24             : 
      25             : extern const AP_HAL::HAL& hal;
      26             : 
      27             : using namespace HALSITL;
      28             : 
      29             : /*
      30             :  * SPIBus
      31             :  */
      32             : class SPIBus {
      33             :     friend class SPIDeviceManager;
      34             : public:
      35             : 
      36           8 :     SPIBus(uint8_t _bus) :
      37           8 :         bus{_bus}
      38           8 :         { }
      39             : 
      40             :     uint8_t bus;
      41             :     Semaphore sem;
      42      263095 :     int ioctl(uint8_t cs_pin, uint8_t ioctl_number, void *data) {
      43      263095 :         return _ioctl(cs_pin, ioctl_number, data);
      44             :     }
      45             :     // void _timer_tick(); // in lieu of a thread-per-bus
      46             :     AP_HAL::Device::PeriodicHandle register_periodic_callback(uint32_t period_usec, AP_HAL::Device::PeriodicCb cb);
      47             : 
      48             :     class SPIBus *next;
      49             : 
      50             : private:
      51             :     int _ioctl(uint8_t cs_pin, uint8_t ioctl_number, void *data);
      52             : 
      53             :     struct callback_info {
      54             :         struct callback_info *next;
      55             :         AP_HAL::Device::PeriodicCb cb;
      56             :         uint32_t period_usec;
      57             :         uint64_t next_usec;
      58             :     } *callbacks;
      59             : 
      60             :     static uint8_t spi_buscount;
      61             : 
      62             : };
      63             : 
      64             : uint8_t SPIBus::spi_buscount;
      65             : 
      66             : // FIXME: do the whole subdev dance here and get an actual FD to do an ioctl on?
      67      263095 : int SPIBus::_ioctl(uint8_t cs_pin, uint8_t ioctl_number, void *data)
      68             : {
      69      263095 :     SITL::SIM *sitl = AP::sitl();
      70      263095 :     return sitl->spi_ioctl(bus, cs_pin, ioctl_number, data);
      71             : }
      72             : 
      73           0 : AP_HAL::Device::PeriodicHandle SPIBus::register_periodic_callback(uint32_t period_usec, AP_HAL::Device::PeriodicCb cb)
      74             : {
      75             :     // mostly swiped from ChibiOS:
      76           0 :     SPIBus::callback_info *callback = NEW_NOTHROW SPIBus::callback_info;
      77           0 :     if (callback == nullptr) {
      78           0 :         return nullptr;
      79             :     }
      80           0 :     callback->cb = cb;
      81           0 :     callback->period_usec = period_usec;
      82           0 :     callback->next_usec = AP_HAL::micros64() + period_usec;
      83             : 
      84             :     // add to linked list of callbacks on thread
      85           0 :     callback->next = callbacks;
      86           0 :     callbacks = callback;
      87           0 :     return callback;
      88             : }
      89             : 
      90             : // void SPIBus::_timer_tick()
      91             : // {
      92             : //     const uint64_t now = AP_HAL::micros64();
      93             : //     for (struct callback_info *ci = callbacks; ci != nullptr; ci = ci->next) {
      94             : //         if (ci->next_usec < now) {
      95             : //             WITH_SEMAPHORE(sem);
      96             : //             ci->cb();
      97             : //             ci->next_usec += ci->period_usec;
      98             : //         }
      99             : //     }
     100             : // }
     101             : 
     102             : /*
     103             :  * SPIDeviceManager
     104             :  */
     105             : SPIBus *SPIDeviceManager::buses;
     106             : 
     107        2145 : SPIDeviceManager::SPIDeviceManager()
     108             : {
     109        2145 : }
     110             : 
     111             : static const struct SPIDriverInfo {
     112             :     // SPIDriver *driver;
     113             :     uint8_t busid; // used for device IDs in parameters
     114             :     // uint8_t dma_channel_rx;
     115             :     // uint8_t dma_channel_tx;
     116             : } spi_devices[] = {
     117             :     { 0, },
     118             :     { 1, },
     119             : };
     120             : 
     121             : // name, bus, cs_pin
     122             : SPIDesc SPIDeviceManager::device_table[] = {
     123             :     { "ramtron", 0, 0 },
     124             :     { "dataflash", 1, 0}
     125             : };
     126             : 
     127             : AP_HAL::SPIDevice *
     128           8 : SPIDeviceManager::get_device_ptr(const char *name)
     129             : {
     130             :     // this was swiped from AP_HAL_ChibiOS
     131             : 
     132             :     /* Find the bus description in the table */
     133             :     uint8_t i;
     134          13 :     for (i = 0; i<ARRAY_SIZE(device_table); i++) {
     135          13 :         if (strcmp(device_table[i].name, name) == 0) {
     136           8 :             break;
     137             :         }
     138             :     }
     139           8 :     if (i == ARRAY_SIZE(device_table)) {
     140           0 :         return nullptr;
     141             :     }
     142             : 
     143           8 :     SPIDesc &desc = device_table[i];
     144             : 
     145             :     // find the bus
     146             :     SPIBus *busp;
     147           8 :     for (busp = buses; busp; busp = (SPIBus *)busp->next) {
     148           0 :         if (busp->bus == desc.bus) {
     149           0 :             break;
     150             :         }
     151             :     }
     152           8 :     if (busp == nullptr) {
     153             :         // create a new one
     154           8 :         busp = NEW_NOTHROW SPIBus(desc.bus);
     155           8 :         if (busp == nullptr) {
     156           0 :             return nullptr;
     157             :         }
     158           8 :         busp->next = buses;
     159           8 :         busp->bus = desc.bus;
     160             : 
     161           8 :         buses = busp;
     162             :     }
     163             : 
     164           8 :     return NEW_NOTHROW SPIDevice(*busp, desc);
     165             : }
     166             : 
     167             : // void SPIDeviceManager::_timer_tick()
     168             : // {
     169             : //     for (auto &bus : buses) {
     170             : //         bus._timer_tick();
     171             : //     }
     172             : // }
     173             : 
     174             : /*
     175             :  * SPIDevice
     176             :  */
     177             : 
     178           8 : SPIDevice::SPIDevice(SPIBus &_bus, SPIDesc &_device_desc)
     179           8 :     : bus(_bus)
     180           8 :     , device_desc(_device_desc)
     181             : {
     182           8 :     if (_bus.bus >= ARRAY_SIZE(spi_devices)) {
     183           0 :         AP_HAL::panic("SPIDevice: bus %u out of range", (unsigned)_bus.bus);
     184             :     }
     185           8 :     set_device_bus(spi_devices[_bus.bus].busid);
     186           8 :     set_device_address(_device_desc.cs_pin);
     187           8 : }
     188             : 
     189         783 : AP_HAL::Semaphore *SPIDevice::get_semaphore()
     190             : {
     191         783 :     return &bus.sem;
     192             : }
     193             : 
     194             : /*
     195             :   low level transfer function - swiped from the Linux HAL
     196             :  */
     197             : // this is copied into the SITL SPI layer
     198             : struct spi_ioc_transfer {
     199             :         uint64_t tx_buf;
     200             :         uint64_t rx_buf;
     201             : 
     202             :         uint32_t len;
     203             :         // uint32_t speed_hz;
     204             : 
     205             :         // uint16_t delay_usecs;
     206             :         // uint8_t bits_per_word;
     207             :         // uint8_t cs_change;
     208             : };
     209             : 
     210             : #define SPI_TRANSACTION_1LONG 17
     211             : #define SPI_TRANSACTION_2LONG 18
     212             : 
     213      263095 : bool SPIDevice::transfer(const uint8_t *send, uint32_t send_len,
     214             :                          uint8_t *recv, uint32_t recv_len)
     215             : {
     216      263095 :     bus.sem.check_owner();
     217             : 
     218      263095 :     struct spi_ioc_transfer msgs[2] = { };
     219      263095 :     unsigned nmsgs = 0;
     220             : 
     221      263095 :     if (send && send_len != 0) {
     222      232035 :         msgs[nmsgs].tx_buf = (uint64_t) send;
     223      232035 :         msgs[nmsgs].rx_buf = 0;
     224      232035 :         msgs[nmsgs].len = send_len;
     225      232035 :         nmsgs++;
     226             :     }
     227             : 
     228      263095 :     if (recv && recv_len != 0) {
     229      104073 :         msgs[nmsgs].tx_buf = 0;
     230      104073 :         msgs[nmsgs].rx_buf = (uint64_t) recv;
     231      104073 :         msgs[nmsgs].len = recv_len;
     232      104073 :         nmsgs++;
     233             :     }
     234             : 
     235      263095 :     if (!nmsgs) {
     236           0 :         return false;
     237             :     }
     238             : 
     239             :     uint8_t ioctl_number;
     240      263095 :     switch (nmsgs) {
     241      190082 :     case 1:
     242      190082 :         ioctl_number = SPI_TRANSACTION_1LONG;
     243      190082 :         break;
     244       73013 :     case 2:
     245       73013 :         ioctl_number = SPI_TRANSACTION_2LONG;
     246       73013 :         break;
     247           0 :     default:
     248           0 :         abort();
     249             :     }
     250      263095 :     const int r = bus.ioctl(device_desc.cs_pin, ioctl_number, &msgs);
     251             : 
     252      263095 :     if (r == -1) {
     253           0 :         hal.console->printf("SPIDevice: error transferring data\n");
     254           0 :         return false;
     255             :     }
     256             : 
     257      263095 :     return true;
     258             : }
     259             : 
     260           0 : AP_HAL::Device::PeriodicHandle SPIDevice::register_periodic_callback(uint32_t period_usec, AP_HAL::Device::PeriodicCb cb)
     261             : {
     262           0 :     return bus.register_periodic_callback(period_usec, cb);
     263             : }
     264             : 
     265             : #endif // HAL_BOARD_SITL

Generated by: LCOV version 1.14