Newer
Older
casic_unitree_dog / src / tcp_service.cpp
//
// Created by casic on 25-2-25.
//

#include "tcp_service.hpp"
#include <iomanip>
#include <cerrno>
#include <vector>
#include <iostream>
#include <stdexcept>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

void TcpService::init_serial_port(const std::string &port_name, const int baud_rate) {
    _port.open(port_name);
    if (_port.is_open()) {
        _port.set_option(serial_port_base::baud_rate(baud_rate));
        _port.set_option(serial_port_base::character_size(8));
        _port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one));
        _port.set_option(serial_port_base::parity(serial_port_base::parity::none));
        _port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none));
    } else {
        std::cerr << "Failed to open serial port" << std::endl;
    }
}

TcpService::TcpService(
    boost::asio::io_context &io_context, const std::string &port_name, const int baud_rate
): _context(io_context), _port(io_context) {
    std::cout << "TcpService::init success" << std::endl;
    init_serial_port(port_name, baud_rate);
}

void TcpService::handle_data_packet(std::vector<uint8_t> &data) {
    for (const uint8_t i: data) {
        std::cout << std::hex
                << std::uppercase
                << std::setw(2)
                << std::setfill('0')
                << static_cast<int>(static_cast<uint8_t>(i))
                << " ";
    }
    std::cout << std::endl;

    //转为std::vector<uint8_t>并发给机械臂串口
    std::vector command(data.begin(), data.end());
    const size_t bytes_to_send = command.size();
    if (bytes_to_send == 0) {
        std::cout << "Empty command, nothing to send." << std::endl;
        return;
    }

    try {
        const size_t bytes_sent = boost::asio::write(_port, boost::asio::buffer(command));
        if (bytes_sent == bytes_to_send) {
            std::cout << "sent successfully" << std::endl;
        } else {
            std::cerr << "only " << bytes_sent << " bytes sent out of " << bytes_to_send << std::endl;
        }
    } catch (const boost::system::system_error &e) {
        std::cerr << "error sending data: " << e.what() << std::endl;
    }
}

void TcpService::handle_client(const int client_socket) {
    std::vector<uint8_t> buffer;
    char byte;
    while (true) {
        const ssize_t bytes_received = recv(client_socket, &byte, 1, 0);
        if (bytes_received < 0) {
            std::cerr << "Failed to receive data: " << strerror(errno) << std::endl;
            close(client_socket);
            return;
        }

        if (bytes_received == 0) {
            std::cerr << "Connection closed by client" << std::endl;
            close(client_socket);
            return;
        }

        buffer.push_back(byte);

        if (static_cast<uint8_t>(byte) == 0xFA) {
            // 处理接收到的数据包
            if (!buffer.empty()) {
                handle_data_packet(buffer);
                buffer.clear(); // 清空缓冲区以接收下一个数据包
            }
        }
    }
}

void TcpService::start(const int port) {
    try {
        _socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_socket_fd == -1) {
            throw std::runtime_error("failed to create socket");
        }

        // 绑定套接字
        sockaddr_in server_addr = {};
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        if (bind(_socket_fd, reinterpret_cast<sockaddr *>(&server_addr), sizeof(server_addr)) == -1) {
            throw std::runtime_error("failed to bind socket");
        }

        // 监听连接,最多允许5个连接
        if (listen(_socket_fd, 5) == -1) {
            throw std::runtime_error("failed to listen on socket");
        }

        std::cout << "TcpService started" << " and listening on port " << port << std::endl;

        // 接受连接
        while (true) {
            sockaddr_in client_addr{};
            socklen_t client_len = sizeof(client_addr);
            const int client_socket_fd = accept(_socket_fd, reinterpret_cast<sockaddr *>(&client_addr), &client_len);
            if (client_socket_fd == -1) {
                std::cerr << "failed to accept connection" << std::endl;
                continue;
            }

            std::cout << "accepted connection from "
                    << inet_ntoa(client_addr.sin_addr)
                    << ":"
                    << ntohs(client_addr.sin_port)
                    << std::endl;

            // 处理连接
            handle_client(client_socket_fd);
        }
    } catch (const std::exception &e) {
        std::cerr << "exception in tcp_server::start: " << e.what() << std::endl;
    }
}