LCOV - code coverage report
Current view: top level - SITL - SIM_JSON_Master.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 6 73 8.2 %
Date: 2026-09-09 11:02:08 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   Send and receive JSON backend data to alow a second AP instance to ride along
      17             : */
      18             : 
      19             : #include "SIM_JSON_Master.h"
      20             : 
      21             : #if AP_SIM_JSON_MASTER_ENABLED
      22             : 
      23             : #include <AP_Logger/AP_Logger.h>
      24             : #include <errno.h>
      25             : #include <stdio.h>
      26             : #include <SITL/SITL.h>
      27             : 
      28             : using namespace SITL;
      29             : 
      30           0 : void JSON_Master::init(const int32_t num_slaves)
      31             : {
      32           0 :     socket_list *list = &_list;
      33           0 :     uint8_t i = 1;
      34           0 :     for (i = 1 ; i <= num_slaves; i++) {
      35             :         // init each socket and instance
      36           0 :         list->instance = i;
      37           0 :         uint16_t port = 9002 + 10 * i;
      38             : 
      39           0 :         if (!list->sock_in.reuseaddress()) {
      40           0 :             AP_HAL::panic("JSON master: socket reuseaddress failed on port: %d - %s", port, strerror(errno));
      41             :         }
      42             : 
      43           0 :         if (!list->sock_in.bind("127.0.0.1", port)) {
      44           0 :             AP_HAL::panic("JSON master: socket reuseaddress failed on port: %d - %s", port, strerror(errno));
      45             :         }
      46             : 
      47           0 :         if (!list->sock_in.set_blocking(false)) {
      48           0 :             AP_HAL::panic( "JSON master: socket set_blocking(false) failed on port: %d - %s", port, strerror(errno));
      49             :         }
      50             : 
      51           0 :         printf("Slave %u: listening on %u\n", list->instance, port);
      52           0 :         list->next = NEW_NOTHROW socket_list;
      53           0 :         list = list->next;
      54             : 
      55           0 :         initialized = true;
      56             :     }
      57           0 : }
      58             : 
      59             : // Receive PWM outs from ride along controlers
      60   187275482 : void JSON_Master::receive(struct sitl_input &input)
      61             : {
      62   187275482 :     if (!initialized) {
      63   187275482 :         return;
      64             :     }
      65             : 
      66           0 :     uint8_t master_instance = AP::sitl()->ride_along_master.get();
      67             : 
      68           0 :     for (socket_list *list = &_list; list->next; list=list->next) {
      69             :         // cycle through all ride along instances
      70             :         struct servo_packet {
      71             :             uint16_t magic;
      72             :             uint16_t frame_rate;
      73             :             uint32_t frame_count;
      74             :             uint16_t pwm[16];
      75           0 :         } buffer{};
      76             : 
      77             :         while (true) {
      78           0 :             ssize_t ret = list->sock_in.recv(&buffer, sizeof(buffer), 100);
      79           0 :             if (ret == 0) {
      80             :                 // wait some more
      81           0 :                 continue;
      82             :             }
      83           0 :             if (buffer.magic != 18458) {
      84             :                 // magic value does not match
      85           0 :                 continue;
      86             :             }
      87           0 :             if (!list->connected) {
      88             :                 // connect back to the last address for send
      89             :                 uint16_t port;
      90           0 :                 const char *_ip = nullptr;
      91           0 :                 list->sock_in.last_recv_address(_ip, port);
      92           0 :                 list->connected = list->sock_out.connect(_ip, port) && (port != 0);
      93           0 :                 if (list->connected) {
      94           0 :                     printf("Slave %u connected to %s:%u\n", list->instance, _ip, port);
      95             :                 }
      96             :             }
      97           0 :             if (list->connected) {
      98           0 :                 break;
      99             :             }
     100           0 :         }
     101             : 
     102             : #if HAL_LOGGING_ENABLED
     103           0 :         const bool use_servos = list->instance == master_instance;
     104             : 
     105             : // @LoggerMessage: SLV1
     106             : // @Description: Log data received from JSON simulator 1
     107             : // @Field: TimeUS: Time since system startup (us)
     108             : // @Field: Instance: Slave instance
     109             : // @Field: magic: magic JSON protocol key
     110             : // @Field: frame_rate: Slave instance's desired frame rate
     111             : // @Field: frame_count: Slave instance's current frame count
     112             : // @Field: active: 1 if the servo outputs are being used from this instance
     113           0 :         AP::logger().WriteStreaming("SLV1", "TimeUS,Instance,magic,frame_rate,frame_count,active",
     114             :                        "s#----",
     115             :                        "F?????",
     116             :                        "QBHHIB",
     117             :                        AP_HAL::micros64(),
     118           0 :                        list->instance,
     119           0 :                        buffer.magic,
     120           0 :                        buffer.frame_rate,
     121             :                        buffer.frame_count,
     122             :                        use_servos);
     123             : 
     124             : // @LoggerMessage: SLV2
     125             : // @Description: Log data received from JSON simulator 2
     126             : // @Field: TimeUS: Time since system startup
     127             : // @Field: Instance: Slave instance
     128             : // @Field: C1: channel 1 output
     129             : // @Field: C2: channel 2 output
     130             : // @Field: C3: channel 3 output
     131             : // @Field: C4: channel 4 output
     132             : // @Field: C5: channel 5 output
     133             : // @Field: C6: channel 6 output
     134             : // @Field: C7: channel 7 output
     135             : // @Field: C8: channel 8 output
     136             : // @Field: C9: channel 9 output
     137             : // @Field: C10: channel 10 output
     138             : // @Field: C11: channel 11 output
     139             : // @Field: C12: channel 12 output
     140             : // @Field: C13: channel 13 output
     141             : // @Field: C14: channel 14 output
     142           0 :         AP::logger().WriteStreaming("SLV2", "TimeUS,Instance,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14",
     143             :                        "s#YYYYYYYYYYYYYY",
     144             :                        "F?--------------",
     145             :                        "QBHHHHHHHHHHHHHH",
     146             :                        AP_HAL::micros64(),
     147           0 :                        list->instance,
     148           0 :                        buffer.pwm[0],
     149           0 :                        buffer.pwm[1],
     150           0 :                        buffer.pwm[2],
     151           0 :                        buffer.pwm[3],
     152           0 :                        buffer.pwm[4],
     153           0 :                        buffer.pwm[5],
     154           0 :                        buffer.pwm[6],
     155           0 :                        buffer.pwm[7],
     156           0 :                        buffer.pwm[8],
     157           0 :                        buffer.pwm[9],
     158           0 :                        buffer.pwm[10],
     159           0 :                        buffer.pwm[11],
     160           0 :                        buffer.pwm[12],
     161           0 :                        buffer.pwm[13]);
     162             : #endif
     163             : 
     164           0 :         if (list->instance == master_instance) {
     165             :             // Use the servo outs from this instance
     166           0 :             memcpy(input.servos,buffer.pwm,sizeof(buffer.pwm));
     167             :         }
     168             :     }
     169             : }
     170             : 
     171             : // send vehicle state to ride along controlers
     172   187275482 : void JSON_Master::send(const struct sitl_fdm &output, const Vector3d &position)
     173             : {
     174   187275482 :     if (!initialized) {
     175   187275482 :         return;
     176             :     }
     177             : 
     178             :     // message is the same to all slaves
     179           0 :     int length = asprintf(&json_out,"\n{\"timestamp\":%f,\"imu\":{\"gyro\":[%f,%f,%f],\"accel_body\":[%f,%f,%f]},\"position\":[%f,%f,%f],\"quaternion\":[%f,%f,%f,%f],\"velocity\":[%f,%f,%f],\"no_time_sync\":1}\n",
     180           0 :                             output.timestamp_us * 1e-6,
     181           0 :                             radians(output.rollRate), radians(output.pitchRate), radians(output.yawRate),
     182           0 :                             output.xAccel, output.yAccel, output.zAccel,
     183           0 :                             position.x, position.y, position.z,
     184           0 :                             output.quaternion.q1, output.quaternion.q2, output.quaternion.q3, output.quaternion.q4,
     185           0 :                             output.speedN, output.speedE, output.speedD);
     186             : 
     187           0 :     for (socket_list *list = &_list; list->next; list=list->next) {
     188           0 :         list->sock_out.send(json_out,length);
     189             :     }
     190           0 :     free(json_out);
     191             : }
     192             : 
     193             : 
     194             : #endif  // AP_SIM_JSON_MASTER_ENABLED

Generated by: LCOV version 1.14