linux串口特定channel,Linux 将串口映射为TCP服务+无线热点(树莓派)

起因

最近在做一个Android控制APP,本来想使用蓝牙BLE的串口透传模块,但是因为项目中使用的串口数据包比较长,通信比较频繁,买了个透传模块一次多大(MTU)只有20个字节,也不支持修改,而且写入过程需要有Thread.sleep(23),就很蛋疼了,数据量一大通信延迟特别严重,而且控制的设备对实时性要求较高,这个方案显然不能满足要求,放弃。

手里刚好有一块树莓派3B+,放着吃灰,想着是不是可以用树莓派建WIFI热点,把串口用网络转发出来。树莓派自带的串口,网上说有些小问题,再有项目中需要控制多个串口,树莓派最多自带2个,不走弯路直接上usb转串口,插到rspi的USB上,试了几个常用模块,都可以识别,美滋滋。插上之后在/dev/ttyUSB*上,可以用echo 123 > /dev/ttyUSB0去尝试发送。

第一步将串口映射为TCP服务,双向转发。

首先当然是想自己写代码转发,网上搜了下,嗯~~,好像都是简单demo,要写成产品级别的估计要下点功夫。看有没有现成的工具,学过几天信安,转发当然是nc(netcat),奈何好像脚本挺负载的,最后在国外某论坛上找到了一个一条命令搞定的好玩意,socat,完美解决问题

socat TCP-LISTEN:4161,fork,reuseaddr FILE:/dev/ttyUSB0,b57600,raw,echo=0”

#4161是TCP服务的端口号

#/dev/ttyUSB0就是对应的USB转的串口

#最后加echo=0,不加的话树莓派会给串口回写,也就是外部设备向串口写什么,串口会原样向串口返回同样的数据

测试使用sscom串口调试工具使用网络“TCPClient”连接测试,通信顺畅,测试一小时连接正常,大问题解决

第二步将TCP服务设为自启动,不需要也不可能每次都要人工启动。

确定串口设备的名称

首先要解决的问题是usb转串口每次插入时设备名不确定的问题,由于是多个串口,不能确定是哪一个,这就要求设置usb串口名称固定

在/etc/udev/rules.d/99-input.rules(也有可能不一样),中添加一行:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523",ATTRS{serial}=="123456", SYMLINK+="userilaMoto"

这些信息可以使用命令 udevadmin info -a -n /dev/ttyUSB0 中查找idVendor,idProduct,serial,可以添加更多只要能区分出不同设备即可

最后SYMLINK就是设置完成后在/dev中要出现的名称,当然不能与现有的重名。

可是有些串口设备没有serial号,呵呵,如果买了几个相同的usb转串口根本没法区分。

最后在/dev/serial目录下有两个目录 by-id 和 by-path,在by-path下不管是什么模块插上只要物理USB端口一样,名字就不会变,这就方便多了,哈哈。

串口名称形如/dev/serial/by-path/platform-3f980000.usb-0:1.2:0-port0

设置编写服务脚本

在/etc/init.d/下建立一个脚本文件取名netserial,名字可以自己起

在/etc/init.d/下有很多服务脚本,可以参考编写,注意下面脚本中echo和log*mes使用service或systemctl命令都不会显示,不写无妨,只是在自己测试脚本的时候比较方便而已

/etc/init.d/netserial

#!/bin/sh

#

### BEGIN INIT INFO

# Provides: netserial

# Required-Start:

# Required-Stop:

# Should-Start:

# Should-Stop:

# Default-Start: 2 3 4 5

# Default-Stop: 0 1 6

# Short-Description: serial port via network

# Description:

### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

. /lib/lsb/init-functions

start(){

pcount=$(ps -aux | grep TCP-LISTEN:5961 | grep socat | wc -l)

if [ $pcount -eq 0 ]

then

nohup socat -lu -d -d -d TCP-LISTEN:5961,fork,reuseaddr FILE:'/dev/serial/by-path/platform-3f980000.usb-usb-0\:1.3\:1.0-port0',b57600,raw,echo=0 > /var/logs/socat5961.log &

log_success_msg "\033[32msocat TCP:5961 RightTop USB Serial Port@57600 Started \033[0m"

else

log_warning_msg "\033[35msocat TCP:5961 RightTop USB Serial Port@57600 has Started last time \033[0m"

fi

pcount=$(ps -aux | grep TCP-LISTEN:5962 | grep socat | wc -l)

if [ $pcount -eq 0 ]

then

nohup socat -lu -d -d -d TCP-LISTEN:5962,fork,reuseaddr FILE:'/dev/serial/by-path/platform-3f980000.usb-usb-0\:1.2\:1.0-port0',b38400,raw,echo=0 > /var/logs/socat5962.log &

log_success_msg "\033[32msocat TCP:5962 RightBottom USB Serial Port@38400 Started \033[0m"

else

log_warning_msg "\033[35msocat TCP:5962 RightBottom USB Serial Port@38400 has Started last time \033[0m"

fi

pcount=$(ps -aux | grep TCP-LISTEN:5963| grep socat | wc -l)

if [ $pcount -eq 0 ]

then

nohup socat -lu -d -d -d TCP-LISTEN:5963,fork,reuseaddr FILE:'/dev/serial/by-path/platform-3f980000.usb-usb-0\:1.1.3\:1.0-port0',b9600,raw,echo=0 > /var/logs/socat5963.log &

log_success_msg "\033[32msocat TCP:5963 LeftBottom USB Serial Port@9600 Started \033[0m"

else

log_warning_msg "\033[35msocat TCP:5963 LeftBottom USB Serial Port@9600 has Started last time \033[0m"

fi

}

stop(){

pcount=$(ps -aux | grep TCP-LISTEN:5961 | grep socat | wc -l)

if [ $pcount -gt 0 ]

then

ps -aux | grep TCP-LISTEN:5961 | grep socat | awk '{print $2}' | xargs kill

log_success_msg "\033[31msocat TCP:5961 RightTop USB Serial Port Stop\033[0m"

fi

pcount=$(ps -aux | grep TCP-LISTEN:5962| grep socat | wc -l)

if [ $pcount -gt 0 ]

then

ps -aux | grep TCP-LISTEN:5962| grep socat | awk '{print $2}' | xargs kill

log_success_msg "\033[31msocat TCP:5962 RightBottom USB Serial Port Stop\033[0m"

fi

pcount=$(ps -aux | grep TCP-LISTEN:5963 | grep socat | wc -l)

if [ $pcount -gt 0 ]

then

ps -aux | grep TCP-LISTEN:5963 | grep socat | awk '{print $2}' | xargs kill

log_success_msg "\033[31msocat TCP:5963 LeftBottom USB Serial Port Stop\033[0m"

fi

}

status(){

pcount=$(ps -aux | grep TCP-LISTEN:5961 | grep socat | wc -l)

if [ $pcount -gt 0 ]

then

log_progress_msg "\033[32msocat TCP:5961 RightTop USB Serial Port @57600 active\033[0m \n"

else

echo "\033[31msocat TCP:5961 RightTop USB Serial Port @57600 inactive\033[0m \n"

#cat /var/logs/socat5961.log | grep -v transferred | tail -n 20

fi

log_progress_msg "see log in /var/logs/socat5961.log \n"

pcount=$(ps -aux | grep TCP-LISTEN:5962| grep socat | wc -l)

if [ $pcount -gt 0 ]

then

echo "\033[32msocat TCP:5962 RightBottom USB Serial Port @38400 active\033[0m"

else

echo "\033[31msocat TCP:5962 RightBottom USB Serial Port @38400 inactive\033[0m"

fi

log_progress_msg "see log in /var/logs/socat5962.log \n"

pcount=$(ps -aux | grep TCP-LISTEN:5963 | grep socat | wc -l)

if [ $pcount -gt 0 ]

then

echo "\033[32msocat TCP:5963 LeftBottom USB Serial Port @9600 active\033[0m"

else

echo "\033[31msocat TCP:5963 LeftBottom USB Serial Port @9600 inactive\033[0m"

fi

log_progress_msg "see log in /var/logs/socat5963.log \n"

}

case "$1" in

start)

start

;;

stop)

stop

;;

restart)

stop

start

;;

status)

status

;;

*)

log_failure_msg "Usage: /etc/init.d/netserial {start|stop|restart|status}"

exit 1

;;

esac

设置开机启动

cd /etc/init.d

#脚本权限

chmod 775 netserial

#安装启动脚本,96是启动序号,因为需要使用网络,和usb硬件,设置到靠后,多个串口可以分别安装

update-rc.d netserial defaults 96

#卸载启动脚本,先写到这里,以免后期需要卸载

# update-rc.d -f netserial remove

# 同样可以使用 service或者systemctl start/stop/restart/status 控制服务

无线热点

由于不可能每次都要手动在设备上连接无线网络,需要无线网络自动连接,有两种方案可选:

手机/平板创建热点,树莓派自动连接,缺点,移动设备热点不会自动开启,长时间不连接会关闭,如果热点名字改了密码变了,就再连接不上了,而且支持特定设备。

树莓派创建热点,移动设备自动连接,缺点实现有点难度,但使用方便。

3.使用自动化工具完成 [更新]

主要有两种一个是create_ap,另一个是

wget -q https://git.io/voEUQ -O /tmp/raspap && bash /tmp/raspap

更新:以下方式太麻烦(不推荐)

下面采用法案2搭建热点,就当给自己做笔记,一面以后再填坑。

使用hostapd dnsmasq 搭建

sudo apt-get install dnsmasq hostapd

# 修改 /etc/dhcpcd.conf

interface wlan0

static ip_address=192.168.0.1/24

# 创建 sudo nano /etc/hostapd/hostapd.conf

interface=wlan0

driver=nl80211

ssid=RaspberryPi

hw_mode=g

channel=7

wmm_enabled=0

macaddr_acl=0

auth_algs=1

ignore_broadcast_ssid=0

wpa=2

wpa_passphrase=12345678

wpa_key_mgmt=WPA-PSK

rsn_pairwise=CCMP

# 修改/etc/default/hostapd

DAEMON_CONF="/etc/hostapd/hostapd.conf"

#配置DNSMASQ

sudo mv /etc/dnsmasq.conf /etc/bak_dnsmasq.conf

#重新创建 /etc/dnsmasq.conf,并写入

interface=wlan0

dhcp-range=192.168.0.2,192.168.0.20,255.255.255.0,24h

# 还有net转发,当然这里不涉及数据转发问题

到此为止好像结束了,但是hostapd 起不来,查看状态,提示

Loaded: masked (/dev/null; bad)

需要使用命令"unmask"

sudo systemctl unmask hostapd.service

sudo systemctl enable hostapd.service

但是开机之后还是没有无线热点,但是 service hostapd status 提示启动了呀,并且重启服务就可以正常连接,好坑呀。

最后查看状态有一个日志提示

random: Cannot readfrom /dev/random: Try again

random: Only 0/20bytes of strong random data available from /dev/random

random: Not enoughentropy pool available for secure operations

表示随机数不够,查了一下是因为/dev/random 生成速度太慢,改成/dev/urandom 就好了

网上有说是将random 备份然后软链接urandom->random,但是每次重启后就没有了...

没办法只有源码改造了

#下载源码

wget http://w1.fi/releases/hostapd-2.9.tar.gz

tar -xzvf hostapd-2.6.tar.gz

#配置文件

cd hostapd-2.6/hostapd

cp defconfig .config

#修改源码

hostapd-2.6/src/crypto/random.c :(不止1处)

由 fd = open("/dev/random", O_RDONLY | O_NONBLOCK);

改为 fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK);

#安装依赖,使用工具搜索缺失的依赖

sudo apt install apt-file

apt-file search xx/xx/xx.h

#编译,如果出现错误安装对应的依赖

cd hostapd-2.9/hostapd

make

#将编译好的hostapd覆盖原来的文件

sudo cp hostapd /usr/sbin/

sudo cp hostapd_cli /usr/sbin/

嗯....,提示信息是没了,但是还是不能开机启动,手启可以,没办法了,最后在netserial脚本上加了一句

start(){

...

#暂停10秒

sleep 10

#重启hostapd服务

service hostapd restart

}

不算完美,功能实现了,不想折腾了...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值