LCOV - code coverage report
Current view: top level - AP_SerialManager - AP_SerialManager.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 173 267 64.8 %
Date: 2026-09-09 11:02:08 Functions: 19 23 82.6 %

          Line data    Source code
       1             : /*
       2             :    Please contribute your ideas! See https://ardupilot.club/dev for details
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : /*
      18             :   SerialManager allows defining the protocol and baud rates for the available
      19             :   serial ports and provides helper functions so objects (like a gimbal) can
      20             :   find which serial port they should use
      21             :  */
      22             : 
      23             : #include "AP_SerialManager_config.h"
      24             : 
      25             : #if AP_SERIALMANAGER_ENABLED
      26             : 
      27             : #include <AP_HAL/AP_HAL.h>
      28             : #include <AP_Math/AP_Math.h>
      29             : #include <AP_RCProtocol/AP_RCProtocol.h>
      30             : #include <AP_MSP/AP_MSP.h>
      31             : #include <AP_InertialSensor/AP_InertialSensor.h>
      32             : #include "AP_SerialManager.h"
      33             : #include <GCS_MAVLink/GCS.h>
      34             : 
      35             : extern const AP_HAL::HAL& hal;
      36             : 
      37             : #ifndef DEFAULT_SERIAL0_PROTOCOL
      38             : #define DEFAULT_SERIAL0_PROTOCOL SerialProtocol_MAVLink2
      39             : #endif
      40             : #ifndef DEFAULT_SERIAL0_BAUD
      41             : #define DEFAULT_SERIAL0_BAUD AP_SERIALMANAGER_CONSOLE_BAUD
      42             : #endif
      43             : #ifdef HAL_SERIAL0_PROTOCOL
      44             : #error "Please use DEFAULT_SERIAL0_PROTOCOL"
      45             : #endif
      46             : 
      47             : #ifndef DEFAULT_SERIAL1_PROTOCOL
      48             : #define DEFAULT_SERIAL1_PROTOCOL SerialProtocol_MAVLink2
      49             : #endif
      50             : #ifndef DEFAULT_SERIAL1_BAUD
      51             : #define DEFAULT_SERIAL1_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
      52             : #endif
      53             : #ifndef DEFAULT_SERIAL1_OPTIONS
      54             : #define DEFAULT_SERIAL1_OPTIONS 0
      55             : #endif
      56             : #ifdef HAL_SERIAL1_PROTOCOL
      57             : #error "Please use DEFAULT_SERIAL1_PROTOCOL"
      58             : #endif
      59             : 
      60             : #ifndef DEFAULT_SERIAL2_PROTOCOL
      61             : #define DEFAULT_SERIAL2_PROTOCOL SerialProtocol_MAVLink2
      62             : #endif
      63             : #ifndef DEFAULT_SERIAL2_BAUD
      64             : #define DEFAULT_SERIAL2_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
      65             : #endif
      66             : #ifndef DEFAULT_SERIAL2_OPTIONS
      67             : #define DEFAULT_SERIAL2_OPTIONS 0
      68             : #endif
      69             : #ifdef HAL_SERIAL2_PROTOCOL
      70             : #error "Please use DEFAULT_SERIAL2_PROTOCOL"
      71             : #endif
      72             : 
      73             : #ifndef DEFAULT_SERIAL3_PROTOCOL
      74             : #define DEFAULT_SERIAL3_PROTOCOL SerialProtocol_GPS
      75             : #endif
      76             : #ifndef DEFAULT_SERIAL3_BAUD
      77             : #define DEFAULT_SERIAL3_BAUD AP_SERIALMANAGER_GPS_BAUD/1000
      78             : #endif
      79             : #ifndef DEFAULT_SERIAL3_OPTIONS
      80             : #define DEFAULT_SERIAL3_OPTIONS 0
      81             : #endif
      82             : #ifdef HAL_SERIAL3_PROTOCOL
      83             : #error "Please use DEFAULT_SERIAL3_PROTOCOL"
      84             : #endif
      85             : 
      86             : #ifndef DEFAULT_SERIAL4_PROTOCOL
      87             : #define DEFAULT_SERIAL4_PROTOCOL SerialProtocol_GPS
      88             : #endif
      89             : #ifndef DEFAULT_SERIAL4_BAUD
      90             : #define DEFAULT_SERIAL4_BAUD AP_SERIALMANAGER_GPS_BAUD/1000
      91             : #endif
      92             : #ifndef DEFAULT_SERIAL4_OPTIONS
      93             : #define DEFAULT_SERIAL4_OPTIONS 0
      94             : #endif
      95             : #ifdef HAL_SERIAL4_PROTOCOL
      96             : #error "Please use DEFAULT_SERIAL4_PROTOCOL"
      97             : #endif
      98             : 
      99             : #ifndef DEFAULT_SERIAL5_PROTOCOL
     100             : #define DEFAULT_SERIAL5_PROTOCOL SerialProtocol_None
     101             : #endif
     102             : #ifndef DEFAULT_SERIAL5_BAUD
     103             : #define DEFAULT_SERIAL5_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
     104             : #endif
     105             : #ifndef DEFAULT_SERIAL5_OPTIONS
     106             : #define DEFAULT_SERIAL5_OPTIONS 0
     107             : #endif
     108             : #ifdef HAL_SERIAL5_PROTOCOL
     109             : #error "Please use DEFAULT_SERIAL5_PROTOCOL"
     110             : #endif
     111             : 
     112             : #ifndef DEFAULT_SERIAL6_PROTOCOL
     113             : #define DEFAULT_SERIAL6_PROTOCOL SerialProtocol_None
     114             : #endif
     115             : #ifndef DEFAULT_SERIAL6_BAUD
     116             : #define DEFAULT_SERIAL6_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
     117             : #endif
     118             : #ifndef DEFAULT_SERIAL6_OPTIONS
     119             : #define DEFAULT_SERIAL6_OPTIONS 0
     120             : #endif
     121             : #ifdef HAL_SERIAL6_PROTOCOL
     122             : #error "Please use DEFAULT_SERIAL6_PROTOCOL"
     123             : #endif
     124             : 
     125             : #ifndef DEFAULT_SERIAL7_PROTOCOL
     126             : #define DEFAULT_SERIAL7_PROTOCOL SerialProtocol_None
     127             : #endif
     128             : #ifndef DEFAULT_SERIAL7_BAUD
     129             : #define DEFAULT_SERIAL7_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
     130             : #endif
     131             : #ifndef DEFAULT_SERIAL7_OPTIONS
     132             : #define DEFAULT_SERIAL7_OPTIONS 0
     133             : #endif
     134             : #ifdef HAL_SERIAL7_PROTOCOL
     135             : #error "Please use DEFAULT_SERIAL7_PROTOCOL"
     136             : #endif
     137             : 
     138             : #ifndef DEFAULT_SERIAL8_PROTOCOL
     139             : #define DEFAULT_SERIAL8_PROTOCOL SerialProtocol_None
     140             : #endif
     141             : #ifndef DEFAULT_SERIAL8_BAUD
     142             : #define DEFAULT_SERIAL8_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
     143             : #endif
     144             : #ifndef DEFAULT_SERIAL8_OPTIONS
     145             : #define DEFAULT_SERIAL8_OPTIONS 0
     146             : #endif
     147             : #ifdef HAL_SERIAL8_PROTOCOL
     148             : #error "Please use DEFAULT_SERIAL8_PROTOCOL"
     149             : #endif
     150             : 
     151             : #ifndef DEFAULT_SERIAL9_PROTOCOL
     152             : #define DEFAULT_SERIAL9_PROTOCOL SerialProtocol_None
     153             : #endif
     154             : #ifndef DEFAULT_SERIAL9_BAUD
     155             : #define DEFAULT_SERIAL9_BAUD AP_SERIALMANAGER_MAVLINK_BAUD/1000
     156             : #endif
     157             : #ifndef DEFAULT_SERIAL9_OPTIONS
     158             : #define DEFAULT_SERIAL9_OPTIONS 0
     159             : #endif
     160             : #ifdef HAL_SERIAL9_PROTOCOL
     161             : #error "Please use DEFAULT_SERIAL9_PROTOCOL"
     162             : #endif
     163             : 
     164             : const AP_Param::GroupInfo AP_SerialManager::var_info[] = {
     165             : #if HAL_HAVE_SERIAL0_PARAMS
     166             :     // @Param: 0_BAUD
     167             :     // @DisplayName: Serial0 baud rate
     168             :     // @Description: The baud rate used on the USB console. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     169             :     // @Values: 1:1200,2:2400,4:4800,9:9600,19:19200,38:38400,57:57600,111:111100,115:115200,230:230400,256:256000,460:460800,500:500000,921:921600,1500:1.5MBaud,2000:2MBaud,12500000:12.5MBaud
     170             :     // @Range: 1 20000000
     171             :     // @User: Standard
     172             :     AP_GROUPINFO("0_BAUD",  0, AP_SerialManager, state[0].baud, DEFAULT_SERIAL0_BAUD/1000),
     173             : 
     174             :     // @Param: 0_PROTOCOL
     175             :     // @DisplayName: Console protocol selection
     176             :     // @Description: Control what protocol to use on the console. 
     177             :     // @Values: 1:MAVLink1, 2:MAVLink2
     178             :     // @User: Standard
     179             :     // @RebootRequired: True
     180             :     AP_GROUPINFO("0_PROTOCOL",  11, AP_SerialManager, state[0].protocol, SerialProtocol_MAVLink2),
     181             : #endif
     182             : 
     183             : #if HAL_HAVE_SERIAL1_PARAMS
     184             :     // @Param: 1_PROTOCOL
     185             :     // @DisplayName: Telem1 protocol selection
     186             :     // @Description: Control what protocol to use on the Telem1 port. Note that the Frsky options require external converter hardware. See the wiki for details.
     187             :     // @SortValues: AlphabeticalZeroAtTop
     188             :     // @Values: -1:None, 1:MAVLink1, 2:MAVLink2, 3:Frsky D, 4:Frsky SPort, 5:GPS, 7:Alexmos Gimbal Serial, 8:Gimbal, 9:Rangefinder, 10:FrSky SPort Passthrough (OpenTX), 11:Lidar360, 13:Beacon, 14:Volz servo out, 15:SBus servo out, 16:ESC Telemetry, 17:Devo Telemetry, 18:OpticalFlow, 19:RobotisServo, 20:NMEA Output, 21:WindVane, 22:SLCAN, 23:RCIN, 24:EFI Serial, 25:LTM, 26:RunCam, 27:HottTelem, 28:Scripting, 29:Crossfire VTX, 30:Generator, 31:Winch, 32:MSP, 33:DJI FPV, 34:AirSpeed, 35:ADSB, 36:AHRS, 37:SmartAudio, 38:FETtecOneWire, 39:Torqeedo, 40:AIS, 41:CoDevESC, 42:DisplayPort, 43:MAVLink High Latency, 44:IRC Tramp, 45:DDS XRCE, 46:IMUDATA, 48:PPP, 49:i-BUS Telemetry, 50: IOMCU
     189             :     // @User: Standard
     190             :     // @RebootRequired: True
     191             :     AP_GROUPINFO("1_PROTOCOL",  1, AP_SerialManager, state[1].protocol, DEFAULT_SERIAL1_PROTOCOL),
     192             : 
     193             :     // @Param: 1_BAUD
     194             :     // @DisplayName: Telem1 Baud Rate
     195             :     // @Description: The baud rate used on the Telem1 port. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     196             :     // @Values: 1:1200,2:2400,4:4800,9:9600,19:19200,38:38400,57:57600,111:111100,115:115200,230:230400,256:256000,460:460800,500:500000,921:921600,1500:1.5MBaud,2000:2MBaud,12500000:12.5MBaud
     197             :     // @Range: 1 20000000
     198             :     // @User: Standard
     199             :     AP_GROUPINFO("1_BAUD", 2, AP_SerialManager, state[1].baud, DEFAULT_SERIAL1_BAUD),
     200             : #endif
     201             : 
     202             : #if HAL_HAVE_SERIAL2_PARAMS
     203             :     // @Param: 2_PROTOCOL
     204             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     205             :     // @DisplayName: Telemetry 2 protocol selection
     206             :     // @Description: Control what protocol to use on the Telem2 port. Note that the Frsky options require external converter hardware. See the wiki for details.
     207             :     AP_GROUPINFO("2_PROTOCOL",  3, AP_SerialManager, state[2].protocol, DEFAULT_SERIAL2_PROTOCOL),
     208             : 
     209             :     // @Param: 2_BAUD
     210             :     // @CopyFieldsFrom: SERIAL1_BAUD
     211             :     // @DisplayName: Telemetry 2 Baud Rate
     212             :     // @Description: The baud rate of the Telem2 port. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     213             :     AP_GROUPINFO("2_BAUD", 4, AP_SerialManager, state[2].baud, DEFAULT_SERIAL2_BAUD),
     214             : #endif
     215             : 
     216             : #if HAL_HAVE_SERIAL3_PARAMS
     217             :     // @Param: 3_PROTOCOL
     218             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     219             :     // @DisplayName: Serial 3 (GPS) protocol selection
     220             :     // @Description: Control what protocol Serial 3 (GPS) should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     221             :     AP_GROUPINFO("3_PROTOCOL",  5, AP_SerialManager, state[3].protocol, DEFAULT_SERIAL3_PROTOCOL),
     222             : 
     223             :     // @Param: 3_BAUD
     224             :     // @CopyFieldsFrom: SERIAL1_BAUD
     225             :     // @DisplayName: Serial 3 (GPS) Baud Rate
     226             :     // @Description: The baud rate used for the Serial 3 (GPS). Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     227             :     AP_GROUPINFO("3_BAUD", 6, AP_SerialManager, state[3].baud, DEFAULT_SERIAL3_BAUD),
     228             : #endif
     229             : 
     230             : #if HAL_HAVE_SERIAL4_PARAMS
     231             :     // @Param: 4_PROTOCOL
     232             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     233             :     // @DisplayName: Serial4 protocol selection
     234             :     // @Description: Control what protocol Serial4 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     235             :     AP_GROUPINFO("4_PROTOCOL",  7, AP_SerialManager, state[4].protocol, DEFAULT_SERIAL4_PROTOCOL),
     236             : 
     237             :     // @Param: 4_BAUD
     238             :     // @CopyFieldsFrom: SERIAL1_BAUD
     239             :     // @DisplayName: Serial 4 Baud Rate
     240             :     // @Description: The baud rate used for Serial4. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     241             :     AP_GROUPINFO("4_BAUD", 8, AP_SerialManager, state[4].baud, DEFAULT_SERIAL4_BAUD),
     242             : #endif
     243             : 
     244             : #if HAL_HAVE_SERIAL5_PARAMS
     245             :     // @Param: 5_PROTOCOL
     246             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     247             :     // @DisplayName: Serial5 protocol selection
     248             :     // @Description: Control what protocol Serial5 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     249             :     AP_GROUPINFO("5_PROTOCOL",  9, AP_SerialManager, state[5].protocol, DEFAULT_SERIAL5_PROTOCOL),
     250             : 
     251             :     // @Param: 5_BAUD
     252             :     // @CopyFieldsFrom: SERIAL1_BAUD
     253             :     // @DisplayName: Serial 5 Baud Rate
     254             :     // @Description: The baud rate used for Serial5. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     255             :     AP_GROUPINFO("5_BAUD", 10, AP_SerialManager, state[5].baud, DEFAULT_SERIAL5_BAUD),
     256             : #endif
     257             : 
     258             :     // index 11 used by 0_PROTOCOL
     259             :         
     260             : #if HAL_HAVE_SERIAL6_PARAMS
     261             :     // @Param: 6_PROTOCOL
     262             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     263             :     // @DisplayName: Serial6 protocol selection
     264             :     // @Description: Control what protocol Serial6 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     265             :     AP_GROUPINFO("6_PROTOCOL",  12, AP_SerialManager, state[6].protocol, DEFAULT_SERIAL6_PROTOCOL),
     266             : 
     267             :     // @Param: 6_BAUD
     268             :     // @CopyFieldsFrom: SERIAL1_BAUD
     269             :     // @DisplayName: Serial 6 Baud Rate
     270             :     // @Description: The baud rate used for Serial6. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     271             :     AP_GROUPINFO("6_BAUD", 13, AP_SerialManager, state[6].baud, DEFAULT_SERIAL6_BAUD),
     272             : #endif
     273             : 
     274             : #if HAL_HAVE_SERIAL1_PARAMS
     275             :     // @Param: 1_OPTIONS
     276             :     // @DisplayName: Telem1 options
     277             :     // @Description: Control over UART options. The InvertRX option controls invert of the receive pin. The InvertTX option controls invert of the transmit pin. The HalfDuplex option controls half-duplex (onewire) mode, where both transmit and receive is done on the transmit wire. The Swap option allows the RX and TX pins to be swapped on STM32F7 based boards.  NOTE that two bits have moved from this parameter into MAVn_OPTIONS!
     278             :     // @Bitmask: 0:InvertRX, 1:InvertTX, 2:HalfDuplex, 3:SwapTXRX, 4: RX_PullDown, 5: RX_PullUp, 6: TX_PullDown, 7: TX_PullUp, 8: RX_NoDMA, 9: TX_NoDMA, 10: Don't forward mavlink to/from (moved to MAVn_OPTIONS >4.7), 11: DisableFIFO, 12: Ignore Streamrate (moved to MAVn_OPTIONS >4.7)
     279             :     // @User: Advanced
     280             :     // @RebootRequired: True
     281             :     AP_GROUPINFO("1_OPTIONS",  14, AP_SerialManager, state[1].options, DEFAULT_SERIAL1_OPTIONS),
     282             : #endif
     283             : 
     284             : #if HAL_HAVE_SERIAL2_PARAMS
     285             :     // @Param: 2_OPTIONS
     286             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     287             :     // @DisplayName: Telem2 options
     288             :     AP_GROUPINFO("2_OPTIONS",  15, AP_SerialManager, state[2].options, DEFAULT_SERIAL2_OPTIONS),
     289             : #endif
     290             : 
     291             : #if HAL_HAVE_SERIAL3_PARAMS
     292             :     // @Param: 3_OPTIONS
     293             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     294             :     // @DisplayName: Serial3 options
     295             :     AP_GROUPINFO("3_OPTIONS",  16, AP_SerialManager, state[3].options, DEFAULT_SERIAL3_OPTIONS),
     296             : #endif
     297             : 
     298             : #if HAL_HAVE_SERIAL4_PARAMS
     299             :     // @Param: 4_OPTIONS
     300             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     301             :     // @DisplayName: Serial4 options
     302             :     AP_GROUPINFO("4_OPTIONS",  17, AP_SerialManager, state[4].options, DEFAULT_SERIAL4_OPTIONS),
     303             : #endif
     304             : 
     305             : #if HAL_HAVE_SERIAL5_PARAMS
     306             :     // @Param: 5_OPTIONS
     307             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     308             :     // @DisplayName: Serial5 options
     309             :     AP_GROUPINFO("5_OPTIONS",  18, AP_SerialManager, state[5].options, DEFAULT_SERIAL5_OPTIONS),
     310             : #endif
     311             : 
     312             : #if HAL_HAVE_SERIAL6_PARAMS
     313             :     // @Param: 6_OPTIONS
     314             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     315             :     // @DisplayName: Serial6 options
     316             :     AP_GROUPINFO("6_OPTIONS",  19, AP_SerialManager, state[6].options, DEFAULT_SERIAL6_OPTIONS),
     317             : #endif
     318             : 
     319             :     // @Param: _PASS1
     320             :     // @DisplayName: Serial passthru first port
     321             :     // @Description: This sets one side of pass-through between two serial ports. Once both sides are set then all data received on either port will be passed to the other port
     322             :     // @Values: -1:Disabled,0:Serial0,1:Serial1,2:Serial2,3:Serial3,4:Serial4,5:Serial5,6:Serial6
     323             :     // @User: Advanced
     324             :     AP_GROUPINFO("_PASS1",  20, AP_SerialManager, passthru_port1, 0),
     325             : 
     326             :     // @Param: _PASS2
     327             :     // @DisplayName: Serial passthru second port
     328             :     // @Description: This sets one side of pass-through between two serial ports. Once both sides are set then all data received on either port will be passed to the other port. This parameter is normally reset to -1 on reboot, disabling passthrough. If SERIAL_PASSTIMO is set to -1 then it is not reset on reboot.
     329             :     // @Values: -1:Disabled,0:Serial0,1:Serial1,2:Serial2,3:Serial3,4:Serial4,5:Serial5,6:Serial6
     330             :     // @User: Advanced
     331             :     AP_GROUPINFO("_PASS2",  21, AP_SerialManager, passthru_port2, -1),
     332             : 
     333             :     // @Param: _PASSTIMO
     334             :     // @DisplayName: Serial passthru timeout
     335             :     // @Description: This sets a timeout for serial pass-through in seconds. When the pass-through is enabled by setting the SERIAL_PASS1 and SERIAL_PASS2 parameters then it remains in effect until no data comes from the first port for SERIAL_PASSTIMO seconds. This allows the port to revent to its normal usage (such as MAVLink connection to a GCS) when it is no longer needed. A value of 0 means no timeout. A value of -1 means no timeout and the SERIAL_PASS2 parameter is not reset on reboot.
     336             :     // @Range: -1 120
     337             :     // @Units: s
     338             :     // @User: Advanced
     339             :     AP_GROUPINFO("_PASSTIMO",  22, AP_SerialManager, passthru_timeout, 15),
     340             : 
     341             : #if HAL_HAVE_SERIAL7_PARAMS
     342             :     // @Param: 7_PROTOCOL
     343             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     344             :     // @DisplayName: Serial7 protocol selection
     345             :     // @Description: Control what protocol Serial7 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     346             :     AP_GROUPINFO("7_PROTOCOL",  23, AP_SerialManager, state[7].protocol, DEFAULT_SERIAL7_PROTOCOL),
     347             : 
     348             :     // @Param: 7_BAUD
     349             :     // @CopyFieldsFrom: SERIAL1_BAUD
     350             :     // @DisplayName: Serial 7 Baud Rate
     351             :     // @Description: The baud rate used for Serial7. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     352             :     AP_GROUPINFO("7_BAUD", 24, AP_SerialManager, state[7].baud, DEFAULT_SERIAL7_BAUD),
     353             : 
     354             :     // @Param: 7_OPTIONS
     355             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     356             :     // @DisplayName: Serial7 options
     357             :     AP_GROUPINFO("7_OPTIONS",  25, AP_SerialManager, state[7].options, 0),
     358             : #endif
     359             : 
     360             : #if HAL_HAVE_SERIAL8_PARAMS
     361             :     // @Param: 8_PROTOCOL
     362             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     363             :     // @DisplayName: Serial8 protocol selection
     364             :     // @Description: Control what protocol Serial8 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     365             :     AP_GROUPINFO("8_PROTOCOL",  26, AP_SerialManager, state[8].protocol, DEFAULT_SERIAL8_PROTOCOL),
     366             : 
     367             :     // @Param: 8_BAUD
     368             :     // @CopyFieldsFrom: SERIAL1_BAUD
     369             :     // @DisplayName: Serial 8 Baud Rate
     370             :     // @Description: The baud rate used for Serial8. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     371             :     AP_GROUPINFO("8_BAUD", 27, AP_SerialManager, state[8].baud, DEFAULT_SERIAL8_BAUD),
     372             : 
     373             :     // @Param: 8_OPTIONS
     374             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     375             :     // @DisplayName: Serial8 options
     376             :     AP_GROUPINFO("8_OPTIONS",  28, AP_SerialManager, state[8].options, 0),
     377             : #endif
     378             : 
     379             : #if HAL_HAVE_SERIAL9_PARAMS
     380             :     // @Param: 9_PROTOCOL
     381             :     // @CopyFieldsFrom: SERIAL1_PROTOCOL
     382             :     // @DisplayName: Serial9 protocol selection
     383             :     // @Description: Control what protocol Serial9 port should be used for. Note that the Frsky options require external converter hardware. See the wiki for details.
     384             :     AP_GROUPINFO("9_PROTOCOL",  29, AP_SerialManager, state[9].protocol, DEFAULT_SERIAL9_PROTOCOL),
     385             : 
     386             :     // @Param: 9_BAUD
     387             :     // @CopyFieldsFrom: SERIAL1_BAUD
     388             :     // @DisplayName: Serial 9 Baud Rate
     389             :     // @Description: The baud rate used for Serial8. Most stm32-based boards can support rates of up to 1500. If you setup a rate you cannot support and then can't connect to your board you should load a firmware from a different vehicle type. That will reset all your parameters to defaults.
     390             :     AP_GROUPINFO("9_BAUD", 30, AP_SerialManager, state[9].baud, DEFAULT_SERIAL9_BAUD),
     391             : 
     392             :     // @Param: 9_OPTIONS
     393             :     // @CopyFieldsFrom: SERIAL1_OPTIONS
     394             :     // @DisplayName: Serial9 options
     395             :     AP_GROUPINFO("9_OPTIONS",  31, AP_SerialManager, state[9].options, DEFAULT_SERIAL9_OPTIONS),
     396             : #endif
     397             : 
     398             :     AP_GROUPEND
     399             : };
     400             : 
     401             : // singleton instance
     402             : AP_SerialManager *AP_SerialManager::_singleton;
     403             : 
     404             : // Constructor
     405       23078 : AP_SerialManager::AP_SerialManager()
     406             : {
     407        2098 :     _singleton = this;
     408             :     // setup parameter defaults
     409        2098 :     AP_Param::setup_object_defaults(this, var_info);
     410        2098 : }
     411             : 
     412             : // init_console - initialise console at default baud rate
     413        4188 : void AP_SerialManager::init_console()
     414             : {
     415             :     // initialise console immediately at default size and baud
     416             : #if SERIALMANAGER_NUM_PORTS > 0
     417        4188 :     if (!init_console_done) {
     418        2094 :         init_console_done = true;
     419        2094 :         hal.serial(0)->begin(DEFAULT_SERIAL0_BAUD,
     420             :                              AP_SERIALMANAGER_CONSOLE_BUFSIZE_RX,
     421             :                              AP_SERIALMANAGER_CONSOLE_BUFSIZE_TX);
     422             :     }
     423             : #endif
     424        4188 : }
     425             : 
     426             : // init - // init - initialise serial ports
     427        2094 : void AP_SerialManager::init()
     428             : {
     429        2094 :     convert_parameters();
     430             : 
     431             :     // reset passthru port2 on boot if timeout is not -1
     432        2094 :     if (passthru_timeout != -1) {
     433        2094 :         passthru_port2.set_and_save_ifchanged(-1);
     434             :     }
     435             : 
     436             : #ifdef HAL_OTG1_CONFIG
     437             :     /*
     438             :       prevent users from changing USB protocol to other than
     439             :       MAVLink. This fixes an issue where users trying to get SLCAN
     440             :       change SERIAL0_PROTOCOL to 22 and find they can no longer connect
     441             :      */
     442             :     if (state[0].protocol != SerialProtocol_MAVLink &&
     443             :         state[0].protocol != SerialProtocol_MAVLink2) {
     444             :         state[0].protocol.set(SerialProtocol_MAVLink2);
     445             :     }
     446             : #endif
     447             : 
     448        2094 :     init_console();
     449             : 
     450             :     // initialise serial ports
     451       16752 :     for (uint8_t i=1; i<SERIALMANAGER_NUM_PORTS; i++) {
     452       14658 :         auto *uart = hal.serial(i);
     453             : 
     454       14658 :         state[i].idx = i;
     455             : 
     456       14658 :         if (uart != nullptr) {
     457       14658 :             set_options(i);
     458       14658 :             switch (state[i].protocol) {
     459        6164 :                 case SerialProtocol_None:
     460             : #if HAL_GCS_ENABLED
     461             :                     // disable RX and TX pins in case they are shared
     462             :                     // with another peripheral (eg. RCIN pin). We
     463             :                     // don't do this if GCS is not enabled as in that
     464             :                     // case we don't have serialmanager parameters and
     465             :                     // this would prevent AP_Periph from using a GPS
     466        6164 :                     uart->disable_rxtx();
     467             : #endif
     468        6164 :                     break;
     469        4234 :                 case SerialProtocol_Console:
     470             :                 case SerialProtocol_MAVLink:
     471             :                 case SerialProtocol_MAVLink2:
     472             :                 case SerialProtocol_MAVLinkHL:
     473        4234 :                     uart->begin(state[i].baudrate(),
     474             :                                          AP_SERIALMANAGER_MAVLINK_BUFSIZE_RX,
     475             :                                          AP_SERIALMANAGER_MAVLINK_BUFSIZE_TX);
     476        4234 :                     break;
     477           1 :                 case SerialProtocol_FrSky_D:
     478             :                     // Note baudrate is hardcoded to 9600
     479           1 :                     state[i].baud.set_and_default(AP_SERIALMANAGER_FRSKY_D_BAUD/1000); // update baud param in case user looks at it
     480             :                     // begin is handled by AP_Frsky_telem library
     481           1 :                     break;
     482           4 :                 case SerialProtocol_FrSky_SPort:
     483             :                 case SerialProtocol_FrSky_SPort_Passthrough:
     484             :                     // Note baudrate is hardcoded to 57600
     485           4 :                     state[i].baud.set_and_default(AP_SERIALMANAGER_FRSKY_SPORT_BAUD/1000); // update baud param in case user looks at it
     486             :                     // begin is handled by AP_Frsky_telem library
     487           4 :                     break;
     488        4112 :                 case SerialProtocol_GPS:
     489             :                 case SerialProtocol_GPS2:
     490        4112 :                     uart->begin(state[i].baudrate(),
     491             :                                          AP_SERIALMANAGER_GPS_BUFSIZE_RX,
     492             :                                          AP_SERIALMANAGER_GPS_BUFSIZE_TX);
     493        4112 :                     break;
     494           0 :                 case SerialProtocol_AlexMos:
     495             :                     // Note baudrate is hardcoded to 115200
     496           0 :                     state[i].baud.set_and_default(AP_SERIALMANAGER_ALEXMOS_BAUD / 1000);   // update baud param in case user looks at it
     497           0 :                     uart->begin(AP_SERIALMANAGER_ALEXMOS_BAUD,
     498             :                                          AP_SERIALMANAGER_ALEXMOS_BUFSIZE_RX,
     499             :                                          AP_SERIALMANAGER_ALEXMOS_BUFSIZE_TX);
     500           0 :                     break;
     501           3 :                 case SerialProtocol_Gimbal:
     502             :                     // Note baudrate is hardcoded to 115200
     503           3 :                     state[i].baud.set_and_default(AP_SERIALMANAGER_GIMBAL_BAUD / 1000);     // update baud param in case user looks at it
     504           3 :                     uart->begin(state[i].baudrate(),
     505             :                                          AP_SERIALMANAGER_GIMBAL_BUFSIZE_RX,
     506             :                                          AP_SERIALMANAGER_GIMBAL_BUFSIZE_TX);
     507           3 :                     break;
     508           0 :                 case SerialProtocol_Aerotenna_USD1:
     509           0 :                     state[i].protocol.set_and_save(SerialProtocol_Rangefinder);
     510           0 :                     break;
     511           0 :                 case SerialProtocol_Sbus1:
     512             :                     // initialised within library
     513           0 :                     break;
     514           0 :                 case SerialProtocol_ESCTelemetry:
     515             :                     // ESC telemetry protocol from BLHeli32 ESCs. Note that baudrate is hardcoded to 115200
     516           0 :                     state[i].baud.set_and_default(115200 / 1000);
     517           0 :                     uart->begin(state[i].baudrate(), 30, 30);
     518           0 :                     uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
     519           0 :                     break;
     520             : 
     521           0 :                 case SerialProtocol_Robotis:
     522           0 :                     uart->begin(state[i].baudrate(),
     523             :                                          AP_SERIALMANAGER_ROBOTIS_BUFSIZE_RX,
     524             :                                          AP_SERIALMANAGER_ROBOTIS_BUFSIZE_TX);
     525           0 :                     uart->set_unbuffered_writes(true);
     526           0 :                     uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
     527           0 :                     break;
     528             : 
     529           0 :                 case SerialProtocol_SLCAN:
     530           0 :                     uart->begin(state[i].baudrate(),
     531             :                                          AP_SERIALMANAGER_SLCAN_BUFSIZE_RX,
     532             :                                          AP_SERIALMANAGER_SLCAN_BUFSIZE_TX);
     533           0 :                     break;
     534             : 
     535             : #if AP_RCPROTOCOL_ENABLED
     536           1 :                 case SerialProtocol_RCIN:
     537           1 :                     if (!AP::RC().has_uart()) {
     538           1 :                         AP::RC().add_uart(uart);
     539             :                     } else {
     540           0 :                         GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "SERIAL%u_PROTOCOL: duplicate RCIN not permitted", i);
     541             :                     }
     542             : 
     543           1 :                     break;
     544             : #endif
     545             :                     
     546           2 :                 case SerialProtocol_EFI:
     547           2 :                     state[i].baud.set_default(AP_SERIALMANAGER_EFI_MS_BAUD);
     548           2 :                     uart->begin(state[i].baudrate(),
     549             :                                          AP_SERIALMANAGER_EFI_MS_BUFSIZE_RX,
     550             :                                          AP_SERIALMANAGER_EFI_MS_BUFSIZE_TX);
     551           2 :                     uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
     552           2 :                     break;
     553             : 
     554           6 :                 case SerialProtocol_Generator:
     555           6 :                     break;
     556             : #if HAL_MSP_ENABLED                    
     557           6 :                 case SerialProtocol_MSP:
     558             :                 case SerialProtocol_DJI_FPV:
     559             :                 case SerialProtocol_MSP_DisplayPort:
     560             :                     // baudrate defaults to 115200
     561           6 :                     state[i].baud.set_default(AP_SERIALMANAGER_MSP_BAUD/1000);
     562           6 :                     uart->begin(state[i].baudrate(),
     563             :                                          AP_SERIALMANAGER_MSP_BUFSIZE_RX,
     564             :                                          AP_SERIALMANAGER_MSP_BUFSIZE_TX);
     565           6 :                     uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
     566             :                     // Note init is handled by AP_MSP
     567           6 :                     break;
     568             : #endif
     569             : 
     570             : #if AP_SERIALMANAGER_IMUOUT_ENABLED
     571           0 :                 case SerialProtocol_IMUOUT:
     572           0 :                     uart->begin(state[i].baudrate(),
     573             :                                 AP_SERIALMANAGER_IMUOUT_BUFSIZE_RX,
     574             :                                 AP_SERIALMANAGER_IMUOUT_BUFSIZE_TX);
     575           0 :                     AP::ins().set_imu_out_uart(uart);
     576           0 :                     uart->set_unbuffered_writes(true);
     577           0 :                     break;
     578             : #endif
     579             : #if AP_NETWORKING_BACKEND_PPP
     580             :                 case SerialProtocol_PPP:
     581             :                     break;
     582             : #endif
     583           0 :                 case SerialProtocol_IOMCU:
     584             :                     // nothing to do, AP_IOMCU handles this
     585           0 :                     break;
     586         125 :                 default:
     587         125 :                     uart->begin(state[i].baudrate());
     588             :             }
     589             :         }
     590             :     }
     591        2094 : }
     592             : 
     593        2094 : void AP_SerialManager::convert_parameters()
     594             : {
     595             :     // PARAMETER_CONVERSION - Added: Jun-2025 for ArduPilot-4.7
     596       23034 :     for (auto &_state : state) {
     597       20940 :         _state.options.convert_parameter_width(AP_PARAM_INT16);
     598             :     }
     599        2094 : }
     600             : 
     601    41691263 : const AP_SerialManager::UARTState *AP_SerialManager::find_protocol_instance(enum SerialProtocol protocol, uint8_t instance) const
     602             : {
     603    41691263 :     uint8_t found_instance = 0;
     604             : 
     605             :     // search for matching protocol
     606   375121766 :     for(uint8_t i=0; i<SERIALMANAGER_NUM_PORTS; i++) {
     607   333445537 :         if (protocol_match(protocol, (enum SerialProtocol)state[i].protocol.get())) {
     608       34433 :             if (found_instance == instance) {
     609       15034 :                 return &state[i];
     610             :             }
     611       19399 :             found_instance++;
     612             :         }
     613             :     }
     614             : 
     615             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     616    41801305 :     for (auto p = registered_ports; p; p = p->next) {
     617      125102 :         if (protocol_match(protocol, (enum SerialProtocol)p->state.protocol.get())) {
     618          66 :             if (found_instance == instance) {
     619          26 :                 return &p->state;
     620             :             }
     621          40 :             found_instance++;
     622             :         }
     623             :     }
     624             : #endif
     625             : 
     626             :     // if we got this far we did not find the uart
     627    41676203 :     return nullptr;
     628             : }
     629             : 
     630             : // find_serial - searches available serial ports for the first instance that allows the given protocol
     631             : //  instance should be zero if searching for the first instance, 1 for the second, etc
     632             : //  returns uart on success, nullptr if a serial port cannot be found
     633    41539853 : AP_HAL::UARTDriver *AP_SerialManager::find_serial(enum SerialProtocol protocol, uint8_t instance) const
     634             : {
     635    41539853 :     const struct UARTState *_state = find_protocol_instance(protocol, instance);
     636    41539853 :     if (_state == nullptr) {
     637    41531328 :         return nullptr;
     638             :     }
     639        8525 :     const uint8_t serial_idx = _state->idx;
     640             : 
     641             :     // set options before any user does begin()
     642        8525 :     AP_HAL::UARTDriver *port = hal.serial(serial_idx);
     643             : 
     644             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     645        8525 :     if (port == nullptr) {
     646             :         // look for a registered port
     647          28 :         for (auto p = registered_ports; p; p = p->next) {
     648          28 :             if (p->state.idx == serial_idx) {
     649          14 :                 port = p;
     650          14 :                 break;
     651             :             }
     652             :         }
     653             :     }
     654             : #endif
     655             : 
     656        8525 :     if (port) {
     657        8525 :         port->set_options(_state->options);
     658             :     }
     659        8525 :     return port;
     660             : }
     661             : 
     662             : // have_serial - return true if we have the given serial protocol configured
     663      144910 : bool AP_SerialManager::have_serial(enum SerialProtocol protocol, uint8_t instance) const
     664             : {
     665      144910 :     return find_protocol_instance(protocol, instance) != nullptr;
     666             : }
     667             : 
     668             : // find_baudrate - searches available serial ports for the first instance that allows the given protocol
     669             : //  instance should be zero if searching for the first instance, 1 for the second, etc
     670             : //  returns baudrate on success, 0 if a serial port cannot be found
     671          95 : uint32_t AP_SerialManager::find_baudrate(enum SerialProtocol protocol, uint8_t instance) const
     672             : {
     673          95 :     const struct UARTState *_state = find_protocol_instance(protocol, instance);
     674          95 :     if (_state == nullptr) {
     675           0 :         return 0;
     676             :     }
     677          95 :     return _state->baudrate();
     678             : }
     679             : 
     680           3 : void AP_SerialManager::set_and_default_baud(enum SerialProtocol protocol, uint8_t instance, uint32_t _baud)
     681             : {
     682           3 :     const struct UARTState *_state = find_protocol_instance(protocol, instance);
     683           3 :     if (_state == nullptr) {
     684           0 :         return;
     685             :     }
     686           3 :     state->baud.set_and_default(_baud);
     687             : }
     688             : 
     689             : // find_portnum - find port number (SERIALn index) for a protocol and instance, -1 for not found
     690          62 : int8_t AP_SerialManager::find_portnum(enum SerialProtocol protocol, uint8_t instance) const
     691             : {
     692          62 :     const struct UARTState *_state = find_protocol_instance(protocol, instance);
     693          62 :     if (_state == nullptr) {
     694           0 :         return -1;
     695             :     }
     696          62 :     return int8_t(_state->idx);
     697             : }
     698             : 
     699             : // get_serial_by_id - gets serial by serial id
     700           0 : AP_HAL::UARTDriver *AP_SerialManager::get_serial_by_id(uint8_t id)
     701             : {
     702           0 :     if (id < SERIALMANAGER_NUM_PORTS) {
     703           0 :         return hal.serial(id);
     704             :     }
     705             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     706           0 :     for (auto p = registered_ports; p; p = p->next) {
     707           0 :         if (p->state.idx == id) {
     708           0 :             return (AP_HAL::UARTDriver *)p;
     709             :         }
     710             :     }
     711             : #endif
     712           0 :     return nullptr;
     713             : }
     714             : 
     715             : /*
     716             :   get a UARTState by index
     717             : */
     718           0 : const AP_SerialManager::UARTState *AP_SerialManager::get_state_by_id(uint8_t id) const
     719             : {
     720           0 :     if (id < SERIALMANAGER_NUM_PORTS) {
     721           0 :         return &state[id];
     722             :     }
     723             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     724           0 :     for (auto p = registered_ports; p; p = p->next) {
     725           0 :         if (p->state.idx == id) {
     726           0 :             return &p->state;
     727             :         }
     728             :     }
     729             : #endif
     730           0 :     return nullptr;
     731             : }
     732             : 
     733             : /*
     734             :  *  map from a 16 bit EEPROM baud rate to a real baud rate.  For
     735             :  *  stm32-based boards we can do 1.5MBit, although 921600 is more
     736             :  *  reliable.
     737             :  */
     738       14919 : uint32_t AP_SerialManager::map_baudrate(int32_t rate)
     739             : {
     740       14919 :     if (rate <= 0) {
     741          10 :         rate = 57;
     742             :     }
     743       14919 :     switch (rate) {
     744           0 :     case 1:    return 1200;
     745           0 :     case 2:    return 2400;
     746           0 :     case 4:    return 4800;
     747           0 :     case 9:    return 9600;
     748           0 :     case 19:   return 19200;
     749           6 :     case 38:   return 38400;
     750        8515 :     case 57:   return 57600;
     751           0 :     case 100:  return 100000;
     752           0 :     case 111:  return 111100;
     753        2127 :     case 115:  return 115200;
     754        4133 :     case 230:  return 230400;
     755           0 :     case 256:  return 256000;
     756           0 :     case 460:  return 460800;
     757           0 :     case 500:  return 500000;
     758           0 :     case 921:  return 921600;
     759           0 :     case 1500:  return 1500000;
     760           0 :     case 2000:  return 2000000;
     761             :     }
     762             : 
     763         138 :     if (rate > 2000) {
     764             :         // assume it is a direct baudrate. This allows for users to
     765             :         // set an exact baudrate as long as it is over 2000 baud
     766         138 :         return (uint32_t)rate;
     767             :     }
     768             : 
     769             :     // otherwise allow any other kbaud rate
     770           0 :     return rate*1000;
     771             : }
     772             : 
     773             : // protocol_match - returns true if the protocols match
     774   333570639 : bool AP_SerialManager::protocol_match(enum SerialProtocol protocol1, enum SerialProtocol protocol2) const
     775             : {
     776             :     // check for obvious match
     777   333570639 :     if (protocol1 == protocol2) {
     778        2498 :         return true;
     779             :     }
     780             : 
     781             :     // mavlink match
     782   333568141 :     if (((protocol1 == SerialProtocol_MAVLink) || (protocol1 == SerialProtocol_MAVLink2) || (protocol1 == SerialProtocol_MAVLinkHL)) &&
     783       42669 :         ((protocol2 == SerialProtocol_MAVLink) || (protocol2 == SerialProtocol_MAVLink2) || (protocol2 == SerialProtocol_MAVLinkHL))) {
     784       32001 :         return true;
     785             :     }
     786             : 
     787             :     // gps match
     788   333536140 :     if (((protocol1 == SerialProtocol_GPS) || (protocol1 == SerialProtocol_GPS2)) &&
     789        6126 :         ((protocol2 == SerialProtocol_GPS) || (protocol2 == SerialProtocol_GPS2))) {
     790           0 :         return true;
     791             :     }
     792             : 
     793   333536140 :     return false;
     794             : }
     795             : 
     796             : // setup any special options
     797       14658 : void AP_SerialManager::set_options(uint16_t i)
     798             : {
     799       14658 :     struct UARTState &opt = state[i];
     800             :     // pass through to HAL
     801       14658 :     if (!hal.serial(i)->set_options(opt.options)) {
     802           0 :         DEV_PRINTF("Unable to setup options for Serial%u\n", i);
     803             :     }
     804       14658 : }
     805             : 
     806             : // get the passthru ports if enabled
     807    41931458 : bool AP_SerialManager::get_passthru(AP_HAL::UARTDriver *&port1, AP_HAL::UARTDriver *&port2, uint8_t &timeout_s,
     808             :                                     uint32_t &baud1, uint32_t &baud2)
     809             : {
     810    41931458 :     if (passthru_port2 < 0 ||
     811           0 :         passthru_port1 < 0) {
     812    41931458 :         return false;
     813             :     }
     814           0 :     port1 = get_serial_by_id(passthru_port1);
     815           0 :     port2 = get_serial_by_id(passthru_port2);
     816           0 :     if (port1 == nullptr || port2 == nullptr) {
     817           0 :         return false;
     818             :     }
     819           0 :     const auto *state1 = get_state_by_id(passthru_port1);
     820           0 :     const auto *state2 = get_state_by_id(passthru_port2);
     821           0 :     if (!state1 || !state2) {
     822           0 :         return false;
     823             :     }
     824           0 :     baud1 = state1->baudrate();
     825           0 :     baud2 = state2->baudrate();
     826           0 :     timeout_s = MAX(passthru_timeout, 0);
     827           0 :     return true;
     828             : }
     829             : 
     830             : // disable passthru by settings SERIAL_PASS2 to -1
     831           0 : void AP_SerialManager::disable_passthru(void)
     832             : {
     833           0 :     passthru_port2.set_and_notify(-1);
     834           0 : }
     835             : 
     836             : // accessor for AP_Periph to set baudrate and type
     837           0 : void AP_SerialManager::set_protocol_and_baud(uint8_t sernum, enum SerialProtocol protocol, uint32_t baudrate)
     838             : {
     839           0 :     if (sernum < SERIALMANAGER_NUM_PORTS) {
     840           0 :         state[sernum].protocol.set_and_default(protocol);
     841           0 :         state[sernum].baud.set_and_default(baudrate);
     842             :     }
     843           0 : }
     844      140684 : bool AP_SerialManager::pre_arm_checks(char *failure_msg, const uint8_t failure_msg_len)
     845             : {
     846             :     // PARAMETER_CONVERSION - Added: Jun-2025 for ArduPilot-4.7
     847             :     // ArduPilot 4.7 pre-arm fails if either bit is set when conversion should have nuked them
     848             :     // ArduPilot 4.8 pre-arm fails if either bit is set when conversion should have nuked them
     849             :     // ArduPilot 4.9 pre-arm fails if either bit is set when conversion should have nuked them
     850             :     // ArduPilot 4.9++ removes the pre-arm failure
     851     1547524 :     for (uint8_t i=0; i<ARRAY_SIZE(state); i++) {
     852     1406840 :         const auto &_state = state[i];
     853     1406840 :         if (_state.options & AP_HAL::UARTDriver::Option::OPTION_MAVLINK_NO_FORWARD_old) {
     854           0 :             hal.util->snprintf(failure_msg, failure_msg_len, "SERIAL%u_OPTIONS bit 10 ('no forward mavlink') must not be set; use MAVn_OPTIONS bit 1 instead", unsigned(i));
     855           0 :             return false;
     856             :         }
     857     1406840 :         if (_state.options & AP_HAL::UARTDriver::Option::OPTION_NOSTREAMOVERRIDE_old) {
     858           0 :             hal.util->snprintf(failure_msg, failure_msg_len, "SERIAL%u_OPTIONS bit 12 ('no stream overrides') must not be set; use MAVn_OPTIONS bit 2 instead", unsigned(i));
     859           0 :             return false;
     860             :         }
     861             :     }
     862      140684 :     return true;
     863             : }
     864             : 
     865             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     866             : /*
     867             :   register an external network port. It is up to the caller to use a unique id field
     868             :   using AP_SERIALMANAGER_NET_PORT_1 as the base id for NET_P1_*
     869             :  */
     870          16 : void AP_SerialManager::register_port(RegisteredPort *port)
     871             : {
     872          16 :     const auto idx = port->state.idx;
     873          16 :     WITH_SEMAPHORE(port_sem);
     874             :     /*
     875             :       maintain the list in ID order
     876             :      */
     877          16 :     if (registered_ports == nullptr ||
     878          10 :         registered_ports->state.idx >= idx) {
     879           6 :         port->next = registered_ports;
     880           6 :         registered_ports = port;
     881           6 :         return;
     882             :     }
     883          17 :     for (auto p = registered_ports; p; p = p->next) {
     884          17 :         if (p->next == nullptr || p->next->state.idx >= idx) {
     885          10 :             port->next = p->next;
     886          10 :             p->next = port;
     887          10 :             break;
     888             :         }
     889             :     }
     890          16 : }
     891             : 
     892             : #if HAL_LOGGING_ENABLED && HAL_UART_STATS_ENABLED
     893             : // Log UART message for each registered serial port
     894      149217 : void AP_SerialManager::registered_ports_log()
     895             : {
     896             :     // Calculate time since last call
     897      149217 :     const uint32_t now_ms = AP_HAL::millis();
     898      149217 :     const uint32_t dt_ms = now_ms - registered_ports_last_log_ms;
     899      149217 :     registered_ports_last_log_ms = now_ms;
     900             : 
     901      149217 :     WITH_SEMAPHORE(port_sem);
     902             : 
     903             :     // Loop over ports
     904      149546 :     for (auto p = registered_ports; p; p = p->next) {
     905         329 :         p->log_stats(p->state.idx, p->state.stats, dt_ms);
     906             :     }
     907      149217 : }
     908             : #endif
     909             : 
     910             : #endif // AP_SERIALMANAGER_REGISTER_ENABLED
     911             : 
     912             : // Return a device id for this port
     913        6340 : uint32_t AP_SerialManager::UARTState::get_device_id() const
     914             : {
     915             : #if AP_SERIALMANAGER_REGISTER_ENABLED
     916        6340 :     if (idx >= AP_SERIALMANAGER_SCR_PORT_1) {
     917             :         // Scripting port
     918           0 :         return AP_HAL::Device::make_bus_id(
     919             :             AP_HAL::Device::BUS_TYPE_SERIAL,
     920             :             0,
     921           0 :             idx - AP_SERIALMANAGER_SCR_PORT_1,
     922             :             uint8_t(DeviceType::SCRIPTING)
     923           0 :         );
     924             :     }
     925             : 
     926        6340 :     if (idx >= AP_SERIALMANAGER_CAN_D2_PORT_1) {
     927             :         // CAN D2 port
     928           0 :         return AP_HAL::Device::make_bus_id(
     929             :             AP_HAL::Device::BUS_TYPE_SERIAL,
     930             :             1,
     931           0 :             idx - AP_SERIALMANAGER_CAN_D2_PORT_1,
     932             :             uint8_t(DeviceType::CANBUS)
     933           0 :         );
     934             :     }
     935             : 
     936        6340 :     if (idx >= AP_SERIALMANAGER_CAN_D1_PORT_1) {
     937             :         // CAN D1 port
     938           2 :         return AP_HAL::Device::make_bus_id(
     939             :             AP_HAL::Device::BUS_TYPE_SERIAL,
     940             :             0,
     941           2 :             idx - AP_SERIALMANAGER_CAN_D1_PORT_1,
     942             :             uint8_t(DeviceType::CANBUS)
     943           2 :         );
     944             :     }
     945             : 
     946        6338 :     if (idx >= AP_SERIALMANAGER_NET_PORT_1) {
     947             :         // Networking port
     948          10 :         return AP_HAL::Device::make_bus_id(
     949             :             AP_HAL::Device::BUS_TYPE_SERIAL,
     950             :             0,
     951          10 :             idx - AP_SERIALMANAGER_NET_PORT_1,
     952             :             uint8_t(DeviceType::NETWORKING)
     953          10 :         );
     954             :     }
     955             : #endif // AP_SERIALMANAGER_REGISTER_ENABLED
     956             : 
     957             :     // Standard port
     958        6328 :     return AP_HAL::Device::make_bus_id(
     959             :         AP_HAL::Device::BUS_TYPE_SERIAL,
     960             :         0,
     961        6328 :         idx,
     962             :         uint8_t(DeviceType::UART)
     963        6328 :     );
     964             : }
     965             : 
     966             : namespace AP {
     967             : 
     968    83740977 : AP_SerialManager &serialmanager()
     969             : {
     970    83740977 :     return *AP_SerialManager::get_singleton();
     971             : }
     972             : 
     973             : }
     974             : 
     975             : #endif  // AP_SERIALMANAGER_ENABLED

Generated by: LCOV version 1.14