LCOV - code coverage report
Current view: top level - AP_Scripting - lua_bindings.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 326 634 51.4 %
Date: 2026-09-09 11:02:08 Functions: 23 41 56.1 %

          Line data    Source code
       1             : #include "AP_Scripting_config.h"
       2             : 
       3             : #if AP_SCRIPTING_ENABLED
       4             : 
       5             : #include <AP_Common/AP_Common.h>
       6             : #include <AP_HAL/HAL.h>
       7             : #include <AP_Networking/AP_Networking_Config.h>
       8             : #if AP_NETWORKING_ENABLED
       9             : #include <AP_HAL/utility/Socket.h>
      10             : #endif
      11             : #include <AP_Logger/AP_Logger.h>
      12             : #include <AP_Filesystem/AP_Filesystem.h>
      13             : #include <AP_GPS/AP_GPS.h>
      14             : #include <AP_AHRS/AP_AHRS.h>
      15             : 
      16             : #include "lua_bindings.h"
      17             : 
      18             : #include "lua_boxed_numerics.h"
      19             : #include <AP_Scripting/lua_generated_bindings.h>
      20             : 
      21             : #include <AP_Scheduler/AP_Scheduler.h>
      22             : #include <AP_Scripting/AP_Scripting.h>
      23             : #include <AP_Scripting/lua_scripts.h>
      24             : #include <string.h>
      25             : 
      26             : #include "lua/src/lauxlib.h"
      27             : 
      28             : extern const AP_HAL::HAL& hal;
      29             : 
      30             : extern "C" {
      31             : #include "lua/src/lmem.h"
      32             : }
      33             : 
      34             : // fix up . access to pretend it was : access by inserting a dummy element at
      35             : // the start of the stack. don't ever add another call, this is purely for
      36             : // legacy compatibility! (though many places semantically SHOULD use dots...)
      37       55883 : static void fix_dot_access_never_add_another_call(lua_State *L, const char *tname) {
      38       55883 :     if (luaL_testudata(L, 1, tname) != NULL) {
      39       22586 :         return; // expected type is at start of stack, : was used, nothing to do
      40             :     }
      41             : 
      42       33297 :     lua_pushnil(L); // put nil at start of stack, shifting other elements up
      43       33297 :     lua_insert(L, 1);
      44             : }
      45             : 
      46             : // millis
      47       69548 : int lua_millis(lua_State *L) {
      48       69548 :     binding_argcheck(L, 0);
      49             : 
      50       69548 :     *new_uint32_t(L) = AP_HAL::millis();
      51             : 
      52       69548 :     return 1;
      53             : }
      54             : 
      55             : // micros
      56          39 : int lua_micros(lua_State *L) {
      57          39 :     binding_argcheck(L, 0);
      58             : 
      59          39 :     *new_uint32_t(L) = AP_HAL::micros();
      60             : 
      61          39 :     return 1;
      62             : }
      63             : 
      64             : #if HAL_GCS_ENABLED
      65          19 : int lua_mavlink_init(lua_State *L) {
      66          19 :     fix_dot_access_never_add_another_call(L, "mavlink");
      67             : 
      68          19 :     binding_argcheck(L, 3);
      69             :     // get the depth of receive queue
      70          19 :     const uint32_t queue_size = get_uint32(L, 2, 0, 25);
      71             :     // get number of msgs to accept
      72          19 :     const uint32_t num_msgs = get_uint32(L, 3, 0, 25);
      73             : 
      74          19 :     struct AP_Scripting::mavlink &data = AP::scripting()->mavlink_data;
      75          19 :     bool failed = false;
      76             :     {
      77          19 :         WITH_SEMAPHORE(data.sem);
      78          19 :         if (data.rx_buffer == nullptr) {
      79          17 :             data.rx_buffer = NEW_NOTHROW ObjectBuffer<struct AP_Scripting::mavlink_msg>(queue_size);
      80             :         }
      81          19 :         if (data.accept_msg_ids == nullptr) {
      82          17 :             data.accept_msg_ids = NEW_NOTHROW uint32_t[num_msgs];
      83          17 :             if (data.accept_msg_ids != nullptr) {
      84          17 :                 data.accept_msg_ids_size = num_msgs;
      85          17 :                 memset(data.accept_msg_ids, UINT32_MAX, sizeof(int) * num_msgs);
      86             :             }
      87             :         }
      88          19 :         if ((data.rx_buffer == nullptr) || (data.accept_msg_ids == nullptr)) {
      89           0 :             delete data.rx_buffer;
      90           0 :             delete[] data.accept_msg_ids;
      91           0 :             data.rx_buffer = nullptr;
      92           0 :             data.accept_msg_ids = nullptr;
      93           0 :             data.accept_msg_ids_size = 0;
      94           0 :             failed = true;
      95             :         }
      96          19 :     } // release semaphore here as luaL_error will NOT do that!
      97             : 
      98          19 :     if (failed) {
      99           0 :         return luaL_error(L, "out of memory");
     100             :     }
     101             : 
     102          19 :     return 0;
     103             : }
     104             : 
     105        4869 : int lua_mavlink_receive_chan(lua_State *L) {
     106        4869 :     fix_dot_access_never_add_another_call(L, "mavlink");
     107             : 
     108        4869 :     binding_argcheck(L, 1);
     109             : 
     110             :     struct AP_Scripting::mavlink_msg msg;
     111        4869 :     ObjectBuffer<struct AP_Scripting::mavlink_msg> *rx_buffer = AP::scripting()->mavlink_data.rx_buffer;
     112             : 
     113        4869 :     if (rx_buffer == nullptr) {
     114           0 :         return luaL_error(L, "RX not initialized");
     115             :     }
     116             : 
     117        4869 :     if (rx_buffer->pop(msg)) {
     118          20 :         lua_pushlstring(L, (char *)&msg.msg, sizeof(msg.msg));
     119          20 :         lua_pushinteger(L, msg.chan);
     120          20 :         *new_uint32_t(L) = msg.timestamp_ms;
     121          20 :         return 3;
     122             :     } else {
     123             :         // no MAVLink to handle, just return no results
     124        4849 :         return 0;
     125             :     }
     126             : }
     127             : 
     128          19 : int lua_mavlink_register_rx_msgid(lua_State *L) {
     129          19 :     fix_dot_access_never_add_another_call(L, "mavlink");
     130             : 
     131          19 :     binding_argcheck(L, 2);
     132             : 
     133          19 :     const uint32_t msgid = get_uint32(L, 2, 0, (1 << 24) - 1);
     134             : 
     135          19 :     struct AP_Scripting::mavlink &data = AP::scripting()->mavlink_data;
     136             : 
     137             :     // check that we aren't currently watching this ID
     138          36 :     for (uint8_t i = 0; i < data.accept_msg_ids_size; i++) {
     139          19 :         if (data.accept_msg_ids[i] == msgid) {
     140           2 :             lua_pushboolean(L, false);
     141           2 :             return 1;
     142             :         }
     143             :     }
     144             : 
     145          17 :     int i = 0;
     146          17 :     for (i = 0; i < data.accept_msg_ids_size; i++) {
     147          17 :         if (data.accept_msg_ids[i] == UINT32_MAX) {
     148          17 :             break;
     149             :         }
     150             :     }
     151             : 
     152          17 :     if (i >= data.accept_msg_ids_size) {
     153           0 :         return luaL_error(L, "no registrations free");
     154             :     }
     155             : 
     156             :     {
     157          17 :         WITH_SEMAPHORE(data.sem);
     158          17 :         data.accept_msg_ids[i] = msgid;
     159          17 :     }
     160             : 
     161          17 :     lua_pushboolean(L, true);
     162          17 :     return 1;
     163             : }
     164             : 
     165          11 : int lua_mavlink_send_chan(lua_State *L) {
     166          11 :     fix_dot_access_never_add_another_call(L, "mavlink");
     167             : 
     168          11 :     binding_argcheck(L, 4);
     169             : 
     170          11 :     const mavlink_channel_t chan = (mavlink_channel_t)get_uint32(L, 2, 0, MAVLINK_COMM_NUM_BUFFERS - 1);
     171             : 
     172             :     // Check if the channel is valid
     173          11 :     if (chan >= gcs().num_gcs()) {
     174             :         // Return nil
     175           0 :         return 0;
     176             :     }
     177             : 
     178          11 :     const uint32_t msgid = get_uint32(L, 3, 0, (1 << 24) - 1);
     179             : 
     180          11 :     const char *packet = luaL_checkstring(L, 4);
     181             : 
     182             :     // FIXME: The data that's in this mavlink_msg_entry_t should be provided from the script, which allows
     183             :     //        sending entirely new messages as outputs. At the moment we can only encode messages that
     184             :     //        are known at compile time. This is fine as a starting point as this is symmetrical to the
     185             :     //        decoding side of the scripting support
     186          11 :     const mavlink_msg_entry_t *entry = mavlink_get_msg_entry(msgid);
     187          11 :     if (entry == nullptr) {
     188           0 :         return luaL_error(L, "Unknown MAVLink message ID (%d)", msgid);
     189             :     }
     190             : 
     191          11 :     WITH_SEMAPHORE(comm_chan_lock(chan));
     192          11 :     if (comm_get_txspace(chan) >= (GCS_MAVLINK::packet_overhead_chan(chan) + entry->max_msg_len)) {
     193          10 :         _mav_finalize_message_chan_send(chan,
     194          10 :                                         entry->msgid,
     195             :                                         packet,
     196          10 :                                         entry->min_msg_len,
     197          10 :                                         entry->max_msg_len,
     198          10 :                                         entry->crc_extra);
     199             : 
     200          10 :         lua_pushboolean(L, true);
     201             :     } else {
     202           1 :         lua_pushboolean(L, false);
     203             :     }
     204             : 
     205          11 :     return 1;
     206          11 : }
     207             : 
     208           0 : int lua_mavlink_block_command(lua_State *L) {
     209           0 :     fix_dot_access_never_add_another_call(L, "mavlink");
     210             : 
     211           0 :     binding_argcheck(L, 2);
     212             : 
     213           0 :     const uint16_t id = get_uint16_t(L, 2);
     214             : 
     215             :     // Check if ID is already registered
     216           0 :     if (AP::scripting()->is_handling_command(id)) {
     217           0 :         lua_pushboolean(L, true);
     218           0 :         return 1;
     219             :     }
     220             : 
     221             :     // Add new list item
     222           0 :     AP_Scripting::command_block_list *new_item = NEW_NOTHROW AP_Scripting::command_block_list;
     223           0 :     if (new_item == nullptr) {
     224           0 :         lua_pushboolean(L, false);
     225           0 :         return 1;
     226             :     }
     227           0 :     new_item->id = id;
     228             : 
     229             :     {
     230           0 :         WITH_SEMAPHORE(AP::scripting()->mavlink_command_block_list_sem);
     231           0 :         new_item->next = AP::scripting()->mavlink_command_block_list;
     232           0 :         AP::scripting()->mavlink_command_block_list = new_item;
     233           0 :     }
     234             : 
     235           0 :     lua_pushboolean(L, true);
     236           0 :     return 1;
     237             : }
     238             : #endif // HAL_GCS_ENABLED
     239             : 
     240             : #if AP_MISSION_ENABLED
     241           0 : int lua_mission_receive(lua_State *L) {
     242           0 :     binding_argcheck(L, 0);
     243             : 
     244           0 :     ObjectBuffer<struct AP_Scripting::scripting_mission_cmd> *input = AP::scripting()->mission_data;
     245             : 
     246           0 :     if (input == nullptr) {
     247             :         // no mission items ever received
     248           0 :         return 0;
     249             :     }
     250             : 
     251             :     struct AP_Scripting::scripting_mission_cmd cmd;
     252             : 
     253           0 :     if (!input->pop(cmd)) {
     254             :         // no new item
     255           0 :         return 0;
     256             :     }
     257             : 
     258           0 :     *new_uint32_t(L) = cmd.time_ms;
     259             : 
     260           0 :     lua_pushinteger(L, cmd.p1);
     261           0 :     lua_pushnumber(L, cmd.content_p1);
     262           0 :     lua_pushnumber(L, cmd.content_p2);
     263           0 :     lua_pushnumber(L, cmd.content_p3);
     264             : 
     265           0 :     return 5;
     266             : }
     267             : #endif // AP_MISSION_ENABLED
     268             : 
     269             : #if HAL_LOGGING_ENABLED
     270       50963 : int AP_Logger_Write(lua_State *L) {
     271       50963 :     AP_Logger * AP_logger = AP_Logger::get_singleton();
     272       50963 :     if (AP_logger == nullptr) {
     273           0 :         return luaL_argerror(L, 1, "logger not supported on this firmware");
     274             :     }
     275             : 
     276       50963 :     fix_dot_access_never_add_another_call(L, "logger");
     277             : 
     278             :     // check we have at least 5 arguments passed in
     279       50963 :     const size_t args = lua_gettop(L);
     280       50963 :     if (args < 5) {
     281           0 :         return luaL_argerror(L, args, "too few arguments");
     282             :     }
     283             : 
     284       50963 :     const char * name = luaL_checkstring(L, 2);
     285       50963 :     const char * labels = luaL_checkstring(L, 3);
     286       50963 :     const char * fmt = luaL_checkstring(L, 4);
     287             : 
     288             :     // cheack the name, labels and format are not too long
     289       50963 :     if (strlen(name) >= LS_NAME_SIZE) {
     290           0 :         return luaL_error(L, "Name must be 4 or less chars long");
     291             :     }
     292       50963 :     size_t labels_length = strlen(labels);
     293       50963 :     if (labels_length >= (LS_LABELS_SIZE - 7)) { // need 7 chars to add 'TimeUS,'
     294           0 :         return luaL_error(L, "labels must be less than 58 chars long");
     295             :     }
     296             :     // Count the number of commas
     297       50963 :     size_t commas = 1;
     298     1620442 :     for (size_t i=0; i<labels_length; i++) {
     299     1569479 :         if (labels[i] == ',') {
     300      311659 :             commas++;
     301             :         }
     302             :     }
     303             : 
     304       50963 :     size_t fmt_length = strlen(fmt);
     305       50963 :     if (fmt_length >= (LS_FORMAT_SIZE - 1)) { // need 1 char to add timestamp
     306           0 :         return luaL_error(L, "format must be less than 15 chars long");
     307             :     }
     308             : 
     309             :     // check the number of arguments matches the number of values in the label
     310       50963 :     if (fmt_length != commas) {
     311           0 :         return luaL_argerror(L, args, "label does not match format");
     312             :     }
     313             : 
     314       50963 :     bool have_units = false;
     315       50963 :     if (args - 6 == fmt_length) {
     316             :         // check if there are enough arguments for units and multipliers
     317       18070 :         have_units = true;
     318       32893 :     } else if (args - 4 != fmt_length) {
     319             :         // check the number of arguments matches the length of the format string
     320           0 :         return luaL_argerror(L, args, "format does not match No. of arguments");
     321             :     }
     322             : 
     323             :     // prepend timestamp to format and labels
     324             :     char label_cat[LS_LABELS_SIZE];
     325             :     char fmt_cat[LS_FORMAT_SIZE];
     326       50963 :     snprintf(label_cat, sizeof(label_cat), "TimeUS,%s", labels);
     327       50963 :     snprintf(fmt_cat, sizeof(fmt_cat), "Q%s", fmt);
     328             : 
     329       50963 :     uint8_t field_start = 4;
     330             :     struct AP_Logger::log_write_fmt *f;
     331       50963 :     if (!have_units) {
     332             :         // ask for a message type (will duplicate incoming strings if necessary)
     333       32893 :         f = AP_logger->msg_fmt_for_name(name, label_cat, nullptr, nullptr, fmt_cat, true, true);
     334             :     } else {
     335             :         // read in units and multipliers strings
     336       18070 :         field_start += 2;
     337       18070 :         const char * units = luaL_checkstring(L, 5);
     338       18070 :         const char * multipliers = luaL_checkstring(L, 6);
     339             : 
     340       18070 :         if (fmt_length != strlen(units)) {
     341           0 :             return luaL_error(L, "units must be same length as format");
     342             :         }
     343       18070 :         if (fmt_length != strlen(multipliers)) {
     344           0 :             return luaL_error(L, "multipliers must be same length as format");
     345             :         }
     346             : 
     347             :         // prepend timestamp to units and multipliers
     348             :         char units_cat[LS_FORMAT_SIZE];
     349             :         char multipliers_cat[LS_FORMAT_SIZE];
     350       18070 :         snprintf(units_cat, sizeof(units_cat), "s%s", units);
     351       18070 :         snprintf(multipliers_cat, sizeof(multipliers_cat), "F%s", multipliers);
     352             : 
     353             :         // ask for a message type (will duplicate incoming strings if necessary)
     354       18070 :         f = AP_logger->msg_fmt_for_name(name, label_cat, units_cat, multipliers_cat, fmt_cat, true, true);
     355             :     }
     356             : 
     357       50963 :     if (f == nullptr) {
     358             :         // unable to map name to a messagetype; could be out of
     359             :         // msgtypes, could be out of slots, ...
     360           0 :         return luaL_argerror(L, args, "could not map message type");
     361             :     }
     362             : 
     363             :     // work out how long the block will be
     364       50963 :     int16_t msg_len = AP_logger->Write_calc_msg_len(fmt_cat);
     365       50963 :     if (msg_len == -1) {
     366           0 :         return luaL_argerror(L, args, "unknown format");
     367             :     }
     368             : 
     369             :     // lua buffers are ~512 bytes on stack. in the unlikely event packets get
     370             :     // expanded past that, this function should be rewritten to use one.
     371             :     static_assert(LOG_PACKET_MAX_LEN <= sizeof(luaL_Buffer), "packets are too long");
     372             : 
     373             :     char buffer[LOG_PACKET_MAX_LEN]; // constant buffer size optimizes better
     374             : 
     375             :     // add logging headers
     376       50963 :     uint8_t offset = 0;
     377       50963 :     buffer[offset++] = HEAD_BYTE1;
     378       50963 :     buffer[offset++] = HEAD_BYTE2;
     379       50963 :     buffer[offset++] = f->msg_type;
     380             : 
     381             :     // timestamp is always first value
     382       50963 :     const uint64_t now = AP_HAL::micros64();
     383       50963 :     memcpy(&buffer[offset], &now, sizeof(uint64_t));
     384       50963 :     offset += sizeof(uint64_t);
     385             : 
     386      413585 :     for (uint8_t i=field_start; i<=args-1; i++) {
     387      362622 :         uint8_t charlen = 0;
     388      362622 :         uint8_t index = have_units ? i-5 : i-3;
     389      362622 :         uint8_t arg_index = i + 1;
     390      362622 :         switch(fmt_cat[index]) {
     391             :             // logger variable types not available to scripting
     392             :             // 'd': double
     393             :             // 'q': int64_t
     394             :             // 'a': int16_t[32]
     395           0 :             case 'b': { // int8_t
     396           0 :                 int8_t tmp = get_int8_t(L, arg_index);
     397           0 :                 memcpy(&buffer[offset], &tmp, sizeof(int8_t));
     398           0 :                 offset += sizeof(int8_t);
     399           0 :                 break;
     400             :             }
     401           0 :             case 'h': // int16_t
     402             :             case 'c': { // int16_t * 100
     403           0 :                 int16_t tmp = get_int16_t(L, arg_index);
     404           0 :                 memcpy(&buffer[offset], &tmp, sizeof(int16_t));
     405           0 :                 offset += sizeof(int16_t);
     406           0 :                 break;
     407             :             }
     408           0 :             case 'H': // uint16_t
     409             :             case 'C': { // uint16_t * 100
     410           0 :                 uint16_t tmp = get_uint16_t(L, arg_index);
     411           0 :                 memcpy(&buffer[offset], &tmp, sizeof(uint16_t));
     412           0 :                 offset += sizeof(uint16_t);
     413           0 :                 break;
     414             :             }
     415       20584 :             case 'i': // int32_t
     416             :             case 'L': // int32_t (lat/long)
     417             :             case 'e': { // int32_t * 100
     418       20584 :                 const lua_Integer tmp1 = luaL_checkinteger(L, arg_index);
     419       20584 :                 const int32_t tmp = tmp1;
     420       20584 :                 memcpy(&buffer[offset], &tmp, sizeof(int32_t));
     421       20584 :                 offset += sizeof(int32_t);
     422       20584 :                 break;
     423             :             }
     424      339110 :             case 'f': { // float
     425      339110 :                 const lua_Number tmp1 = luaL_checknumber(L, arg_index);
     426      339110 :                 const float tmp = tmp1;
     427      339110 :                 memcpy(&buffer[offset], &tmp, sizeof(float));
     428      339110 :                 offset += sizeof(float);
     429      339110 :                 break;
     430             :             }
     431        2928 :             case 'n': { // char[4]
     432        2928 :                 charlen = 4;
     433        2928 :                 break;
     434             :             }
     435           0 :             case 'M': // uint8_t (flight mode)
     436             :             case 'B': { // uint8_t
     437             :                 uint8_t tmp;
     438           0 :                 if (lua_isboolean(L, arg_index)) { // Also allow boolean
     439           0 :                     tmp = static_cast<uint8_t>(lua_toboolean(L, arg_index));
     440             :                 } else {
     441           0 :                     tmp = get_uint8_t(L, arg_index);
     442             :                 }
     443           0 :                 memcpy(&buffer[offset], &tmp, sizeof(uint8_t));
     444           0 :                 offset += sizeof(uint8_t);
     445           0 :                 break;
     446             :             }
     447           0 :             case 'I': // uint32_t
     448             :             case 'E': { // uint32_t * 100
     449           0 :                 uint32_t tmp = coerce_to_uint32_t(L, arg_index);
     450           0 :                 memcpy(&buffer[offset], &tmp, sizeof(uint32_t));
     451           0 :                 offset += sizeof(uint32_t);
     452           0 :                 break;
     453             :             }
     454           0 :             case 'Q': { // uint64_t
     455           0 :                 uint64_t tmp = coerce_to_uint64_t(L, arg_index);
     456           0 :                 memcpy(&buffer[offset], &tmp, sizeof(uint64_t));
     457           0 :                 offset += sizeof(uint64_t);
     458           0 :                 break;
     459             :             }
     460           0 :             case 'N': { // char[16]
     461           0 :                 charlen = 16;
     462           0 :                 break;
     463             :             }
     464           0 :             case 'Z': { // char[64]
     465           0 :                 charlen = 64;
     466           0 :                 break;
     467             :             }
     468           0 :             default: {
     469           0 :                 return luaL_error(L, "%c unsupported format", fmt_cat[index]);
     470             :             }
     471             :         }
     472      362622 :         if (charlen != 0) {
     473             :             size_t slen;
     474        2928 :             const char *tmp = luaL_checklstring(L, arg_index, &slen);
     475        2928 :             if (slen > charlen) {
     476           0 :                 return luaL_error(L, "arg %d too long for %c format", arg_index, fmt_cat[index]);
     477             :             }
     478        2928 :             memcpy(&buffer[offset], tmp, slen);
     479        2928 :             memset(&buffer[offset+slen], 0, charlen-slen);
     480        2928 :             offset += charlen;
     481             :         }
     482             :     }
     483             : 
     484       50963 :     AP_logger->Safe_Write_Emit_FMT(f);
     485             : 
     486       50963 :     AP_logger->WriteBlock(buffer, msg_len);
     487             : 
     488       50963 :     return 0;
     489             : }
     490             : #endif // HAL_LOGGING_ENABLED
     491             : 
     492           0 : int lua_get_i2c_device(lua_State *L) {
     493           0 :     fix_dot_access_never_add_another_call(L, "i2c");
     494             : 
     495           0 :     const int args = lua_gettop(L);
     496           0 :     if (args < 3) {
     497           0 :         return luaL_argerror(L, args, "require i2c bus and address");
     498             :     }
     499           0 :     if (args > 5) {
     500           0 :         return luaL_argerror(L, args, "too many arguments");
     501             :     }
     502             : 
     503           0 :     const lua_Integer bus_in = get_integer(L, 2, 0, 4);
     504           0 :     const uint8_t bus = static_cast<uint8_t>(bus_in);
     505             : 
     506           0 :     const lua_Integer address_in = get_integer(L, 3, 0, 128);
     507           0 :     const uint8_t address = static_cast<uint8_t>(address_in);
     508             : 
     509             :     // optional arguments, use the same defaults as the hal get_device function
     510           0 :     uint32_t bus_clock = 400000;
     511           0 :     bool use_smbus = false;
     512             : 
     513           0 :     if (args > 3) {
     514           0 :         bus_clock = coerce_to_uint32_t(L, 4);
     515             : 
     516           0 :         if (args > 4) {
     517           0 :             use_smbus = static_cast<bool>(lua_toboolean(L, 5));
     518             :         }
     519             :     }
     520             : 
     521           0 :     auto *scripting = AP::scripting();
     522             : 
     523             :     static_assert(SCRIPTING_MAX_NUM_I2C_DEVICE >= 0, "There cannot be a negative number of I2C devices");
     524           0 :     if (scripting->num_i2c_devices >= SCRIPTING_MAX_NUM_I2C_DEVICE) {
     525           0 :         return luaL_argerror(L, 1, "no i2c devices available");
     526             :     }
     527             : 
     528           0 :     scripting->_i2c_dev[scripting->num_i2c_devices] = hal.i2c_mgr->get_device_ptr(bus, address, bus_clock, use_smbus);
     529             : 
     530           0 :     if (scripting->_i2c_dev[scripting->num_i2c_devices] == nullptr) {
     531           0 :         return luaL_argerror(L, 1, "i2c device nullptr");
     532             :     }
     533             : 
     534           0 :     *new_AP_HAL__I2CDevice(L) = scripting->_i2c_dev[scripting->num_i2c_devices];
     535             : 
     536           0 :     scripting->num_i2c_devices++;
     537             : 
     538           0 :     return 1;
     539             : }
     540             : 
     541           0 : int AP_HAL__I2CDevice_read_registers(lua_State *L) {
     542           0 :     const int args = lua_gettop(L);
     543             :     bool multi_register;
     544           0 :     if (args == 2) {
     545           0 :         multi_register = false;
     546           0 :     } else if (args == 3) {
     547           0 :         multi_register = true;
     548             :     } else {
     549           0 :         return luaL_argerror(L, args, "expected 1 or 2 arguments");
     550             :     }
     551             : 
     552           0 :     AP_HAL::I2CDevice * ud = *check_AP_HAL__I2CDevice(L, 1);
     553             : 
     554           0 :     const uint8_t first_reg = get_uint8_t(L, 2);
     555             : 
     556           0 :     uint8_t recv_length = 1;
     557           0 :     if (multi_register) {
     558           0 :         recv_length = get_uint8_t(L, 3);
     559             :     }
     560             : 
     561           0 :     uint8_t data[recv_length];
     562             : 
     563           0 :     ud->get_semaphore()->take_blocking();
     564           0 :     const bool success = static_cast<bool>(ud->read_registers(first_reg, data, recv_length));
     565           0 :     ud->get_semaphore()->give();
     566             : 
     567           0 :     if (success) {
     568           0 :         if (!multi_register) {
     569           0 :             lua_pushinteger(L, data[0]);
     570             :         } else {
     571             :             // push to table
     572           0 :             lua_newtable(L);
     573           0 :             for (uint8_t i=0; i < recv_length; i++) {
     574           0 :                 lua_pushinteger(L, i+1);
     575           0 :                 lua_pushinteger(L, data[i]);
     576           0 :                 lua_settable(L, -3);
     577             :             }
     578             :         }
     579             :     }
     580           0 :     return success;
     581           0 : }
     582             : 
     583           0 : int AP_HAL__I2CDevice_transfer(lua_State *L) {
     584           0 :     binding_argcheck(L, 3);
     585             : 
     586           0 :     AP_HAL::I2CDevice * ud = *check_AP_HAL__I2CDevice(L, 1);
     587             : 
     588             :     // Parse string of bytes to send
     589             :     size_t send_len;
     590           0 :     const uint8_t* send_data = (const uint8_t*)(lua_tolstring(L, 2, &send_len));
     591             : 
     592             :     // Parse and setup rx buffer
     593           0 :     uint32_t rx_len = get_uint8_t(L, 3);
     594           0 :     uint8_t rx_data[rx_len];
     595             : 
     596             :     // Transfer
     597           0 :     ud->get_semaphore()->take_blocking();
     598           0 :     const bool success = ud->transfer(send_data, send_len, rx_data, rx_len);
     599           0 :     ud->get_semaphore()->give();
     600             : 
     601           0 :     if (!success) {
     602           0 :         return 0;
     603             :     }
     604             : 
     605             :     // Return a string
     606           0 :     lua_pushlstring(L, (const char *)rx_data, rx_len);
     607           0 :     return 1;
     608           0 : }
     609             : 
     610             : #if AP_SCRIPTING_CAN_SENSOR_ENABLED
     611           0 : int lua_get_CAN_device(lua_State *L) {
     612           0 :     fix_dot_access_never_add_another_call(L, "CAN");
     613             : 
     614           0 :     binding_argcheck(L, 2);
     615             : 
     616           0 :     const uint32_t raw_buffer_len = get_uint32(L, 2, 1, 25);
     617           0 :     const uint32_t buffer_len = static_cast<uint32_t>(raw_buffer_len);
     618             : 
     619           0 :     auto *scripting = AP::scripting();
     620             : 
     621           0 :     if (scripting->_CAN_dev == nullptr) {
     622           0 :         scripting->_CAN_dev = NEW_NOTHROW ScriptingCANSensor(AP_CAN::Protocol::Scripting);
     623           0 :         if (scripting->_CAN_dev == nullptr) {
     624           0 :             return luaL_argerror(L, 1, "CAN device nullptr");
     625             :         }
     626             :     }
     627             : 
     628           0 :     if (!scripting->_CAN_dev->initialized()) {
     629             :         // Driver not initialized, probably because there is no can driver set to scripting
     630             :         // Return nil
     631           0 :         return 0;
     632             :     }
     633             : 
     634           0 :     *new_ScriptingCANBuffer(L) = scripting->_CAN_dev->add_buffer(buffer_len);
     635             : 
     636           0 :     return 1;
     637             : }
     638             : 
     639           0 : int lua_get_CAN_device2(lua_State *L) {
     640           0 :     fix_dot_access_never_add_another_call(L, "CAN");
     641             : 
     642           0 :     binding_argcheck(L, 2);
     643             : 
     644           0 :     const uint32_t raw_buffer_len = get_uint32(L, 2, 1, 25);
     645           0 :     const uint32_t buffer_len = static_cast<uint32_t>(raw_buffer_len);
     646             : 
     647           0 :     auto *scripting = AP::scripting();
     648             : 
     649           0 :     if (scripting->_CAN_dev2 == nullptr) {
     650           0 :         scripting->_CAN_dev2 = NEW_NOTHROW ScriptingCANSensor(AP_CAN::Protocol::Scripting2);
     651           0 :         if (scripting->_CAN_dev2 == nullptr) {
     652           0 :             return luaL_argerror(L, 1, "CAN device nullptr");
     653             :         }
     654             :     }
     655             : 
     656           0 :     if (!scripting->_CAN_dev2->initialized()) {
     657             :         // Driver not initialized, probably because there is no can driver set to scripting 2
     658             :         // Return nil
     659           0 :         return 0;
     660             :     }
     661             : 
     662           0 :     *new_ScriptingCANBuffer(L) = scripting->_CAN_dev2->add_buffer(buffer_len);
     663             : 
     664           0 :     return 1;
     665             : }
     666             : #endif // AP_SCRIPTING_CAN_SENSOR_ENABLED
     667             : 
     668             : #if AP_SERIALMANAGER_ENABLED
     669           1 : int lua_serial_find_serial(lua_State *L) {
     670           1 :     fix_dot_access_never_add_another_call(L, "serial");
     671             : 
     672           1 :     binding_argcheck(L, 2);
     673             : 
     674           1 :     uint8_t instance = get_uint8_t(L, 2);
     675             : 
     676           1 :     AP_SerialManager *mgr = &AP::serialmanager();
     677           1 :     AP_HAL::UARTDriver *driver_stream = mgr->find_serial(
     678             :         AP_SerialManager::SerialProtocol_Scripting, instance);
     679             : 
     680           1 :     if (driver_stream == nullptr) { // not found
     681           0 :         return 0;
     682             :     }
     683             : 
     684           1 :     AP_Scripting_SerialAccess *port = new_AP_Scripting_SerialAccess(L);
     685           1 :     port->stream = driver_stream;
     686             : #if AP_SCRIPTING_SERIALDEVICE_ENABLED
     687           1 :     port->is_device_port = false;
     688             : #endif
     689             : 
     690           1 :     return 1;
     691             : }
     692             : #endif // AP_SERIALMANAGER_ENABLED
     693             : 
     694             : #if AP_SCRIPTING_SERIALDEVICE_ENABLED
     695           1 : int lua_serial_find_simulated_device(lua_State *L) {
     696           1 :     fix_dot_access_never_add_another_call(L, "serial");
     697             : 
     698           1 :     binding_argcheck(L, 3);
     699             : 
     700           1 :     const int8_t protocol = (int8_t)get_uint32(L, 2, 0, INT8_MAX);
     701           1 :     uint32_t instance = get_uint16_t(L, 3);
     702             : 
     703           1 :     auto *scripting = AP::scripting();
     704           1 :     AP_Scripting_SerialDevice::Port *device_stream = nullptr;
     705             : 
     706           1 :     for (auto &port : scripting->_serialdevice.ports) {
     707           1 :         if (port.state.protocol == protocol) {
     708           1 :             if (instance-- == 0) {
     709           1 :                 device_stream = &port;
     710           1 :                 break;
     711             :             }
     712             :         }
     713             :     }
     714             : 
     715           1 :     if (!scripting->_serialdevice.enable || device_stream == nullptr) {
     716             :         // serial devices as a whole are disabled, or port not found
     717           0 :         return 0;
     718             :     }
     719             : 
     720           1 :     AP_Scripting_SerialAccess *port = new_AP_Scripting_SerialAccess(L);
     721           1 :     port->stream = device_stream;
     722           1 :     port->is_device_port = true;
     723             : 
     724           1 :     return 1;
     725             : }
     726             : #endif // AP_SCRIPTING_SERIALDEVICE_ENABLED
     727             : 
     728           1 : int lua_serial_writestring(lua_State *L)
     729             : {
     730           1 :     binding_argcheck(L, 2);
     731             : 
     732           1 :     AP_Scripting_SerialAccess * port = check_AP_Scripting_SerialAccess(L, 1);
     733             : 
     734             :     // get the bytes the user wants to write, along with their length
     735             :     size_t req_bytes;
     736           1 :     const char *data = luaL_checklstring(L, 2, &req_bytes);
     737             : 
     738             :     // write up to that number of bytes
     739           1 :     const uint32_t written_bytes = port->write((const uint8_t*)data, req_bytes);
     740             : 
     741             :     // return the number of bytes that were actually written
     742           1 :     lua_pushinteger(L, written_bytes);
     743             : 
     744           1 :     return 1;
     745             : }
     746             : 
     747           2 : int lua_serial_readstring(lua_State *L) {
     748           2 :     binding_argcheck(L, 2);
     749             : 
     750           2 :     AP_Scripting_SerialAccess * port = check_AP_Scripting_SerialAccess(L, 1);
     751             : 
     752             :     // create a buffer sized to hold the number of bytes the user wants to read
     753             :     luaL_Buffer b;
     754           2 :     const uint16_t req_bytes = get_uint16_t(L, 2);
     755           2 :     uint8_t *data = (uint8_t *)luaL_buffinitsize(L, &b, req_bytes);
     756             : 
     757             :     // read up to that number of bytes
     758           2 :     const ssize_t read_bytes = port->read(data, req_bytes);
     759           2 :     if (read_bytes < 0) {
     760           0 :         return 0; // error, return nil
     761             :     }
     762             : 
     763             :     // push the buffer as a string, truncated to the number of bytes actually read
     764           2 :     luaL_pushresultsize(&b, read_bytes);
     765             : 
     766           2 :     return 1;
     767             : }
     768             : 
     769           1 : int lua_serial_begin(lua_State *L) {
     770           1 :     const int args = lua_gettop(L);
     771           1 :     if (args > 2) {
     772           0 :         return luaL_argerror(L, args, "too many arguments");
     773           1 :     } else if (args < 1) {
     774           0 :         return luaL_argerror(L, args, "too few arguments");
     775             :     }
     776           1 :     AP_Scripting_SerialAccess * port = check_AP_Scripting_SerialAccess(L, 1);
     777             : 
     778             :     // nil or absent argument treated as automatic baud
     779           1 :     if (!lua_isnoneornil(L, 2)) {
     780           1 :         port->begin(get_uint32(L, 2, 1, UINT32_MAX));
     781             :     } else {
     782           0 :         port->begin();
     783             :     }
     784             : 
     785           1 :     return 0;
     786             : }
     787             : 
     788             : /*
     789             :   directory listing, return table of files in a directory
     790             :  */
     791           0 : int lua_dirlist(lua_State *L) {
     792           0 :     binding_argcheck(L, 1);
     793             : 
     794             :     struct dirent *entry;
     795             :     int i;
     796           0 :     const char *path = luaL_checkstring(L, 1);
     797             :     
     798             :     /* open directory */
     799           0 :     auto dir = AP::FS().opendir(path);
     800           0 :     if (dir == nullptr) {  /* error opening the directory? */
     801           0 :         lua_pushnil(L);  /* return nil and ... */
     802           0 :         lua_pushstring(L, strerror(errno));  /* error message */
     803           0 :         return 2;  /* number of results */
     804             :     }
     805             :     
     806             :     /* create result table */
     807           0 :     lua_newtable(L);
     808           0 :     i = 1;
     809           0 :     while ((entry = AP::FS().readdir(dir)) != nullptr) {
     810           0 :         lua_pushnumber(L, i++);  /* push key */
     811           0 :         lua_pushstring(L, entry->d_name);  /* push value */
     812           0 :         lua_settable(L, -3);
     813             :     }
     814             :     
     815           0 :     AP::FS().closedir(dir);
     816           0 :     return 1;  /* table is already on top */
     817             : }
     818             : 
     819             : /*
     820             :   remove a file
     821             :  */
     822           0 : int lua_removefile(lua_State *L) {
     823           0 :     binding_argcheck(L, 1);
     824           0 :     const char *filename = luaL_checkstring(L, 1);
     825           0 :     return luaL_fileresult(L, AP::FS().unlink(filename) == 0, filename);
     826             : }
     827             : 
     828             : // Manual binding to allow SRV_Channels table to see safety state
     829           0 : int SRV_Channels_get_safety_state(lua_State *L) {
     830           0 :     binding_argcheck(L, 1);
     831           0 :     const bool data = hal.util->safety_switch_state() !=  AP_HAL::Util::SAFETY_ARMED;
     832           0 :     lua_pushboolean(L, data);
     833           0 :     return 1;
     834             : }
     835             : 
     836           0 : int lua_get_PWMSource(lua_State *L) {
     837           0 :     binding_argcheck(L, 0);
     838             : 
     839           0 :     auto *scripting = AP::scripting();
     840             : 
     841             :     static_assert(SCRIPTING_MAX_NUM_PWM_SOURCE >= 0, "There cannot be a negative number of PWMSources");
     842           0 :     if (scripting->num_pwm_source >= SCRIPTING_MAX_NUM_PWM_SOURCE) {
     843           0 :         return luaL_argerror(L, 1, "no PWMSources available");
     844             :     }
     845             : 
     846           0 :     scripting->_pwm_source[scripting->num_pwm_source] = NEW_NOTHROW AP_HAL::PWMSource;
     847           0 :     if (scripting->_pwm_source[scripting->num_pwm_source] == nullptr) {
     848           0 :         return luaL_argerror(L, 1, "PWMSources device nullptr");
     849             :     }
     850             : 
     851           0 :     *new_AP_HAL__PWMSource(L) = scripting->_pwm_source[scripting->num_pwm_source];
     852             : 
     853           0 :     scripting->num_pwm_source++;
     854             : 
     855           0 :     return 1;
     856             : }
     857             : 
     858             : #if AP_NETWORKING_ENABLED
     859             : /*
     860             :   allocate a SocketAPM
     861             :  */
     862           2 : int lua_get_SocketAPM(lua_State *L) {
     863           2 :     binding_argcheck(L, 1);
     864           2 :     const uint8_t datagram = get_uint8_t(L, 1);
     865           2 :     auto *scripting = AP::scripting();
     866             : 
     867           2 :     auto *sock = NEW_NOTHROW SocketAPM(datagram);
     868           2 :     if (sock == nullptr) {
     869           0 :         return luaL_argerror(L, 1, "SocketAPM device nullptr");
     870             :     }
     871           2 :     for (uint8_t i=0; i<SCRIPTING_MAX_NUM_NET_SOCKET; i++) {
     872           2 :         if (scripting->_net_sockets[i] == nullptr) {
     873           2 :             scripting->_net_sockets[i] = sock;
     874           2 :             *new_SocketAPM(L) = scripting->_net_sockets[i];
     875           2 :             return 1;
     876             :         }
     877             :     }
     878             : 
     879           0 :     return luaL_argerror(L, 1, "no sockets available");
     880             : }
     881             : 
     882             : /*
     883             :   socket close
     884             :  */
     885           2 : int SocketAPM_close(lua_State *L) {
     886           2 :     binding_argcheck(L, 1);
     887             : 
     888           2 :     SocketAPM *ud = *check_SocketAPM(L, 1);
     889             : 
     890           2 :     auto *scripting = AP::scripting();
     891             : 
     892             :     // clear allocated socket
     893           4 :     for (uint8_t i=0; i<SCRIPTING_MAX_NUM_NET_SOCKET; i++) {
     894           4 :         if (scripting->_net_sockets[i] == ud) {
     895           2 :             ud->close();
     896           2 :             delete ud;
     897           2 :             scripting->_net_sockets[i] = nullptr;
     898           2 :             *check_SocketAPM(L, 1) = nullptr;
     899           2 :             break;
     900             :         }
     901             :     }
     902             : 
     903           2 :     return 0;
     904             : }
     905             : 
     906             : /*
     907             :   socket sendfile, for offloading file send to AP_Networking
     908             :  */
     909           0 : int SocketAPM_sendfile(lua_State *L) {
     910           0 :     binding_argcheck(L, 2);
     911             : 
     912           0 :     SocketAPM *ud = *check_SocketAPM(L, 1);
     913             : 
     914           0 :     auto *p = (luaL_Stream *)luaL_checkudata(L, 2, LUA_FILEHANDLE);
     915           0 :     int fd = p->f->fd;
     916             : 
     917           0 :     bool ret = fd != -1 && AP::network().sendfile(ud, fd);
     918           0 :     if (ret) {
     919             :         // the fd is no longer valid. The lua script must
     920             :         // still call close() to release the memory from the
     921             :         // socket
     922           0 :         p->f->fd = -1;
     923             :     }
     924             : 
     925           0 :     lua_pushboolean(L, ret);
     926           0 :     return 1;
     927             : }
     928             : 
     929             : /*
     930             :   receive from a socket to a lua string
     931             :  */
     932           2 : int SocketAPM_recv(lua_State *L) {
     933           2 :     binding_argcheck(L, 2);
     934             : 
     935           2 :     SocketAPM * ud = *check_SocketAPM(L, 1);
     936             : 
     937           2 :     const uint16_t count = get_uint16_t(L, 2);
     938             : 
     939             :     // create a buffer sized to hold the number of bytes the user
     940             :     // wants to read. This will fault if the memory is not available
     941             :     luaL_Buffer b;
     942           2 :     uint8_t *data = (uint8_t *)luaL_buffinitsize(L, &b, count);
     943             : 
     944             :     // read up to that number of bytes
     945           2 :     const auto ret = ud->recv(data, count, 0);
     946           2 :     if (ret < 0) {
     947           0 :         return 0; // error, return nil
     948             :     }
     949             : 
     950           2 :     int retcount = 1;
     951             : 
     952             :     // push the buffer as a string, truncated to the number of bytes
     953             :     // actually read
     954           2 :     luaL_pushresultsize(&b, ret);
     955             : 
     956             :     // also push the address and port if available
     957             :     uint32_t ip_addr;
     958             :     uint16_t port;
     959           2 :     if (ud->last_recv_address(ip_addr, port)) {
     960           0 :         *new_uint32_t(L) = ip_addr;
     961           0 :         lua_pushinteger(L, port);
     962           0 :         retcount += 2;
     963             :     }
     964             : 
     965           2 :     return retcount;
     966             : }
     967             : 
     968             : /*
     969             :   TCP socket accept() call
     970             :  */
     971           2 : int SocketAPM_accept(lua_State *L) {
     972           2 :     binding_argcheck(L, 1);
     973             : 
     974           2 :     SocketAPM * ud = *check_SocketAPM(L, 1);
     975             : 
     976           2 :     auto *scripting = AP::scripting();
     977             : 
     978             :     // find an empty slot
     979           4 :     for (uint8_t i=0; i<SCRIPTING_MAX_NUM_NET_SOCKET; i++) {
     980           4 :         if (scripting->_net_sockets[i] == nullptr) {
     981           2 :             scripting->_net_sockets[i] = ud->accept(0);
     982           2 :             if (scripting->_net_sockets[i] == nullptr) {
     983           0 :                 return 0;
     984             :             }
     985           2 :             *new_SocketAPM(L) = scripting->_net_sockets[i];
     986           2 :             return 1;
     987             :         }
     988             :     }
     989             : 
     990             :     // out of socket slots, return nil, caller can retry
     991           0 :     return 0;
     992             : }
     993             : 
     994             : /*
     995             :   convert a uint32_t ipv4 address to a string
     996             :  */
     997           0 : int SocketAPM_ipv4_addr_to_string(lua_State *L) {
     998           0 :     binding_argcheck(L, 1);
     999           0 :     const uint32_t ip_addr = get_uint32(L, 1, 0, UINT32_MAX);
    1000             :     char buf[IP4_STR_LEN];
    1001           0 :     const char *ret = SocketAPM::inet_addr_to_str(ip_addr, buf, sizeof(buf));
    1002           0 :     if (ret == nullptr) {
    1003           0 :         return 0;
    1004             :     }
    1005           0 :     lua_pushlstring(L, (const char *)ret, strlen(ret));
    1006           0 :     return 1;
    1007             : }
    1008             : 
    1009             : /*
    1010             :   convert a ipv4 string address to a uint32_t
    1011             :  */
    1012           0 : int SocketAPM_string_to_ipv4_addr(lua_State *L) {
    1013           0 :     binding_argcheck(L, 1);
    1014           0 :     const char *str = luaL_checkstring(L, 1);
    1015           0 :     *new_uint32_t(L) = SocketAPM::inet_str_to_addr(str);
    1016           0 :     return 1;
    1017             : }
    1018             : 
    1019             : #endif // AP_NETWORKING_ENABLED
    1020             : 
    1021             : 
    1022          53 : int lua_get_current_env_ref()
    1023             : {
    1024          53 :     auto *scripting = AP::scripting();
    1025          53 :     return scripting->get_current_env_ref();
    1026             : }
    1027             : 
    1028             : // This is used when loading modules with require, lua must only look in enabled directory's
    1029          92 : const char* lua_get_modules_path()
    1030             : {
    1031             : #define LUA_PATH_ROMFS "@ROMFS/scripts/modules/?.lua;" "@ROMFS/scripts/modules/?/init.lua"
    1032             : #define LUA_PATH_SCRIPTS LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua"
    1033             : 
    1034          92 :     uint16_t dir_disable = AP_Scripting::get_singleton()->get_disabled_dir();
    1035          92 :     dir_disable &= uint16_t(AP_Scripting::SCR_DIR::SCRIPTS) | uint16_t(AP_Scripting::SCR_DIR::ROMFS);
    1036          92 :     if (dir_disable == 0) {
    1037             :         // Both directory's are enabled, return both, ROMFS takes priority
    1038          92 :         return LUA_PATH_ROMFS ";" LUA_PATH_SCRIPTS;
    1039             :     }
    1040             : 
    1041           0 :     if ((dir_disable & uint16_t(AP_Scripting::SCR_DIR::SCRIPTS)) == 0) {
    1042             :         // Only scripts enabled
    1043           0 :         return LUA_PATH_SCRIPTS;
    1044             :     }
    1045             : 
    1046           0 :     if ((dir_disable & uint16_t(AP_Scripting::SCR_DIR::ROMFS)) == 0) {
    1047             :         // Only ROMFS enabled
    1048           0 :         return LUA_PATH_ROMFS;
    1049             :     }
    1050             : 
    1051             :     // Nothing enabled?
    1052           0 :     return "";
    1053             : }
    1054             : 
    1055             : // Simple print to GCS or over CAN
    1056          20 : int lua_print(lua_State *L) {
    1057             :     // Only support a single argument
    1058          20 :     binding_argcheck(L, 1);
    1059             : 
    1060          20 :     GCS_SEND_TEXT(MAV_SEVERITY_DEBUG, "%s", luaL_checkstring(L, 1));
    1061             : 
    1062          20 :     return 0;
    1063             : }
    1064             : 
    1065             : #if AP_RANGEFINDER_ENABLED
    1066       17066 : int lua_range_finder_handle_script_msg(lua_State *L) {
    1067             :     // Arg 1 => self (an instance of rangefinder_backend)
    1068             :     // Arg 2 => a float distance or a RangeFinder_State user data
    1069       17066 :     binding_argcheck(L, 2);
    1070             : 
    1071             :     // check_AP_RangeFinder_Backend aborts if not found. No need to check for null
    1072       17066 :     AP_RangeFinder_Backend * ud = *check_AP_RangeFinder_Backend(L, 1);
    1073             : 
    1074       17066 :     bool result = false;
    1075             : 
    1076             :     // Check to see if the first argument is the state structure.
    1077       17066 :     const void *state_arg = luaL_testudata(L, 2, "RangeFinder_State");
    1078       17066 :     if (state_arg != nullptr) {
    1079       17063 :         result = ud->handle_script_msg(*static_cast<const RangeFinder::RangeFinder_State *>(state_arg));
    1080             : 
    1081             :     } else {
    1082             :         // Otherwise assume the argument is a number and set the measurement.
    1083           3 :         result = ud->handle_script_msg(luaL_checknumber(L, 2));
    1084             :     }
    1085             : 
    1086       17066 :     lua_pushboolean(L, result);
    1087       17066 :     return 1;
    1088             : }
    1089             : #endif  // AP_RANGEFINDER_ENABLED
    1090             : 
    1091             : /*
    1092             :   Lua raised an error outside protected mode. Outside protected mode, our code
    1093             :   doesn't call functions which can raise errors, so this shouldn't happen (tm).
    1094             :  */
    1095           0 : void lua_abort()
    1096             : {
    1097           0 :     INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
    1098             : #if AP_SIM_ENABLED
    1099           0 :     AP_HAL::panic("lua_abort called");
    1100             : #else
    1101             :     while (true) { // scripts will stop but the rest of the system will run
    1102           0 :         hal.scheduler->delay(1000);
    1103             :     }
    1104             : #endif
    1105             : }
    1106             : 
    1107             : #if (HAL_GCS_ENABLED && !defined(HAL_BUILD_AP_PERIPH))
    1108             : /*
    1109             :   implement gcs:command_int() access to MAV_CMD_xxx commands
    1110             :  */
    1111          16 : int lua_GCS_command_int(lua_State *L)
    1112             : {
    1113          16 :     GCS *_gcs = check_GCS(L);
    1114          16 :     binding_argcheck(L, 3);
    1115             : 
    1116          16 :     const uint16_t command = get_uint16_t(L, 2);
    1117          16 :     if (!lua_istable(L, 3)) {
    1118             :         // must have parameter table
    1119           0 :         return 0;
    1120             :     }
    1121             : 
    1122          16 :     mavlink_command_int_t pkt {};
    1123             : 
    1124          16 :     pkt.command = command;
    1125             : 
    1126          16 :     float *params = &pkt.param1;
    1127          16 :     int32_t *xy = &pkt.x;
    1128             : 
    1129             :     // extract the first 4 parameters as floats
    1130          80 :     for (uint8_t i=0; i<4; i++) {
    1131          64 :         char pname[3] { 'p' , char('1' + i), 0 };
    1132          64 :         lua_pushstring(L, pname);
    1133          64 :         lua_gettable(L, 3);
    1134          64 :         if (lua_isnumber(L, -1)) {
    1135          42 :             params[i] = lua_tonumber(L, -1);
    1136             :         }
    1137          64 :         lua_pop(L, 1);
    1138             :     }
    1139             : 
    1140             :     // extract the xy values
    1141          48 :     for (uint8_t i=0; i<2; i++) {
    1142          32 :         const char *names[] = { "x", "y" };
    1143          32 :         lua_pushstring(L, names[i]);
    1144          32 :         lua_gettable(L, 3);
    1145          32 :         if (lua_isinteger(L, -1)) {
    1146          12 :             xy[i] = lua_tointeger(L, -1);
    1147             :         }
    1148          32 :         lua_pop(L, 1);
    1149             :     }
    1150             : 
    1151             :     // and z
    1152          16 :     lua_pushstring(L, "z");
    1153          16 :     lua_gettable(L, 3);
    1154          16 :     if (lua_isnumber(L, -1)) {
    1155          12 :         pkt.z = lua_tonumber(L, -1);
    1156             :     }
    1157          16 :     lua_pop(L, 1);
    1158             : 
    1159             :     // optional frame
    1160          16 :     lua_pushstring(L, "frame");
    1161          16 :     lua_gettable(L, 3);
    1162          16 :     if (lua_isinteger(L, -1)) {
    1163          16 :         pkt.frame = lua_tointeger(L, -1);
    1164             :     }
    1165          16 :     lua_pop(L, 1);
    1166             :     
    1167             :     // call the interface with scheduler lock
    1168          16 :     WITH_SEMAPHORE(AP::scheduler().get_semaphore());
    1169             : 
    1170          16 :     auto result = _gcs->lua_command_int_packet(pkt);
    1171             : 
    1172             :     // Return the resulting MAV_RESULT
    1173          16 :     lua_pushinteger(L, result);
    1174             : 
    1175          16 :     return 1;
    1176          16 : }
    1177             : #endif
    1178             : 
    1179             : #if HAL_ENABLE_DRONECAN_DRIVERS
    1180             : /*
    1181             :   get FlexDebug from a DroneCAN node
    1182             :  */
    1183           0 : int lua_DroneCAN_get_FlexDebug(lua_State *L)
    1184             : {
    1185           0 :     binding_argcheck(L, 4);
    1186             : 
    1187           0 :     const uint8_t bus = get_uint8_t(L, 1);
    1188           0 :     const uint8_t node_id = get_uint8_t(L, 2);
    1189           0 :     const uint16_t msg_id = get_uint16_t(L, 3);
    1190           0 :     uint32_t tstamp_us = get_uint32(L, 4, 0, UINT32_MAX);
    1191             : 
    1192           0 :     const auto *dc = AP_DroneCAN::get_dronecan(bus);
    1193           0 :     if (dc == nullptr) {
    1194           0 :         return 0;
    1195             :     }
    1196             :     dronecan_protocol_FlexDebug msg;
    1197             : 
    1198           0 :     if (!dc->get_FlexDebug(node_id, msg_id, tstamp_us, msg)) {
    1199           0 :         return 0;
    1200             :     }
    1201             : 
    1202           0 :     *new_uint32_t(L) = tstamp_us;
    1203           0 :     lua_pushlstring(L, (const char *)msg.u8.data, msg.u8.len);
    1204             : 
    1205           0 :     return 2;
    1206             : }
    1207             : #endif // HAL_ENABLE_DRONECAN_DRIVERS
    1208             : 
    1209             : #if AP_GPS_ENABLED
    1210           0 : int lua_gps_inject_data(lua_State *L)
    1211             : {
    1212           0 :     binding_argcheck(L, 2);
    1213           0 :     luaL_checkudata(L, 1, "gps");
    1214             : 
    1215           0 :     size_t len = 0;
    1216           0 :     const char *data = luaL_checklstring(L, 2, &len);
    1217             : 
    1218           0 :     if (len > 0 && len <= UINT16_MAX)
    1219             :     {
    1220           0 :         AP::gps().inject_data((const uint8_t *)data, (uint16_t)len);
    1221             :     }
    1222             : 
    1223           0 :     return 0;
    1224             : }
    1225             : 
    1226             : #endif  // AP_GPS_ENABLED
    1227             : 
    1228             : #if AP_AHRS_ENABLED
    1229             : /*
    1230             :   deprecated compatibility binding for the Vector3f-returning
    1231             :   AP_AHRS::wind_estimate() method which has been removed from the AHRS
    1232             :   interface.  The validity of the estimate is discarded here and the
    1233             :   vector returned regardless; it may be zero or stale.  Scripts should
    1234             :   use ahrs:get_wind() instead.
    1235             : 
    1236             :   the generator can not attach a deprecation warning to a manual
    1237             :   binding, so it is emitted here in the same manner as the generated
    1238             :   bindings do it.
    1239             :  */
    1240           0 : int lua_AP_AHRS_wind_estimate(lua_State *L)
    1241             : {
    1242           0 :     binding_argcheck(L, 1);
    1243           0 :     AP_AHRS *ahrs = check_AP_AHRS(L);
    1244             : 
    1245             :     static bool warned;
    1246           0 :     if (!warned) {
    1247           0 :         lua_scripts::set_and_print_new_error_message(MAV_SEVERITY_WARNING, "ahrs:wind_estimate Use get_wind");
    1248           0 :         warned = true;
    1249             :     }
    1250             : 
    1251           0 :     Vector3f wind;
    1252             :     {
    1253           0 :         WITH_SEMAPHORE(ahrs->get_semaphore());
    1254           0 :         IGNORE_RETURN(ahrs->get_wind(wind));
    1255           0 :     }
    1256             : 
    1257           0 :     *new_Vector3f(L) = wind;
    1258             : 
    1259           0 :     return 1;
    1260             : }
    1261             : #endif  // AP_AHRS_ENABLED
    1262             : 
    1263             : #if AP_SCRIPTING_BINDING_VEHICLE_ENABLED
    1264          47 : int lua_AP_Vehicle_set_target_velocity_NED(lua_State *L)
    1265             : {
    1266          47 :     const int args = lua_gettop(L);
    1267             : 
    1268          47 :     if (args > 3) {
    1269           0 :         return luaL_argerror(L, args, "too many arguments");
    1270          47 :     } else if (args < 2) {
    1271           0 :         return luaL_argerror(L, args, "too few arguments");
    1272             :     }
    1273             : 
    1274          47 :     AP_Vehicle * ud = check_AP_Vehicle(L);
    1275          47 :     Vector3f & data_2 = *check_Vector3f(L, 2);
    1276             : 
    1277          47 :     bool yaw_to_target = false;
    1278             : 
    1279          47 :     if (args == 3) {
    1280           0 :         yaw_to_target = static_cast<bool>(lua_toboolean(L, 3));
    1281             :     }
    1282             : #if AP_SCHEDULER_ENABLED
    1283          47 :     AP::scheduler().get_semaphore().take_blocking();
    1284             : #endif
    1285          47 :     const bool data = static_cast<bool>(ud->set_target_velocity_NED(
    1286             :             data_2,
    1287             :             yaw_to_target));
    1288             : 
    1289             : #if AP_SCHEDULER_ENABLED
    1290          47 :     AP::scheduler().get_semaphore().give();
    1291             : #endif
    1292          47 :     lua_pushboolean(L, data);
    1293          47 :     return 1;
    1294             : }
    1295             : #endif // AP_SCRIPTING_BINDING_VEHICLE_ENABLED
    1296             : 
    1297             : #endif  // AP_SCRIPTING_ENABLED

Generated by: LCOV version 1.14