LCOV - code coverage report
Current view: top level - AP_Scripting - AP_Scripting_helpers.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 48 250 19.2 %
Date: 2026-09-09 11:02:08 Functions: 5 18 27.8 %

          Line data    Source code
       1             : #include "AP_Scripting_config.h"
       2             : 
       3             : #if AP_SCRIPTING_ENABLED
       4             : 
       5             : #include "AP_Scripting_helpers.h"
       6             : #include <AP_Scripting/lua_generated_bindings.h>
       7             : 
       8             : /// Fast param access via pointer helper class
       9             : 
      10             : // Custom lua constructor with optional param name
      11        1912 : int lua_new_Parameter(lua_State *L) {
      12             : 
      13        1912 :     const int args = lua_gettop(L);
      14        1912 :     if (args > 1) {
      15           0 :         return luaL_argerror(L, args, "too many arguments");
      16             :     }
      17        1912 :     const char * name = nullptr;
      18        1912 :     if (args == 1) {
      19        1777 :         name = luaL_checkstring(L, 1);
      20             :     }
      21             : 
      22        1912 :     auto *p = new_Parameter(L);
      23             : 
      24        1912 :     if (args == 0) {
      25             :         // no arguments, nothing to do
      26         135 :         return 1;
      27             :     }
      28             : 
      29        1777 :     if (!p->init(name)) {
      30           7 :         return luaL_error(L, "No parameter: %s", name);
      31             :     }
      32             : 
      33        1770 :     return 1;
      34             : }
      35             : 
      36             : // init by name
      37        1912 : bool Parameter::init(const char *name)
      38             : {
      39        1912 :     vp = AP_Param::find(name, &vtype);
      40        1912 :     if (vp == nullptr) {
      41           7 :         return false;
      42             :     }
      43        1905 :     return true;
      44             : }
      45             : 
      46             : // init by info, to get the value of old params
      47           0 : bool Parameter::init_by_info(uint16_t key, uint32_t group_element, enum ap_var_type type)
      48             : {
      49           0 :     switch (type) {
      50           0 :     case AP_PARAM_INT8:
      51           0 :         vp = NEW_NOTHROW AP_Int8;
      52           0 :         break;
      53           0 :     case AP_PARAM_INT16:
      54           0 :         vp = NEW_NOTHROW AP_Int16;
      55           0 :         break;
      56           0 :     case AP_PARAM_INT32:
      57           0 :         vp = NEW_NOTHROW AP_Int32;
      58           0 :         break;
      59           0 :     case AP_PARAM_FLOAT:
      60           0 :         vp = NEW_NOTHROW AP_Float;
      61           0 :         break;
      62           0 :     default:
      63           0 :         return false;
      64             :     }
      65           0 :     if (vp == nullptr) {
      66           0 :         return false;
      67             :     }
      68           0 :     vtype = type;
      69           0 :     AP_Param::ConversionInfo info = {
      70             :         key,
      71             :         group_element,
      72             :         type,
      73             :         nullptr
      74           0 :     };
      75           0 :     return AP_Param::find_old_parameter(&info, vp);
      76             : }
      77             : 
      78             : // set a value
      79        3855 : bool Parameter::set(float value)
      80             : {
      81        3855 :     if (vp == nullptr) {
      82           0 :         return false;
      83             :     }
      84        3855 :     switch (vtype) {
      85          10 :     case AP_PARAM_INT8:
      86          10 :         ((AP_Int8 *)vp)->set(value);
      87          10 :         return true;
      88           0 :     case AP_PARAM_INT16:
      89           0 :         ((AP_Int16 *)vp)->set(value);
      90           0 :         return true;
      91           0 :     case AP_PARAM_INT32:
      92           0 :         ((AP_Int32 *)vp)->set(value);
      93           0 :         return true;
      94        3845 :     case AP_PARAM_FLOAT:
      95        3845 :         ((AP_Float *)vp)->set(value);
      96        3845 :         return true;
      97           0 :     default:
      98           0 :         break;
      99             :     }
     100             :     // not a supported type
     101           0 :     return false;
     102             : }
     103             : 
     104             : // get value
     105      354665 : bool Parameter::get(float &value)
     106             : {
     107      354665 :     if (vp == nullptr) {
     108           0 :         return false;
     109             :     }
     110      354665 :     switch (vtype) {
     111        4334 :     case AP_PARAM_INT8:
     112        4334 :         value = ((AP_Int8 *)vp)->get();
     113        4334 :         break;
     114       17480 :     case AP_PARAM_INT16:
     115       17480 :         value = ((AP_Int16 *)vp)->get();
     116       17480 :         break;
     117             : 
     118          14 :     case AP_PARAM_INT32:
     119          14 :         value = ((AP_Int32 *)vp)->get();
     120          14 :         break;
     121             : 
     122      332837 :     case AP_PARAM_FLOAT:
     123      332837 :         value = ((AP_Float *)vp)->get();
     124      332837 :         break;
     125             : 
     126           0 :     default:
     127             :         // not a supported type
     128           0 :         return false;
     129             :     }
     130      354665 :     return true;
     131             : }
     132             : 
     133             : // set and save value
     134          15 : bool Parameter::set_and_save(float value)
     135             : {
     136          15 :     if (vp == nullptr) {
     137           0 :         return false;
     138             :     }
     139          15 :     switch (vtype) {
     140           0 :     case AP_PARAM_INT8:
     141           0 :         ((AP_Int8 *)vp)->set_and_save(value);
     142           0 :         return true;
     143           0 :     case AP_PARAM_INT16:
     144           0 :         ((AP_Int16 *)vp)->set_and_save(value);
     145           0 :         return true;
     146           0 :     case AP_PARAM_INT32:
     147           0 :         ((AP_Int32 *)vp)->set_and_save(value);
     148           0 :         return true;
     149          15 :     case AP_PARAM_FLOAT:
     150          15 :         ((AP_Float *)vp)->set_and_save(value);
     151          15 :         return true;
     152           0 :     default:
     153           0 :         break;
     154             :     }
     155             :     // not a supported type
     156           0 :     return false;
     157             : }
     158             : 
     159             : // Check if param had been configured
     160           0 : bool Parameter::configured()
     161             : {
     162           0 :     if (vp == nullptr) {
     163           0 :         return false;
     164             :     }
     165           0 :     return vp->configured();
     166             : }
     167             : 
     168             : // set default value
     169           0 : bool Parameter::set_default(float value)
     170             : {
     171           0 :     if (vp == nullptr) {
     172           0 :         return false;
     173             :     }
     174           0 :     switch (vtype) {
     175           0 :     case AP_PARAM_INT8:
     176           0 :         ((AP_Int8 *)vp)->set_default(value);
     177           0 :         return true;
     178           0 :     case AP_PARAM_INT16:
     179           0 :         ((AP_Int16 *)vp)->set_default(value);
     180           0 :         return true;
     181           0 :     case AP_PARAM_INT32:
     182           0 :         ((AP_Int32 *)vp)->set_default(value);
     183           0 :         return true;
     184           0 :     case AP_PARAM_FLOAT:
     185           0 :         ((AP_Float *)vp)->set_default(value);
     186           0 :         return true;
     187           0 :     default:
     188           0 :         break;
     189             :     }
     190             :     // not a supported type
     191           0 :     return false;
     192             : }
     193             : 
     194             : #if HAL_ENABLE_DRONECAN_DRIVERS
     195             : 
     196             : #define IFACE_ALL uint8_t(((1U<<(HAL_NUM_CAN_IFACES))-1U))
     197             : 
     198             : /************************************************
     199             :   DroneCAN broadcast and request message handling
     200             :  ************************************************/
     201             : 
     202             : /*
     203             :   broadcast a message, takes a lua string as payload
     204             :  */
     205           0 : int DroneCAN_Handle::broadcast(lua_State *L)
     206             : {
     207           0 :     binding_argcheck(L, 2);
     208             : 
     209           0 :     DroneCAN_Handle *h = check_DroneCAN_Handle(L, 1);
     210             : 
     211             :     size_t data_length;
     212           0 :     const void *data = luaL_checklstring(L, 2, &data_length);
     213             :     
     214           0 :     auto &iface = h->dc->get_canard_iface();
     215             :     Canard::Transfer transfer;
     216             : 
     217           0 :     transfer.transfer_type = CanardTransferTypeBroadcast;
     218           0 :     transfer.data_type_signature = h->signature;
     219           0 :     transfer.data_type_id = h->data_type;
     220           0 :     transfer.inout_transfer_id = &h->transfer_id;
     221           0 :     transfer.priority = 0;
     222           0 :     transfer.payload = data;
     223           0 :     transfer.payload_len = data_length;
     224           0 :     transfer.iface_mask = IFACE_ALL;
     225             : #if CANARD_ENABLE_CANFD
     226           0 :     transfer.canfd = h->canfd;
     227             : #endif
     228           0 :     transfer.timeout_ms = 10;
     229             : 
     230           0 :     bool ok = iface.broadcast(transfer);
     231           0 :     lua_pushboolean(L, ok);
     232             : 
     233           0 :     return 1;
     234             : }
     235             : 
     236             : /*
     237             :   send a request message that expects a reply
     238             :  */
     239           0 : int DroneCAN_Handle::request(lua_State *L)
     240             : {
     241           0 :     binding_argcheck(L, 3);
     242             : 
     243           0 :     DroneCAN_Handle *h = check_DroneCAN_Handle(L, 1);
     244           0 :     uint8_t target_node = luaL_checknumber(L, 2);
     245             : 
     246             :     size_t data_length;
     247           0 :     const void *data = luaL_checklstring(L, 3, &data_length);
     248             : 
     249           0 :     auto &iface = h->dc->get_canard_iface();
     250             : 
     251             :     Canard::Transfer transfer;
     252             : 
     253           0 :     transfer.transfer_type = CanardTransferTypeRequest;
     254           0 :     transfer.data_type_signature = h->signature;
     255           0 :     transfer.data_type_id = h->data_type;
     256           0 :     transfer.inout_transfer_id = &h->transfer_id;
     257           0 :     transfer.priority = 0;
     258           0 :     transfer.payload = data;
     259           0 :     transfer.payload_len = data_length;
     260           0 :     transfer.iface_mask = IFACE_ALL;
     261             : #if CANARD_ENABLE_CANFD
     262           0 :     transfer.canfd = h->canfd;
     263             : #endif
     264           0 :     transfer.timeout_ms = 10;
     265             : 
     266           0 :     WITH_SEMAPHORE(iface.get_sem_rx());
     267             : 
     268           0 :     if (h->subscriber != nullptr) {
     269           0 :         delete h->subscriber;
     270             :     }
     271             :     
     272           0 :     h->subscriber = NEW_NOTHROW Subscriber(*h, CanardTransferTypeResponse);
     273           0 :     bool ok = h->subscriber != nullptr;
     274             : 
     275           0 :     if (ok) {
     276           0 :         h->subscriber->node_id = target_node;
     277           0 :         ok &= iface.request(target_node, transfer);
     278             :     }
     279             : 
     280           0 :     lua_pushboolean(L, ok);
     281             : 
     282           0 :     return 1;
     283           0 : }
     284             : 
     285             : /*
     286             :   subscribe to broadcast messages
     287             :  */
     288           0 : bool DroneCAN_Handle::subscribe(void)
     289             : {
     290           0 :     WITH_SEMAPHORE(dc->get_canard_iface().get_sem_rx());
     291           0 :     if (subscriber != nullptr) {
     292           0 :         delete subscriber;
     293             :     }
     294           0 :     subscriber = NEW_NOTHROW Subscriber(*this, CanardTransferTypeBroadcast);
     295           0 :     return subscriber != nullptr;
     296           0 : }
     297             : 
     298           0 : DroneCAN_Handle::Subscriber::Subscriber(DroneCAN_Handle &_handle, CanardTransferType _transfer_type) :
     299           0 :     Canard::HandlerList(_transfer_type, _handle.data_type, _handle.signature, _handle.dc->get_driver_index())
     300             : {
     301           0 :     handle = &_handle;
     302           0 :     trans_type = _transfer_type;
     303           0 :     link();
     304           0 : }
     305             : 
     306           0 : DroneCAN_Handle::Subscriber::~Subscriber(void)
     307             : {
     308           0 :     unlink();
     309             :     Payload payload;
     310           0 :     while (payloads.pop(payload)) {
     311           0 :         free(payload.data);
     312             :     }
     313           0 : }
     314             : 
     315             : /*
     316             :   handle an incoming subscribed message
     317             :  */
     318           0 : bool DroneCAN_Handle::Subscriber::handle_message(const CanardRxTransfer& transfer)
     319             : {
     320           0 :     if (transfer.transfer_type == CanardTransferTypeResponse &&
     321           0 :         (node_id != transfer.source_node_id ||
     322           0 :          ((transfer.transfer_id+1)&0xFF) != handle->transfer_id)) {
     323             :         // not from right node, or not right transfer ID
     324           0 :         return false;
     325             :     }
     326             : 
     327           0 :     if (payloads.space() == 0) {
     328             :         // already have the max number of messages pending, discard
     329             :         // this one, but return true to say it was for us
     330           0 :         return true;
     331             :     }
     332             :     Payload payload;
     333           0 :     payload.data = (uint8_t *)malloc(transfer.payload_len);
     334           0 :     if (payload.data == nullptr) {
     335             :         // discard messages if we can't allocate
     336             :         // but return true to say it was for us
     337           0 :         return true;
     338             :     }
     339             : 
     340           0 :     payload.length = transfer.payload_len;
     341           0 :     payload.node_id = transfer.source_node_id;
     342           0 :     payload.timestamp = transfer.timestamp_usec;
     343             : #if CANARD_ENABLE_CANFD
     344           0 :     payload.canfd = transfer.canfd;
     345             : #endif
     346             : 
     347           0 :     uint32_t bits_remaining = transfer.payload_len * 8;
     348           0 :     uint32_t ofs = 0;
     349             : 
     350             :     // decode in bytes, we don't have a canardDecodeBuffer function
     351           0 :     while (bits_remaining > 0) {
     352           0 :         uint8_t nbits = MIN(8U, bits_remaining);
     353           0 :         canardDecodeScalar(&transfer, ofs*8, nbits, false, (void*)&payload.data[ofs]);
     354           0 :         ofs++;
     355           0 :         bits_remaining -= nbits;
     356             :     }
     357             : 
     358             :     // push to queue
     359           0 :     payloads.push(payload);
     360             : 
     361           0 :     return true;
     362             : }
     363             : 
     364             : /*
     365             :   check for an incoming message
     366             :  */
     367           0 : int DroneCAN_Handle::check_message(lua_State *L)
     368             : {
     369             :     /*
     370             :       get the receive mutex for this driver
     371             :      */
     372           0 :     DroneCAN_Handle *h = check_DroneCAN_Handle(L, 1);
     373             : 
     374           0 :     auto *s = h->subscriber;
     375             : 
     376           0 :     if (s == nullptr) {
     377           0 :         return 0;
     378             :     }
     379             :     Subscriber::Payload payload;
     380             :     /*
     381             :       peek first to avoid a memory leak if lua_pushlstring() faults
     382             :      */
     383           0 :     if (!s->payloads.peek(payload)) {
     384           0 :         return 0;
     385             :     }
     386             : 
     387           0 :     lua_pushlstring(L, (char *)payload.data, payload.length);
     388             : 
     389           0 :     s->payloads.pop();
     390           0 :     free(payload.data);
     391             : 
     392           0 :     lua_pushinteger(L, payload.node_id);
     393           0 :     *new_uint64_t(L) = payload.timestamp;
     394             : #if CANARD_ENABLE_CANFD
     395           0 :     lua_pushboolean(L, payload.canfd);
     396             : #else
     397             :     lua_pushboolean(L, false);
     398             : #endif
     399             : 
     400           0 :     if (s->trans_type == CanardTransferTypeResponse) {
     401             :         // request reply removes the subscriber
     402           0 :         WITH_SEMAPHORE(h->dc->get_canard_iface().get_sem_rx());
     403           0 :         delete h->subscriber;
     404           0 :         h->subscriber = nullptr;
     405           0 :     }
     406             :     
     407           0 :     return 4;
     408             : }
     409             : 
     410             : /*
     411             :   garbage collect a handle
     412             :  */
     413           0 : int DroneCAN_Handle::__gc(lua_State *L)
     414             : {
     415           0 :     DroneCAN_Handle *h = check_DroneCAN_Handle(L, 1);
     416           0 :     WITH_SEMAPHORE(h->dc->get_canard_iface().get_sem_rx());
     417             : 
     418           0 :     if (h->subscriber != nullptr) {
     419           0 :         delete h->subscriber;
     420           0 :         h->subscriber = nullptr;
     421             :     }
     422           0 :     return 0;
     423           0 : }
     424             : 
     425             : // lua constructor for DroneCAN_Handle
     426           0 : int DroneCAN_Handle::new_handle(lua_State *L)
     427             : {
     428           0 :     lua_Number driver_index = luaL_checknumber(L, 1);
     429           0 :     const uint64_t sig = *check_uint64_t(L, 2);
     430           0 :     const uint16_t dtype = luaL_checkinteger(L, 3);
     431             : #if CANARD_ENABLE_CANFD
     432           0 :     const int args = lua_gettop(L);
     433           0 :     bool send_canfd = false;
     434           0 :     if (args > 3) {
     435           0 :         send_canfd = (bool)lua_toboolean(L, 4);
     436             :     }
     437             : #endif
     438             : 
     439           0 :     auto *dc = AP_DroneCAN::get_dronecan(driver_index);
     440           0 :     if (dc == nullptr) {
     441           0 :         return 0;
     442             :     }
     443             : 
     444           0 :     auto *h = new_DroneCAN_Handle(L);
     445             : 
     446           0 :     h->dc = dc;
     447           0 :     h->signature = sig;
     448           0 :     h->data_type = dtype;
     449             : #if CANARD_ENABLE_CANFD
     450           0 :     h->canfd = send_canfd;
     451             : #endif
     452             : 
     453           0 :     return 1;
     454             : }
     455             : 
     456             : #endif // HAL_ENABLE_DRONECAN_DRIVERS
     457             : 
     458             : #endif  // AP_SCRIPTING_ENABLED

Generated by: LCOV version 1.14