LCOV - code coverage report
Current view: top level - wirestead/builder - serial_builder.cc (source / functions) Coverage Total Hit
Test: Wirestead Coverage Report Lines: 87.2 % 149 130
Test Date: 2026-08-30 10:35:09 Functions: 81.0 % 21 17
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 70.8 % 130 92

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright 2025 Jinwoo Sung
       3                 :             :  *
       4                 :             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :             :  * you may not use this file except in compliance with the License.
       6                 :             :  * You may obtain a copy of the License at
       7                 :             :  *
       8                 :             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :             :  *
      10                 :             :  * Unless required by applicable law or agreed to in writing, software
      11                 :             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :             :  * See the License for the specific language governing permissions and
      14                 :             :  * limitations under the License.
      15                 :             :  */
      16                 :             : 
      17                 :             : #include "wirestead/builder/serial_builder.hpp"
      18                 :             : 
      19                 :             : #include <algorithm>
      20                 :             : #include <boost/asio/io_context.hpp>
      21                 :             : #include <cctype>
      22                 :             : 
      23                 :             : #include "wirestead/base/constants.hpp"
      24                 :             : #include "wirestead/builder/auto_initializer.hpp"
      25                 :             : #include "wirestead/diagnostics/exceptions.hpp"
      26                 :             : 
      27                 :             : namespace wirestead {
      28                 :             : namespace builder {
      29                 :             : 
      30                 :          22 : SerialBuilder::SerialBuilder(const std::string& device, uint32_t baud_rate)
      31                 :          22 :     : device_(device),
      32                 :          22 :       baud_rate_(baud_rate),
      33                 :          22 :       auto_start_(false),
      34                 :          22 :       independent_context_(false),
      35                 :          22 :       shared_context_(false),
      36                 :          22 :       retry_interval_ms_(base::constants::DEFAULT_RETRY_INTERVAL_MS),
      37                 :          22 :       char_size_(8),
      38                 :          22 :       stop_bits_(1),
      39                 :          22 :       parity_(config::SerialConfig::Parity::None),
      40                 :          22 :       flow_(config::SerialConfig::Flow::None),
      41                 :          22 :       reopen_on_error_(true) {
      42   [ +  +  +  -  :          28 :   if (device.empty()) throw diagnostics::BuilderException("Device path cannot be empty");
          +  -  +  -  +  
                      - ]
      43                 :             : 
      44                 :             :   // Ensure background IO service is running
      45                 :          21 :   AutoInitializer::ensure_io_context_running();
      46                 :          23 : }
      47                 :             : 
      48                 :          21 : std::unique_ptr<wrapper::Serial> SerialBuilder::build() {
      49                 :          21 :   std::unique_ptr<wrapper::Serial> serial;
      50         [ +  + ]:          21 :   if (independent_context_) {
      51                 :           1 :     serial = std::make_unique<wrapper::Serial>(device_, baud_rate_, std::make_shared<boost::asio::io_context>());
      52                 :           1 :     serial->manage_external_context(true);
      53                 :             :   } else {
      54                 :          20 :     serial = std::make_unique<wrapper::Serial>(device_, baud_rate_);
      55                 :             :   }
      56   [ +  +  +  - ]:          21 :   if (shared_context_) serial->shared_context(true);
      57                 :             : 
      58   [ +  +  +  -  :          21 :   if (this->on_data_) serial->on_data(this->on_data_);
                   +  - ]
      59   [ +  +  +  -  :          21 :   if (this->on_data_batch_) serial->on_data_batch(this->on_data_batch_);
                   +  - ]
      60   [ +  +  +  -  :          21 :   if (this->on_connect_) serial->on_connect(this->on_connect_);
                   +  - ]
      61   [ +  +  +  -  :          21 :   if (this->on_disconnect_) serial->on_disconnect(this->on_disconnect_);
                   +  - ]
      62   [ +  +  +  -  :          21 :   if (this->on_error_) serial->on_error(this->on_error_);
                   +  - ]
      63   [ +  +  +  -  :          21 :   if (this->on_backpressure_) serial->on_backpressure(this->on_backpressure_);
                   +  - ]
      64                 :             : 
      65   [ +  +  +  - ]:          21 :   if (char_size_set_) serial->data_bits(static_cast<int>(char_size_));
      66   [ +  +  +  - ]:          21 :   if (stop_bits_set_) serial->stop_bits(static_cast<int>(stop_bits_));
      67                 :             : 
      68                 :             :   // Note: wrapper::Serial setters use strings for enum types
      69         [ +  + ]:          21 :   if (parity_set_) {
      70                 :           6 :     std::string p_str = "none";
      71         [ +  + ]:           6 :     if (parity_ == config::SerialConfig::Parity::Even)
      72                 :           2 :       p_str = "even";
      73         [ +  + ]:           4 :     else if (parity_ == config::SerialConfig::Parity::Odd)
      74                 :           1 :       p_str = "odd";
      75                 :           6 :     serial->parity(p_str);
      76                 :           6 :   }
      77                 :             : 
      78         [ +  + ]:          21 :   if (flow_set_) {
      79                 :           5 :     std::string f_str = "none";
      80         [ +  + ]:           5 :     if (flow_ == config::SerialConfig::Flow::Software)
      81                 :           1 :       f_str = "software";
      82         [ +  + ]:           4 :     else if (flow_ == config::SerialConfig::Flow::Hardware)
      83                 :           2 :       f_str = "hardware";
      84                 :           5 :     serial->flow_control(f_str);
      85                 :           5 :   }
      86                 :             : 
      87   [ +  +  +  - ]:          21 :   if (reopen_on_error_set_) serial->reopen_on_error(reopen_on_error_);
      88   [ +  +  +  - ]:          21 :   if (read_chunk_set_) serial->read_chunk(read_chunk_);
      89   [ -  +  -  - ]:          21 :   if (low_latency_set_) serial->low_latency(low_latency_);
      90         [ -  + ]:          21 :   if (rs485_.enabled) {
      91                 :           0 :     serial->rs485(rs485_.rts_on_send, rs485_.rx_during_tx, rs485_.delay_rts_before_send_ms,
      92                 :             :                   rs485_.delay_rts_after_send_ms);
      93                 :             :   }
      94   [ -  +  -  - ]:          21 :   if (dtr_) serial->dtr(*dtr_);
      95   [ -  +  -  - ]:          21 :   if (rts_) serial->rts(*rts_);
      96   [ +  +  +  - ]:          21 :   if (rx_idle_timeout_set_) serial->rx_idle_timeout(rx_idle_timeout_);
      97   [ +  +  +  - ]:          21 :   if (retry_interval_set_) serial->retry_interval(std::chrono::milliseconds(retry_interval_ms_));
      98                 :             : 
      99   [ +  +  +  - ]:          21 :   if (this->bp_strategy_set_) serial->backpressure_strategy(this->bp_strategy_);
     100                 :          21 :   serial->backpressure_threshold(this->get_effective_backpressure_threshold());
     101                 :             : 
     102         [ +  + ]:          21 :   if (this->framer_factory_) {
     103                 :           1 :     serial->framer(this->framer_factory_());
     104                 :             :   }
     105         [ +  + ]:          21 :   if (this->on_message_) {
     106                 :           1 :     serial->on_message(this->on_message_);
     107                 :             :   }
     108         [ +  + ]:          21 :   if (this->on_message_batch_) {
     109                 :           1 :     serial->on_message_batch(this->on_message_batch_);
     110                 :             :   }
     111                 :             : 
     112         [ +  + ]:          21 :   if (auto_start_) {
     113                 :           1 :     serial->auto_start(true);
     114                 :             :   }
     115                 :             : 
     116                 :          21 :   return serial;
     117                 :           0 : }
     118                 :             : 
     119                 :           2 : SerialBuilder& SerialBuilder::auto_start(bool auto_start) {
     120                 :           2 :   auto_start_ = auto_start;
     121                 :           2 :   return *this;
     122                 :             : }
     123                 :             : 
     124                 :           4 : SerialBuilder& SerialBuilder::char_size(unsigned int size) {
     125                 :           4 :   char_size_ = size;
     126                 :           4 :   char_size_set_ = true;
     127                 :           4 :   return *this;
     128                 :             : }
     129                 :             : 
     130                 :           3 : SerialBuilder& SerialBuilder::stop_bits(unsigned int bits) {
     131                 :           3 :   stop_bits_ = bits;
     132                 :           3 :   stop_bits_set_ = true;
     133                 :           3 :   return *this;
     134                 :             : }
     135                 :             : 
     136                 :           1 : SerialBuilder& SerialBuilder::parity(config::SerialConfig::Parity p) {
     137                 :           1 :   parity_ = p;
     138                 :           1 :   parity_set_ = true;
     139                 :           1 :   return *this;
     140                 :             : }
     141                 :             : 
     142                 :           5 : SerialBuilder& SerialBuilder::parity(const std::string& p) {
     143                 :           5 :   std::string value = p;
     144                 :           5 :   std::transform(value.begin(), value.end(), value.begin(),
     145                 :          25 :                  [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
     146                 :             : 
     147   [ +  -  +  + ]:           5 :   if (value == "even") {
     148                 :           1 :     parity_ = config::SerialConfig::Parity::Even;
     149   [ +  -  +  + ]:           4 :   } else if (value == "odd") {
     150                 :           1 :     parity_ = config::SerialConfig::Parity::Odd;
     151                 :             :   } else {
     152                 :           3 :     parity_ = config::SerialConfig::Parity::None;
     153                 :             :   }
     154                 :           5 :   parity_set_ = true;
     155                 :           5 :   return *this;
     156                 :           5 : }
     157                 :             : 
     158                 :           1 : SerialBuilder& SerialBuilder::flow_control(config::SerialConfig::Flow f) {
     159                 :           1 :   flow_ = f;
     160                 :           1 :   flow_set_ = true;
     161                 :           1 :   return *this;
     162                 :             : }
     163                 :             : 
     164                 :           4 : SerialBuilder& SerialBuilder::flow_control(const std::string& f) {
     165                 :           4 :   std::string value = f;
     166                 :           4 :   std::transform(value.begin(), value.end(), value.begin(),
     167                 :          27 :                  [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
     168                 :             : 
     169   [ +  -  +  + ]:           4 :   if (value == "software") {
     170                 :           1 :     flow_ = config::SerialConfig::Flow::Software;
     171   [ +  -  +  + ]:           3 :   } else if (value == "hardware") {
     172                 :           1 :     flow_ = config::SerialConfig::Flow::Hardware;
     173                 :             :   } else {
     174                 :           2 :     flow_ = config::SerialConfig::Flow::None;
     175                 :             :   }
     176                 :           4 :   flow_set_ = true;
     177                 :           4 :   return *this;
     178                 :           4 : }
     179                 :             : 
     180                 :           3 : SerialBuilder& SerialBuilder::read_chunk(size_t bytes) {
     181                 :           3 :   read_chunk_ = bytes;
     182                 :           3 :   read_chunk_set_ = true;
     183                 :           3 :   return *this;
     184                 :             : }
     185                 :             : 
     186                 :           0 : SerialBuilder& SerialBuilder::low_latency(bool enable) {
     187                 :           0 :   low_latency_ = enable;
     188                 :           0 :   low_latency_set_ = true;
     189                 :           0 :   return *this;
     190                 :             : }
     191                 :             : 
     192                 :           0 : SerialBuilder& SerialBuilder::rs485(bool rts_on_send, bool rx_during_tx, unsigned delay_before_ms,
     193                 :             :                                     unsigned delay_after_ms) {
     194                 :           0 :   rs485_.enabled = true;
     195                 :           0 :   rs485_.rts_on_send = rts_on_send;
     196                 :           0 :   rs485_.rx_during_tx = rx_during_tx;
     197                 :           0 :   rs485_.delay_rts_before_send_ms = delay_before_ms;
     198                 :           0 :   rs485_.delay_rts_after_send_ms = delay_after_ms;
     199                 :           0 :   return *this;
     200                 :             : }
     201                 :             : 
     202                 :           0 : SerialBuilder& SerialBuilder::dtr(bool assert_line) {
     203                 :           0 :   dtr_ = assert_line;
     204                 :           0 :   return *this;
     205                 :             : }
     206                 :             : 
     207                 :           0 : SerialBuilder& SerialBuilder::rts(bool assert_line) {
     208                 :           0 :   rts_ = assert_line;
     209                 :           0 :   return *this;
     210                 :             : }
     211                 :             : 
     212                 :           1 : SerialBuilder& SerialBuilder::rx_idle_timeout(std::chrono::milliseconds timeout) {
     213                 :           1 :   rx_idle_timeout_ = timeout;
     214                 :           1 :   rx_idle_timeout_set_ = true;
     215                 :           1 :   return *this;
     216                 :             : }
     217                 :             : 
     218                 :           6 : SerialBuilder& SerialBuilder::reopen_on_error(bool enable) {
     219                 :           6 :   reopen_on_error_ = enable;
     220                 :           6 :   reopen_on_error_set_ = true;
     221                 :           6 :   return *this;
     222                 :             : }
     223                 :             : 
     224                 :           3 : SerialBuilder& SerialBuilder::retry_interval(std::chrono::milliseconds interval) {
     225                 :           3 :   retry_interval_ms_ = static_cast<uint32_t>(interval.count());
     226                 :           3 :   retry_interval_set_ = true;
     227                 :           3 :   return *this;
     228                 :             : }
     229                 :             : 
     230                 :           1 : SerialBuilder& SerialBuilder::independent_context(bool use_independent) {
     231                 :           1 :   independent_context_ = use_independent;
     232                 :           1 :   return *this;
     233                 :             : }
     234                 :             : 
     235                 :           2 : SerialBuilder& SerialBuilder::shared_context(bool use_shared) {
     236                 :           2 :   shared_context_ = use_shared;
     237                 :           2 :   return *this;
     238                 :             : }
     239                 :             : 
     240                 :             : // Explicit template instantiations
     241                 :             : 
     242                 :             : }  // namespace builder
     243                 :             : }  // namespace wirestead
        

Generated by: LCOV version 2.0-1