You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式Linux下CAN总线终端数据读取与字符串比对实现问询

Solution for Reading candump can0 Line-by-Line and Comparing Data in C++

Hey there! Since you're working with a GOEMBED TI AM3358 board running embedded Linux and already have a basic GetCmdOutput function, let's tackle your two specific needs step by step: reading the continuous candump can0 output line-by-line, and comparing those captured lines against target strings.


1. Line-by-Line Real-Time Reading of Terminal Output

Your existing GetCmdOutput likely captures the entire command output at once, but candump can0 produces a never-ending stream of CAN messages. To read this line by line as it comes in, we'll use popen() to create a pipe to the command, then use standard I/O functions to read each line in real time.

Here's a reusable, embedded-friendly function for this:

#include <iostream>
#include <string>
#include <cstdio>

// Define a callback type to handle each line (flexible for custom processing)
using LineHandler = void(*)(const std::string& line);

void ReadCmdStreamLineByLine(const std::string& cmd, LineHandler handler) {
    // Open a pipe to the command's standard output
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) {
        std::cerr << "Failed to launch command: " << cmd << std::endl;
        return;
    }

    // Buffer to hold each line (adjust size based on your CAN message length)
    char lineBuffer[256];
    while (fgets(lineBuffer, sizeof(lineBuffer), pipe) != nullptr) {
        std::string rawLine(lineBuffer);
        // Remove trailing newline character to clean up the line
        if (!rawLine.empty() && rawLine.back() == '\n') {
            rawLine.pop_back();
        }
        // Pass the cleaned line to your custom handler
        if (handler) {
            handler(rawLine);
        }
    }

    // Clean up the pipe to avoid resource leaks/zombie processes
    int closeStatus = pclose(pipe);
    if (closeStatus == -1) {
        std::cerr << "Error closing command pipe" << std::endl;
    }
}

How to use this with candump can0:

Define a custom handler function to process each CAN line, then pass it to the reader function:

void HandleCanFrame(const std::string& line); // Forward declaration

int main() {
    // Start reading candump output line by line (blocks until candump stops)
    ReadCmdStreamLineByLine("candump can0", HandleCanFrame);
    return 0;
}

This works because popen() runs candump in a child process and connects its output to a readable pipe. fgets() blocks until a new line is available, which is perfect for handling the continuous stream from CAN bus data.


2. Store Data in Variables and Compare with Strings

Now that we're capturing each line, let's parse it into usable variables and compare against target strings. A typical candump line looks like this:

can0 123 [8] 01 02 03 04 05 06 07 08

We'll extend the HandleCanFrame function to extract components (interface, CAN ID, data bytes) and run comparisons:

#include <sstream>
#include <vector>
#include <algorithm>

void HandleCanFrame(const std::string& line) {
    // Split the line into individual tokens
    std::istringstream lineStream(line);
    std::vector<std::string> tokens;
    std::string token;
    while (lineStream >> token) {
        tokens.push_back(token);
    }

    // Skip malformed lines that don't match the expected candump format
    if (tokens.size() < 4) {
        std::cerr << "Skipping invalid CAN line: " << line << std::endl;
        return;
    }

    // Extract components into variables
    std::string canInterface = tokens[0];
    std::string canId = tokens[1];
    // Strip brackets from data length (e.g., "[8]" -> "8")
    std::string dataLength = tokens[2].substr(1, tokens[2].size() - 2);
    std::vector<std::string> dataBytes(tokens.begin() + 3, tokens.end());

    // Example 1: Compare CAN ID to a target value
    const std::string targetCanId = "123";
    if (canId == targetCanId) {
        std::cout << "Detected target CAN ID: " << targetCanId << std::endl;
    }

    // Example 2: Check if a specific data byte exists in the frame
    const std::string targetByte = "03";
    auto byteMatch = std::find(dataBytes.begin(), dataBytes.end(), targetByte);
    if (byteMatch != dataBytes.end()) {
        std::cout << "Found target byte " << targetByte << " in frame: " << line << std::endl;
    }

    // Example 3: Match the entire line to an exact target string
    const std::string targetFullLine = "can0  123   [8]  01 02 03 04 05 06 07 08";
    if (line == targetFullLine) {
        std::cout << "Exact frame match found!" << std::endl;
    }
}

Key Tips for Embedded Linux:

  • Buffer Size: Adjust lineBuffer[256] to match the maximum length of your candump lines—embedded systems have limited stack space, so don't oversize it.
  • Resource Cleanup: Always call pclose() to avoid zombie processes and resource leaks, which are critical for long-running embedded applications.
  • Error Handling: Add extra checks (like verifying CAN interface availability) if your system requires high reliability.

Full Integration

Combine these functions, and you'll have a complete solution that reads CAN bus data line-by-line, stores key components in variables, and compares them against your target strings. Modify the HandleCanFrame function to fit your exact use case (e.g., triggering actions when specific frames are detected).

内容的提问来源于stack exchange,提问作者TMO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:37:16