Newer
Older
casic_unitree_dog / src / methane_serial_port.cpp
//
// Created by pengx on 2025/3/18.
//

#include "methane_serial_port.hpp"
#include "tcp_service.hpp"
#include "config.hpp"
#include "utils.hpp"

#include <iomanip>
#include <iostream>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = net::ip::tcp;

void upload_to_server(const int value) {
    net::io_context ioc;
    tcp::resolver resolver{ioc};
    auto const results = resolver.resolve(Config::REMOTE_SERVICE_IP, Config::HTTP_PORT);
    tcp::socket socket{ioc};
    try {
        net::connect(socket, results.begin(), results.end());
        // 构建HTTP请求
        http::request<http::string_body> req{http::verb::post, Config::API_RECEIVE_DATA, 11};
        req.set(http::field::host, Config::REMOTE_SERVICE_IP);
        req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
        req.set(http::field::content_type, "application/json");
        req.set(http::field::connection, "keep-alive");
        //{"type":6,"devcode":"1212","data":{"gas":"20"}}
        std::ostringstream oss;
        oss << R"({"type":6,"devcode":")"
                << Config::DOG_CODE
                << R"(","data":{"gas":")"
                << value
                << R"("}})";
        std::string body = oss.str();
        req.body() = body;
        req.prepare_payload();

        // 发送HTTP请求
        http::write(socket, req);
    } catch (std::exception const &e) {
        std::cerr << "Error: " << e.what() << std::endl;
        if (socket.is_open()) {
            socket.shutdown(tcp::socket::shutdown_both);
            socket.close();
        }
    }
}

void MethaneSerialPort::upload_to_server_async(const int value) {
    post(io_service_, [this, value] {
        upload_to_server(value);
    });
}

void MethaneSerialPort::handle_response(const std::vector<uint8_t> &buffer) {
    const auto x = buffer[2];
    const auto y = buffer[3];
    const auto z = buffer[4];
    const auto w = buffer[5];
    const auto result = x * (1 << 24) + y * (1 << 16) + z * (1 << 8) + w;
    TcpService::getInstance().update_gas_value(result);
    // 上传服务器
    if (Utils::is_network_reachable(Config::REMOTE_SERVICE_IP, Config::HTTP_PORT)) {
        upload_to_server_async(result);
    }
}

MethaneSerialPort::MethaneSerialPort(
    boost::asio::io_service &io_service, const std::string &port_name, const int baud_rate
): io_service_(io_service), port_(io_service, port_name), timer_(io_service) {
    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::parity(serial_port_base::parity::none));
    port_.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one));
    std::cout << "\033[1;92m"
            << "MethaneSerialPort init success"
            << "\033[0m" << std::endl;

    start_timer();
}

void MethaneSerialPort::start_timer() {
    timer_.expires_from_now(boost::posix_time::seconds(1));
    timer_.async_wait([this](const boost::system::error_code &error) {
        if (!error) {
            read_from_port();
        }
    });
}

//CC 05 00 00 00 00 0D 77
void MethaneSerialPort::read_from_port() {
    async_read(
        port_, buffer_, boost::asio::transfer_at_least(8),
        [this](const boost::system::error_code &error, const size_t) mutable {
            if (!error) {
                if (buffer_.size() >= 8) {
                    std::istream is(&buffer_);
                    std::vector<uint8_t> response(8);
                    is.read(reinterpret_cast<char *>(response.data()), 8);
                    if (response[0] == 0xCC && response[7] == 0x77) {
                        handle_response(response); // 处理最新的一帧
                    }
                }
                // 丢弃所有缓存数据
                buffer_.consume(buffer_.size());

                // 继续下一次读取
                read_from_port();
            } else {
                start_timer();
            }
        }
    );
}