From faaf72a589124d67cad3d14f659581a028c8d9f0 Mon Sep 17 00:00:00 2001 From: Nestor Neto Date: Thu, 30 Oct 2025 08:29:24 -0300 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=93=9D=20docs(readme):=20Remove=20exa?= =?UTF-8?q?mple=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0579123..0f54c72 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -# CppSerial - +# CppSerial [![release](https://img.shields.io/github/v/release/NestorDP/cppserial)](https://github.com/NestorDP/cppserial/releases) + + [![unit-tests](https://github.com/NestorDP/cppserial/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/NestorDP/cppserial/actions/workflows/unit-tests.yml) [![codecov](https://codecov.io/gh/NestorDP/cppserial/branch/main/graph/badge.svg)](https://codecov.io/gh/NestorDP/cppserial) -[![Documentation Status](https://readthedocs.org/projects/cppserial/badge/?version=latest)](https://cppserial.readthedocs.io/en/latest/?badge=latest) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/3759133c01204a5c880d0dd65e6175bc)](https://app.codacy.com/gh/NestorDP/cppserial/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) +[![Documentation Status](https://readthedocs.org/projects/cppserial/badge/?version=latest)](https://cppserial.readthedocs.io/en/latest/?badge=latest) @@ -97,7 +98,7 @@ cd .. sphinx-build -b html docs build/docs/html ``` --> -## Run an Example Application + ### 🤝 Contributing From 8b00fe165996ca381be1a2473fe86910ef1a211c Mon Sep 17 00:00:00 2001 From: Nestor Neto Date: Fri, 31 Oct 2025 17:53:32 -0300 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9D=20docs(usage):=20Update=20basi?= =?UTF-8?q?c=20usage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/usage.rst | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index a2c70a2..d39ca79 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -16,10 +16,10 @@ Opening a Serial Port int main() { try { // Create a Serial object - libserial::Serial serial("/dev/ttyUSB0"); + libserial::Serial serial; // Open the port - serial.open(); + serial.open("/dev/ttyUSB0"); // Port is now ready for communication @@ -42,15 +42,16 @@ You can configure various serial port parameters: int main() { try { - libserial::Serial serial("/dev/ttyUSB0"); + libserial::Serial serial; // Configure before opening serial.setBaudRate(libserial::BaudRate::BAUD_9600); - serial.setDataBits(libserial::DataBits::DATA_8); - serial.setParity(libserial::Parity::NONE); - serial.setStopBits(libserial::StopBits::STOP_1); + serial.setDataLength(libserial::DataBits::SEVEN); + serial.setParity(libserial::Parity::ENABLE); + serial.setStopBits(libserial::StopBits::ONE); + serial.setCanonicalMode(libserial::CanonicalMode::DISABLE); - serial.open(); + serial.open("/dev/ttyUSB0"); } catch (const libserial::SerialException& e) { std::cerr << "Error: " << e.what() << std::endl; @@ -73,20 +74,16 @@ Basic read/write operations: int main() { try { - libserial::Serial serial("/dev/ttyUSB0"); - serial.open(); + libserial::Serial serial(); + serial.open("/dev/ttyUSB0"); // Write data - std::string message = "Hello, Serial!"; + auto message = std::make_shared("Hello from libserial!"); serial.write(message); // Read response - std::string response = serial.read(100); // Read up to 100 bytes - std::cout << "Received: " << response << std::endl; - - // Read a single byte - char byte = serial.readByte(); - std::cout << "Single byte: " << static_cast(byte) << std::endl; + auto buffer = std::make_shared(); + size_t bytes_read = serial.read(buffer); serial.close(); @@ -113,14 +110,14 @@ Configure read timeouts to prevent blocking: int main() { try { - libserial::Serial serial("/dev/ttyUSB0"); - serial.open(); - + libserial::Serial serial(); + serial.open("/dev/ttyUSB0"); // Set read timeout to 5 seconds - serial.setTimeout(std::chrono::seconds(5)); - + serial.setReadTimeout(std::chrono::milliseconds(5000)); + // This will timeout after 5 seconds if no data is available - std::string data = serial.read(100); + auto buffer = std::make_shared(); + size_t bytes_read = serial.read(buffer); } catch (const libserial::TimeoutException& e) { std::cout << "Read operation timed out" << std::endl; @@ -142,12 +139,14 @@ For non-blocking operations: int main() { try { - libserial::Serial serial("/dev/ttyUSB0"); - serial.open(); + libserial::Serial serial(); + serial.open("/dev/ttyUSB0"); + + auto buffer = std::make_shared(); // Check if data is available before reading - if (serial.available() > 0) { - std::string data = serial.read(); + if (serial.getAvailableData() > 0) { + size_t bytes_read = serial.read(buffer); // Process data... } From 7684e427c664a79f5edfc3b6bc10cfc1e258f310 Mon Sep 17 00:00:00 2001 From: Nestor Neto Date: Fri, 31 Oct 2025 18:05:13 -0300 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=93=9D=20docs(examples):=20Update=20e?= =?UTF-8?q?xamples=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/examples.rst | 570 ++++++++++++++++++++++++++-------------------- 1 file changed, 317 insertions(+), 253 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index f0fae98..f66bd87 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,7 +1,7 @@ Examples ======== -This section provides practical examples of using libserial in various scenarios. +This section provides practical examples of using libserial. Basic Serial Communication --------------------------- @@ -13,249 +13,313 @@ Create a simple echo server that reads data and sends it back: .. code-block:: cpp - #include - #include - #include - - int main() { - try { - libserial::Serial serial("/dev/ttyUSB0"); - serial.setBaudRate(libserial::BaudRate::BAUD_9600); - serial.open(); - - std::cout << "Echo server started. Press Ctrl+C to exit." << std::endl; - - while (true) { - if (serial.available() > 0) { - std::string data = serial.read(); - std::cout << "Received: " << data << std::endl; - serial.write("Echo: " + data); - } - - // Small delay to prevent busy waiting - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - } catch (const libserial::SerialException& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } - - return 0; - } - -Data Logger -~~~~~~~~~~~ - -Log incoming serial data to a file: - -.. code-block:: cpp - - #include - #include - #include - #include - #include - - int main() { - try { - libserial::Serial serial("/dev/ttyUSB0"); - serial.setBaudRate(libserial::BaudRate::BAUD_115200); - serial.setTimeout(std::chrono::seconds(1)); - serial.open(); - - std::ofstream logFile("serial_log.txt"); + #include + #include + #include + #include + #include + + #include "libserial/serial.hpp" + #include "libserial/serial_exception.hpp" + + int main(int argc, const char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << "Example: " << argv[0] << " /tmp/ttyV0" << std::endl; + std::cerr << std::endl; + std::cerr << "To create virtual ports with socat:" << std::endl; + std::cerr << "socat -d -d pty,link=/tmp/ttyV0,raw,echo=0 pty,link=/tmp/ttyV1,raw,echo=0" << std::endl; + return 1; + } + + std::string port = argv[1]; + + try { + // Create and configure serial port + libserial::Serial serial; + + std::cout << "Opening serial port: " << port << std::endl; + serial.open(port); + + std::cout << "Setting baud rate to 115200..." << std::endl; + serial.setBaudRate(libserial::BaudRate::BAUD_RATE_115200); + + // Verify configuration + int current_baud = serial.getBaudRate(); + std::cout << "Current baud rate: " << current_baud << std::endl; + + // Send a message + auto message = std::make_shared("Hello from libserial!"); + std::cout << "Sending message: '" << *message << "'" << std::endl; + serial.write(message); + + // Wait a bit for potential response + std::cout << "Waiting for response..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + // Check for available data + int available = serial.getAvailableData(); + std::cout << "Available data: " << available << " bytes" << std::endl; + + if (available > 0) { + auto buffer = std::make_shared(); + size_t bytes_read = serial.read(buffer); + std::cout << "Received (" << bytes_read << " bytes): '" << *buffer << "'" << std::endl; + } else { + std::cout << "No response received." << std::endl; + std::cout << "You can send data to the other end of the virtual port." << std::endl; + } + + // Interactive mode + std::cout << std::endl; + std::cout << "Interactive mode - type messages (Ctrl+C to exit):" << std::endl; + std::string input; + + while (true) { + std::cout << "> "; + std::getline(std::cin, input); + + if (input.empty()) continue; + + // Send user input + auto user_message = std::make_shared(input); + serial.write(user_message); + std::cout << "Sent: '" << input << "'" << std::endl; + + // Check for response + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + available = serial.getAvailableData(); + + if (available > 0) { + auto buffer = std::make_shared(); + size_t bytes_read = serial.read(buffer); + std::cout << "Received (" << bytes_read << " bytes): '" << *buffer << "'" << std::endl; + } + } + } catch (const libserial::SerialException& e) { + std::cerr << "Serial error: " << e.what() << std::endl; + return 1; + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; + } + + +.. Data Logger +.. ~~~~~~~~~~~ + +.. Log incoming serial data to a file: + +.. .. code-block:: cpp + +.. #include +.. #include +.. #include +.. #include +.. #include + +.. int main() { +.. try { +.. libserial::Serial serial("/dev/ttyUSB0"); +.. serial.setBaudRate(libserial::BaudRate::BAUD_115200); +.. serial.setTimeout(std::chrono::seconds(1)); +.. serial.open(); + +.. std::ofstream logFile("serial_log.txt"); - std::cout << "Data logger started. Logging to serial_log.txt" << std::endl; +.. std::cout << "Data logger started. Logging to serial_log.txt" << std::endl; - while (true) { - try { - std::string data = serial.read(256); +.. while (true) { +.. try { +.. std::string data = serial.read(256); - // Get current timestamp - auto now = std::chrono::system_clock::now(); - auto time_t = std::chrono::system_clock::to_time_t(now); +.. // Get current timestamp +.. auto now = std::chrono::system_clock::now(); +.. auto time_t = std::chrono::system_clock::to_time_t(now); - // Log with timestamp - logFile << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") - << " - " << data << std::endl; - logFile.flush(); +.. // Log with timestamp +.. logFile << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") +.. << " - " << data << std::endl; +.. logFile.flush(); - std::cout << "Logged: " << data << std::endl; +.. std::cout << "Logged: " << data << std::endl; - } catch (const libserial::TimeoutException& e) { - // Timeout is expected, continue - continue; - } - } +.. } catch (const libserial::TimeoutException& e) { +.. // Timeout is expected, continue +.. continue; +.. } +.. } - } catch (const libserial::SerialException& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } +.. } catch (const libserial::SerialException& e) { +.. std::cerr << "Error: " << e.what() << std::endl; +.. return 1; +.. } - return 0; - } +.. return 0; +.. } -Device Communication --------------------- +.. Device Communication +.. -------------------- -AT Command Interface -~~~~~~~~~~~~~~~~~~~~ +.. AT Command Interface +.. ~~~~~~~~~~~~~~~~~~~~ -Communicate with AT command-based devices (modems, GPS modules, etc.): +.. Communicate with AT command-based devices (modems, GPS modules, etc.): -.. code-block:: cpp +.. .. code-block:: cpp - #include - #include - #include - #include +.. #include +.. #include +.. #include +.. #include - class ATDevice { - private: - libserial::Serial serial_; +.. class ATDevice { +.. private: +.. libserial::Serial serial_; - public: - ATDevice(const std::string& port) : serial_(port) { - serial_.setBaudRate(libserial::BaudRate::BAUD_115200); - serial_.setTimeout(std::chrono::seconds(5)); - } +.. public: +.. ATDevice(const std::string& port) : serial_(port) { +.. serial_.setBaudRate(libserial::BaudRate::BAUD_115200); +.. serial_.setTimeout(std::chrono::seconds(5)); +.. } - void connect() { - serial_.open(); - std::cout << "Connected to device" << std::endl; - } +.. void connect() { +.. serial_.open(); +.. std::cout << "Connected to device" << std::endl; +.. } - std::string sendCommand(const std::string& command) { - // Send command with CR+LF - serial_.write(command + "\r\n"); +.. std::string sendCommand(const std::string& command) { +.. // Send command with CR+LF +.. serial_.write(command + "\r\n"); - // Read response - std::string response; - try { - response = serial_.read(1024); - } catch (const libserial::TimeoutException& e) { - throw std::runtime_error("Command timeout: " + command); - } +.. // Read response +.. std::string response; +.. try { +.. response = serial_.read(1024); +.. } catch (const libserial::TimeoutException& e) { +.. throw std::runtime_error("Command timeout: " + command); +.. } - return response; - } +.. return response; +.. } - bool testConnection() { - try { - std::string response = sendCommand("AT"); - return response.find("OK") != std::string::npos; - } catch (const std::exception& e) { - return false; - } - } - }; - - int main() { - try { - ATDevice device("/dev/ttyUSB0"); - device.connect(); +.. bool testConnection() { +.. try { +.. std::string response = sendCommand("AT"); +.. return response.find("OK") != std::string::npos; +.. } catch (const std::exception& e) { +.. return false; +.. } +.. } +.. }; + +.. int main() { +.. try { +.. ATDevice device("/dev/ttyUSB0"); +.. device.connect(); - if (device.testConnection()) { - std::cout << "Device is responding" << std::endl; +.. if (device.testConnection()) { +.. std::cout << "Device is responding" << std::endl; - // Get device information - std::string info = device.sendCommand("ATI"); - std::cout << "Device info: " << info << std::endl; +.. // Get device information +.. std::string info = device.sendCommand("ATI"); +.. std::cout << "Device info: " << info << std::endl; - } else { - std::cout << "Device is not responding" << std::endl; - } +.. } else { +.. std::cout << "Device is not responding" << std::endl; +.. } - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } +.. } catch (const std::exception& e) { +.. std::cerr << "Error: " << e.what() << std::endl; +.. return 1; +.. } - return 0; - } +.. return 0; +.. } -Sensor Data Collection -~~~~~~~~~~~~~~~~~~~~~~ +.. Sensor Data Collection +.. ~~~~~~~~~~~~~~~~~~~~~~ -Collect data from a serial sensor: +.. Collect data from a serial sensor: -.. code-block:: cpp +.. .. code-block:: cpp - #include - #include - #include - #include +.. #include +.. #include +.. #include +.. #include - struct SensorReading { - double temperature; - double humidity; - double pressure; - }; +.. struct SensorReading { +.. double temperature; +.. double humidity; +.. double pressure; +.. }; - class SensorReader { - private: - libserial::Serial serial_; +.. class SensorReader { +.. private: +.. libserial::Serial serial_; - public: - SensorReader(const std::string& port) : serial_(port) { - serial_.setBaudRate(libserial::BaudRate::BAUD_9600); - serial_.setTimeout(std::chrono::seconds(2)); - } +.. public: +.. SensorReader(const std::string& port) : serial_(port) { +.. serial_.setBaudRate(libserial::BaudRate::BAUD_9600); +.. serial_.setTimeout(std::chrono::seconds(2)); +.. } - void connect() { - serial_.open(); - } +.. void connect() { +.. serial_.open(); +.. } - SensorReading readSensor() { - // Request sensor data - serial_.write("READ\n"); +.. SensorReading readSensor() { +.. // Request sensor data +.. serial_.write("READ\n"); - // Read response (assuming CSV format: temp,humidity,pressure) - std::string response = serial_.read(100); +.. // Read response (assuming CSV format: temp,humidity,pressure) +.. std::string response = serial_.read(100); - // Parse CSV data - std::istringstream ss(response); - std::string token; - std::vector values; +.. // Parse CSV data +.. std::istringstream ss(response); +.. std::string token; +.. std::vector values; - while (std::getline(ss, token, ',')) { - values.push_back(std::stod(token)); - } +.. while (std::getline(ss, token, ',')) { +.. values.push_back(std::stod(token)); +.. } - if (values.size() != 3) { - throw std::runtime_error("Invalid sensor data format"); - } +.. if (values.size() != 3) { +.. throw std::runtime_error("Invalid sensor data format"); +.. } - return {values[0], values[1], values[2]}; - } - }; - - int main() { - try { - SensorReader sensor("/dev/ttyUSB0"); - sensor.connect(); +.. return {values[0], values[1], values[2]}; +.. } +.. }; + +.. int main() { +.. try { +.. SensorReader sensor("/dev/ttyUSB0"); +.. sensor.connect(); - for (int i = 0; i < 10; ++i) { - SensorReading reading = sensor.readSensor(); +.. for (int i = 0; i < 10; ++i) { +.. SensorReading reading = sensor.readSensor(); - std::cout << "Reading " << (i + 1) << ": " - << "Temp=" << reading.temperature << "°C, " - << "Humidity=" << reading.humidity << "%, " - << "Pressure=" << reading.pressure << "hPa" - << std::endl; +.. std::cout << "Reading " << (i + 1) << ": " +.. << "Temp=" << reading.temperature << "°C, " +.. << "Humidity=" << reading.humidity << "%, " +.. << "Pressure=" << reading.pressure << "hPa" +.. << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(1)); - } +.. std::this_thread::sleep_for(std::chrono::seconds(1)); +.. } - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } +.. } catch (const std::exception& e) { +.. std::cerr << "Error: " << e.what() << std::endl; +.. return 1; +.. } - return 0; - } +.. return 0; +.. } Port Discovery -------------- @@ -267,71 +331,71 @@ Discover and list available serial ports: .. code-block:: cpp - #include - #include + #include + #include + + #include "libserial/ports.hpp" + #include "libserial/device.hpp" + + int main() { + libserial::Ports ports; + + uint16_t num_ports = ports.scanPorts(); + std::cout << "Listed serial ports (if any)." << std::endl; + std::cout << "Number of devices found: " << num_ports + 1 << std::endl; + + for (uint16_t i = 0; i <= num_ports; ++i) { + auto name = ports.findName(i); + auto port_path = ports.findPortPath(i); + auto bus_path = ports.findBusPath(i); + std::cout << " [" << i << "] " << name.value_or("unknown") << " -> " << port_path.value_or("unknown") << " (bus: " << bus_path.value_or("unknown") << ")\n"; + } + std::vector devices; + ports.getDevices(devices); + + std::cout << "\nRetrieving device list via getDevices() method:\n"; + for (const auto& device : devices) { + std::cout << "Device Name: " << device.getName() << "\n"; + std::cout << "Port Path: " << device.getPortPath() << "\n"; + std::cout << "Bus Path: " << device.getBusPath() << "\n"; + std::cout << "Device ID: " << device.getId() << "\n"; + } + + return 0; + } - int main() { - try { - // Get list of available ports - auto ports = libserial::getAvailablePorts(); - - std::cout << "Available serial ports:" << std::endl; - - if (ports.empty()) { - std::cout << "No serial ports found." << std::endl; - } else { - for (const auto& port : ports) { - std::cout << " " << port << std::endl; - } - } - - // Try to open the first available port - if (!ports.empty()) { - libserial::Serial serial(ports[0]); - serial.open(); - std::cout << "Successfully opened: " << ports[0] << std::endl; - serial.close(); - } - - } catch (const libserial::SerialException& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } - - return 0; - } Building and Running Examples ----------------------------- -To build these examples, create a CMakeLists.txt file: +To run the examples, without physical serial devices, you can create virtual serial ports using `socat`. Open a terminal and run: -.. code-block:: cmake +.. code-block:: bash + # Terminal 1: Create virtual serial ports + $ socat -d -d pty,link=/tmp/ttyV0,raw,echo=0 pty,link=/tmp/ttyV1,raw,echo=0 + 2022/09/09 11:13:10 socat[19050] N PTY is /dev/pts/2 + 2022/09/09 11:13:10 socat[19050] N PTY is /dev/pts/3 + 2022/09/09 11:13:10 socat[19050] N starting data transfer loop with FDs [5,5] and [7,7] - cmake_minimum_required(VERSION 3.10) - project(libserial_examples) +You can build the examples using the main CMake system: - set(CMAKE_CXX_STANDARD 14) +.. code-block:: bash + $ mkdir build && cd build + $ cmake .. -DBUILD_EXAMPLES=ON + $ make examples - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBSERIAL REQUIRED libserial) +To run a simple communication example, execute the basic_communication example: - # Echo server example - add_executable(echo_server echo_server.cpp) - target_link_libraries(echo_server ${LIBSERIAL_LIBRARIES}) +.. code-block:: bash + # Terminal 2: Run the example + $ ./basic_communication /tmp/ttyV0 - # Data logger example - add_executable(data_logger data_logger.cpp) - target_link_libraries(data_logger ${LIBSERIAL_LIBRARIES}) + # Terminal 3: Interact with the other end + $ echo "Hello from terminal!" > /tmp/ttyV1 + $ cat /tmp/ttyV1 - # AT device example - add_executable(at_device at_device.cpp) - target_link_libraries(at_device ${LIBSERIAL_LIBRARIES}) -Then build: +You can also run the list_ports example to display all available serial devices on your system: .. code-block:: bash - - mkdir build && cd build - cmake .. - make \ No newline at end of file + ./examples/list_ports \ No newline at end of file From cce3564134ffe2ef989737188d4d7389fd160294 Mon Sep 17 00:00:00 2001 From: Nestor Neto Date: Fri, 31 Oct 2025 19:07:49 -0300 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=9D=20docs(usage):=20Fix=20typo=20?= =?UTF-8?q?errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/usage.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index d39ca79..1a10405 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -74,7 +74,7 @@ Basic read/write operations: int main() { try { - libserial::Serial serial(); + libserial::Serial serial; serial.open("/dev/ttyUSB0"); // Write data @@ -110,7 +110,7 @@ Configure read timeouts to prevent blocking: int main() { try { - libserial::Serial serial(); + libserial::Serial serial; serial.open("/dev/ttyUSB0"); // Set read timeout to 5 seconds serial.setReadTimeout(std::chrono::milliseconds(5000)); @@ -139,7 +139,7 @@ For non-blocking operations: int main() { try { - libserial::Serial serial(); + libserial::Serial serial; serial.open("/dev/ttyUSB0"); auto buffer = std::make_shared();