# Day 4: Sensing (Whiteboard) ## I/O Threads Let's say we have a serial-based sensor, such as a GPS. All of the I/O threads inherit from `goby::middleware::io::detail::IOThread`: - Subscribe to outgoing data (Goby -> sensor): `protobuf::IOData`, group: `line_out_group` - Handles sync between boost::asio and the Goby interthread transporter - Uniform error handling (`protobuf::IOStatus` on `line_in_group`) Implementors must: - `open_socket()`: (Try to) open the socket - `async_read()`: Start an asynchronous read from the socket (return a "message") - `async_write()`: Start an asynchronous write to the socket (free function `basic_async_write`). ### Serial ```mermaid classDiagram IOThread <|-- detail__SerialThread detail__SerialThread <|-- SerialThreadLineBased class IOThread { +initialize() +finalize() #write() #handle_read_success() #handle_write_success() #handle_read_error() #handle_write_error() #mutable_socket() #mutable_io() #socket_is_open() #async_read() #open_socket() virtual #async_read() virtual #async_write() virtual -loop() } class detail__SerialThread { #mutable_serial_port() -async_write() override -open_socket() override -publish_status() } class SerialThreadLineBased { -async_read() override } ``` Switch to becoming a user of the IOThreads. - Each I/O thread is a Goby Thread (by default the `SimpleThread`: interthread/interprocess/intervehicle) ```mermaid graph TD SerialThreadLineBased-->|protobuf::IOData on gps_in|GPSDriver GPSDriver-->|protobuf::IOData on gps_out|SerialThreadLineBased ``` ### TCP Let's say our GPS was connected to some remote server which then reserves the data as a TCP server. ## goby_gps Is a client for the `gpsd` server. goby_gps publications: - TPV (**T**ime **P**osition **V**elocity) - SKY (sky view: satellite) ## Sensor state machines ```mermaid stateDiagram-v2 [*] --> StartLogging StartLogging --> Logging Logging-->StopLogging StopLogging-->Sleep Sleep-->StartLogging ``` Writing a simulator and a driver for a CTD (**C**onductivity/salinity, **T**emperature, **D**epth/pressure) instrument. We're going to use `boost::statechart` along with Goby. - Uses classes to represent states: - constructor = entry - destructor = exit ```mermaid stateDiagram-v2 [*]-->StartLogging StartLogging Logging StopLogging Sleep ``` Transitions are driven by "events" ```mermaid stateDiagram-v2 [*] --> StartLogging StartLogging --> Logging : EvLoggingStarted Logging-->StopLogging : EvDoStopLogging StopLogging-->Sleep : EvEnterSleep Sleep-->StartLogging : EvDoStartLogging ``` Each state can have a list of reactions. ```mermaid stateDiagram-v2 [*] --> Sleep StartLogging --> Logging : EvLoggingStarted Logging-->StopLogging : EvDoStopLogging StopLogging-->Sleep : EvEnterSleep Sleep-->StartLogging : EvDoStartLogging ``` From the main thread, we might want to know what state the machine is in. Let's look at the interface for our CTD, based on NMEA-0183: ``` RS-232, 9600 baud > means message from the control computer to the CTD < means message from the CTD to the control computer *CS is the standard NMEA-0183 checksum Wake up the CTD > $ZCCMD,WAKE*CS\r\n Wake received, CTD out of low power mode and ready to commence logging < $ZCACK,WAKE*CS\r\n Start logging > $ZCCMD,START*CS\r\n Logging started < $ZCACK,START*CS\r\n Data (streams at 1 Hz) < $ZCDAT,<salinity>,<temp, deg C>,<depth, meters>*CS < $ZCDAT,31.5,10.4,150*CS\r\n < $ZCDAT,31.5,10.3,151*CS\r\n < $ZCDAT,31.4,10.2,152*CS\r\n Stop logging > $ZCCMD,STOP*CS\r\n Logging stopped < $ZCACK,STOP*CS\r\n Enter low power mode > $ZCCMD,SLEEP*CS\r\n < $ZCACK,SLEEP*CS\r\n ``` Given this, let's add a serial thread ## Simulators Key goals - Replicate the real behavior *and* the API of the sensor - Start off by capturing "key behavior" and then iterate. --- ``` ```