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
|