配置串口奇偶校验位

1 概述

介绍配置串口奇偶校验位的背景和适用范围。

1.1背景

串口校验位(Parity)用于检测数据传输中的错误。常见的校验方式有奇校验(odd)、偶校验(even)和无校验(none)。部分客户在使用ED-IPC1100的串口功能时,需要配置串口校验位以实现数据传输的可靠性。针对这一需求,我司提供详细的操作说明,帮助用户正确地配置串口奇偶校验位。

1.2 适用范围

本应用适用于ED-IPC1100设备。

2 应用指导

下文以ED-IPC1100设备的RS485为例,介绍安装和配置串口校验位的操作步骤。

2.1 串口映射

在进行安装前,请先确认设备的串口映射与蓝牙overlay设置,确保/dev/serial0指向预期的硬件设备/dev/ttyAMA0

前提条件:

  • ED-IPC1100已正常启动并接入网络。

操作步骤:

  1. 打开命令窗格,执行如下命令,打开config.txt文件。
sudo nano /boot/firmware/config.txt
  1. 按需配置dtoverlay参数。
  • 配置为dtoverlay=disable-bt,如下图所示。此设置表示/dev/serial0指向硬件端口/dev/ttyAMA0/dev/serial0 -> ttyAMA0),禁用蓝牙,PL011(硬件UART)用于串口(推荐用于稳定通信)。
step-1
  • 配置为dtoverlay=miniuart-bt,如下图所示。此设置表示/dev/serial0指向硬件端口/dev/ttyAMA0/dev/serial0 -> ttyAMA0),保留蓝牙但使用mini UART,PL011(硬件UART)用于串口,波特率可能受CPU频率影响(存在不稳定的风险)。
step-1
  1. 输入ctrl+o保存文件,再按Enter,最后输入ctrl+x退出文件编辑模式。

  2. 执行如下命令重启设备,使配置生效。

sudo reboot
  1. 执行如下命令,验证映射。
readlink -f /dev/serial0

2.2 配置串口校验位设置服务

前提条件:

  • ED-IPC1100已正常启动并接入网络。

操作步骤:

  1. 打开命令窗格,执行如下命令,创建安装文件。
sudo nano serial-service-installer.sh
  1. 将以下脚本内容复制到文件中:

#!/bin/bash

set -e

SCRIPT_NAME="serial-service-installer.sh"
SERVICE_NAME="serial-parity.service"
INSTALL_PATH="/usr/local/bin/serial-parity-daemon"
SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME"
CONFIG_FILE="/etc/serial-parity.conf"

# 默认配置
SERIAL_PORT="/dev/ttyAMA0"
BAUD_RATE="9600"
PARITY_MODE="even"

log() {
    echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

warn() {
    echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

error() {
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

manage_config() {
    local action="$1"
    local file_path="$2"
    
    case "$action" in
        "ensure")
            if [ ! -f "$file_path" ]; then
                mkdir -p "$(dirname "$file_path")" 2>/dev/null || true
                cat > "$file_path" << 'EOF'
# 串口奇偶校验配置
#偶校验even|奇校验odd|无校验none
PARITY_MODE=even
#接口配置
SERIAL_PORT=/dev/ttyAMA0
#波特率配置
BAUD_RATE=9600
EOF
                chmod 644 "$file_path" 2>/dev/null || true
                log "创建配置文件: $file_path"
            fi
            ;;
        "load")
            if [ -f "$file_path" ]; then
                source "$file_path"
            fi
            ;;
    esac
}

check_root() {
    if [[ $EUID -ne 0 ]]; then
        error "此操作需要root权限,请使用 sudo 执行"
        exit 1
    fi
}

check_serial_device() {
    local device="$1"
    if [ ! -e "$device" ]; then
        warn "串口设备 $device 不存在,但继续安装"
        return 1
    fi
    
    if [ ! -r "$device" ] || [ ! -w "$device" ]; then
        warn "对串口设备 $device 权限不足"
        return 1
    fi
    
    log "串口设备 $device 检查通过"
    return 0
}

create_daemon_script() {
    local daemon_path="$1"
    
    log "创建主服务程序..."
    
    cat > "$daemon_path" << 'DAEMON_EOF'
#!/bin/bash
# 串口奇偶校验守护进程

CONFIG_FILE="/etc/serial-parity.conf"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}

apply_serial_settings() {
    (
        case "$PARITY_MODE" in
            "even")
                stty -F "$SERIAL_PORT" speed "$BAUD_RATE" cs7 parenb -parodd -cstopb
                ;;
            "odd")
                stty -F "$SERIAL_PORT" speed "$BAUD_RATE" cs7 parenb parodd -cstopb
                ;;
            *)
                stty -F "$SERIAL_PORT" speed "$BAUD_RATE" cs8 -parenb -cstopb
                ;;
        esac
    ) >/dev/null 2>&1
    
    if [ $? -eq 0 ]; then
        log "串口设置成功: 模式=$PARITY_MODE, 波特率=$BAUD_RATE"
        return 0
    else
        log "串口设置失败"
        return 1
    fi
}

set_config() {
    local new_value="$1"
    
    [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"
    
    case "$new_value" in
        "even"|"odd"|"none")
            sed -i "s/^PARITY_MODE=.*/PARITY_MODE=$new_value/" "$CONFIG_FILE"
            PARITY_MODE="$new_value"
            log "设置校验模式: $PARITY_MODE"
            ;;
        *)
            if [[ "$new_value" =~ ^[0-9]+$ ]] && [ "$new_value" -ge 300 ] && [ "$new_value" -le 4000000 ]; then
                sed -i "s/^BAUD_RATE=.*/BAUD_RATE=$new_value/" "$CONFIG_FILE"
                BAUD_RATE="$new_value"
                log "设置波特率: $BAUD_RATE"
            else
                echo "错误: 无效参数 '$new_value'"
                echo "用法: $0 set {even|odd|none|波特率}"
                return 1
            fi
            ;;
    esac
    
    apply_serial_settings
}

show_help() {
    cat <<'EOF'
串口奇偶校验服务
用法: /usr/local/bin/serial-parity-daemon set {none|odd|even|波特率}

设置示例:
  sudo serial-parity-daemon set odd     # 奇校验  
  sudo serial-parity-daemon set 115200  # 115200波特率

服务管理:
  sudo systemctl {start|stop|status} serial-parity.service
EOF
}

main_service() {
    [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"
    
    log "启动串口服务: $SERIAL_PORT, $BAUD_RATE, $PARITY_MODE"
    
    [ ! -e "$SERIAL_PORT" ] && {
        log "错误: 串口设备不存在"
        exit 1
    }
    
    apply_serial_settings || exit 1
    
    log "服务运行中"
    
    while true; do
        sleep 3600
    done
}

case "${1:-}" in
    "start") main_service ;;
    "set") 
        [ -n "$2" ] && set_config "$2" || {
            echo "用法: $0 set {even|odd|none|波特率}"
            exit 1
        }
        ;;
    "help"|"-h"|*) show_help ;;
esac
DAEMON_EOF

    chmod +x "$daemon_path"
    log "主服务程序创建完成: $daemon_path"
}

create_systemd_service() {
    log "创建systemd服务文件..."
    
    cat > "$SERVICE_FILE" << SERVICE_EOF
[Unit]
Description=Serial Port Parity Configuration Service
After=multi-user.target

[Service]
Type=simple
ExecStart=$INSTALL_PATH start
Restart=always
RestartSec=5
User=root
Group=dialout

[Install]
WantedBy=multi-user.target
SERVICE_EOF

    log "systemd服务文件创建完成: $SERVICE_FILE"
}

install_service() {
    check_root
    log "开始安装串口服务..."
    
    check_serial_device "$SERIAL_PORT"
    
    mkdir -p "$(dirname "$INSTALL_PATH")"
    [ -f "$INSTALL_PATH" ] && {
        backup="$INSTALL_PATH.backup.$(date +%Y%m%d_%H%M%S)"
        cp "$INSTALL_PATH" "$backup"
        log "已备份现有文件: $backup"
    }
    
    create_daemon_script "$INSTALL_PATH"
    create_systemd_service
    manage_config "ensure" "$CONFIG_FILE"
    
    systemctl daemon-reload
    systemctl enable "$SERVICE_NAME"
    log "服务安装完成"
}

start_service() {
    check_root
    systemctl start "$SERVICE_NAME" && log "服务启动成功" || {
        error "服务启动失败"
        exit 1
    }
}

self_cleanup() {
    log "安装完成,清理安装脚本..."
    cat > /tmp/cleanup-$$.sh << 'CLEANUP_EOF'
#!/bin/bash
sleep 3
[ -f "$1" ] && rm -f "$1"
rm -f "$0"
CLEANUP_EOF

    chmod +x /tmp/cleanup-$$.sh
    nohup /tmp/cleanup-$$.sh "$0" >/dev/null 2>&1 &
}

show_help() {
    cat <<'EOF'
串口服务安装脚本
用法: sudo ./serial-service-installer.sh install
EOF
}

main() {
    case "${1:-}" in
        "install")
            install_service
            start_service
            self_cleanup
            ;;
        *) show_help ;;
    esac
}

[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@"

  1. 依次执行如下命令,安装脚本并生成unit。
sudo chmod +x serial-service-installer.sh
sudo ./serial-service-installer.sh install
  1. 执行如下命令,查看服务状态。
sudo systemctl status serial-parity.service

2.3 更改串口配置

前提条件:

  • ED-IPC1100已正常启动并接入网络。

操作步骤:

  1. 打开命令窗格,执行如下命令,打开配置文件。
sudo nano /etc/serial-parity.conf
step-1
  1. 按需修改校验位和波特率。
  • even/odd:常配7数据位(cs7);
  • none:使用8数据位(cs8)。
  1. 输入ctrl+o保存文件,再按Enter,最后输入ctrl+x退出文件编辑模式。

  2. 依次执行如下命令,重启服务,使配置生效。

sudo systemctl stop serial-parity.service
sudo systemctl start serial-parity.service

2.4 常用操作

  • 启动服务:sudo systemctl start serial-parity.service
  • 停止服务:sudo systemctl stop serial-parity.service
  • 开机自启:sudo systemctl enable serial-parity.service
  • 取消开机自启:sudo systemctl disable serial-parity.service
  • 查看状态:sudo systemctl status serial-parity.service