随身WIFI折腾日记(一)---霓虹灯

引言

通过对高通410芯片的随身WIFI刷写Debain系统,我们已经拥有了一台带4G功能的迷你ARM64单板电脑。现在我们可以基于此此平台进行一下二次开发。

随身WIFI的优势就是价格低廉,性能和树莓派zero2、树莓派3b差不多。

硬件配置如下

  • msm8916 主控 Cortex-A53 * 4 on 0.9GHZ
  • 512MB内存+4GB储存emcp
  • WCN3620 & WCN3680b
  • pm8916 PMIC
  • USB接口

外设的io定义如下

型号 red led green led blue led 按键
ufi001b/c gpio22 gpio21 gpio20 gpio37

一、霓虹灯

我主要是想通过点亮LED灯学习一下Linux如何控制底层硬件设备。

1.1 点灯

随身WIFI存在三个led灯,openstick作者设置默认blue表示wifi连接状态,red表示系统是否还处于正常运行状态。

  • 可以通过 echo <行为> > /sys/class/led/<名字>/trigger 来修改led行为。
    可用的行为如下:

    root@openstick:/sys/class/leds/green:internet# cat trigger 
    [none] usb-gadget usb-host rfkill-any rfkill-none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer heartbeat cpu cpu0 cpu1 cpu2 cpu3 default-on panic mmc0 bluetooth-power hci0-power rfkill0 phy0rx phy0tx phy0assoc phy0radio rfkill1
    

可以看到green:internet设备的trigger属性为[none],触发事件为无,即关灯。

  • 设置green led为常量状态

    root@openstick:/sys/class/leds/green:internet# echo default-on > trigger
    

    image-20230517190959899

  • green led的行为定义为usb device模式的活动状态

    root@openstick:/sys/class/leds/green:internet# echo usb-gadget > trigger
    

写入该字符串后led行为立刻生效,重启失效。配置完成后绿色LED在每次USB接口有数据传输时都会闪烁。

1.2 命令解析

 root@openstick:/sys/class/leds/green:internet# echo usb-gadget > trigger
  • /sys: sysfs是一种虚拟的文件系统,可以查看和控制Linux系统中的设备驱动程序和硬件信息。通过sysfs,可以获得系统中已经加载的驱动程序的信息,包括文件系统,输入设备,串口,以太网等等。我们可以通过读写/sys目录下虚拟出来的设备文件控制底层硬件。
  • class - sysfs目录中的一个部分,包含所有的类,用于实现驱动程序中的设备模型。
  • leds - 设备类的名称,用于控制和访问系统的LED组。
  • green:internet - 设备的名称,用于指示您要使用的特定的LED。
  • trigger - 设备属性,表示LED触发器。允许你改变LED工作的模式(例如常亮、闪烁等)。常见的一些trigger值包括none(常亮)、timer(闪烁)、heartbeat(心跳等节律),不同的LED设备支持不同的trigger。可以使用cat命令读取该文件来查看LED设备支持哪些trigger。LED有很多其他常用属性,例如
    • brightness - LED亮度,值为0-255之间的整数。
    • max_brightness - LED的最大亮度值。可以使用cat命令读取该文件来获取LED的最大亮度值。
    • delay_ondelay_off - 用于设置闪烁效果的LED特有属性。delay_on表示LED打开状态的时间长度,delay_off表示LED关闭状态的时间长度。
  • >-重定向符号,即将前面的命令的输出结果(标准输出流stdout)写入到其后面指定的文件中。即向trigger设备文件中写入usb-gadget字符。

总结来说,通过sysfs虚拟文件系统控制底层设备的方法如下:

#  写数据到设备
$/sys/class/设备组/设备名称# echo 属性值 > 属性名称
#  从设备读数据
$/sys/class/设备组/设备名称# cat  属性名称

1.3 硬件控制方式

sysfs之外,我们还可以通过以下方式来控制底层硬件:

  1. 控制寄存器 - 通过使用适当的驱动程序和底层编程语言(如C语言或汇编语言),直接访问控制硬件设备的寄存器。这需要了解硬件设备的寄存器地址和寄存器的具体功能和使用方法。
  2. I/O端口 - 通过使用适当的驱动程序和底层编程语言(如C语言或汇编语言),访问控制硬件设备的I/O端口。这需要了解硬件设备I/O端口的地址和具体的输入输出方法。
  3. 设备文件 - 一些设备可以视为文件,并提供类似文件操作的接口来进行控制。比如,通过/dev/ttyS0设备文件访问串口设备。这需要了解设备文件的访问方法以及设备的具体使用方法。

这些方法都需要了解硬件设备的具体实现细节,因此需要较高水平的技能才能进行硬件控制。如果你想更简单地控制硬件,可以考虑使用通用的高级硬件控制框架或库。这些框架和库一般隐藏了底层硬件控制的实现细节,提供了易于使用和跨平台的高级接口,使得你可以用更简单的方式来控制硬件。

一些流行的高级硬件控制框架或库包括:

  1. WiringPi(用于树莓派)
  2. RPi.GPIO(树莓派Python库)
  3. Adafruit-GPIO(通用的Python GPIO库)
  4. libusb(通用的USB设备控制库)
  5. PyUSB(通用的Python USB库)

使用这些框架或库,你可以用更高级别的代码(通常是Python或其他易于使用的脚本语言)来控制硬件,并且不需要深入了解硬件控制的实现细节,因为这些库已经将它们隐藏在后台中。需要注意的是,使用这些库的好处是简单易用,但是它们可能会带来一些性能和可定制性方面的限制。如果你是高级硬件控制的专家或需要特定的功能,你可能需要更深入地了解底层硬件控制,然后自己实现控制逻辑。

1.4 底层实现:设备树和驱动

image-20230517023046610

为了了解操作系统如何从底层控制LED,我们先需要了解 驱动设备树(Device Tree)2个概念:

  • 驱动程序:实际上是内核的一个模块,用于控制和管理硬件设备。当一个硬件设备插入计算机时,内核会根据其硬件信息来加载相应的驱动程序。驱动程序能够访问硬件设备的寄存器,从而控制设备的操作,例如读写设备状态、发送和接收数据、控制设备的电源等。其它还在操作系统与硬件之间建立了一个桥梁,使得应用程序可以和硬件设备进行交互。通过驱动程序,应用程序可以访问硬件设备。驱动程序建立了一个硬件抽象层,向应用程序提供一些统一用户接口或API,使得用户可以访问某些硬件设备的特性或操作。

  • 设备树:在kernel 3.0以及之后的版本,都是采用设备树的方法实现驱动设备之间的联系。当内核启动时,会在设备树文件中查找与当前系统中硬件设备匹配的节点,之后内核会加载相应的驱动程序来控制设备。这个过程可以通过设备树绑定(Device Tree Binding)来实现。驱动程序需要知道它所控制硬件设备的详细信息,包括设备的寄存器、中断路由、时序等信息。这些信息可以在设备树文件中定义。因此,在编写驱动程序时,需要编写相应的设备树绑定,并根据绑定的规范来编写相应的驱动程序。

    设备树文件通常是系统供应商提供的二进制文件或源代码文件,而在开发中,也会根据具体需求编写或修改。通过设备树文件,内核可以识别硬件并加载相应的设备驱动程序。

简单来说,设备树文件描述了一个系统中的硬件设备及其属性,而驱动程序则实现了针对这些硬件设备的控制和操作。他们的作用总结如下。

  • 驱动程序:提供了一系列的操作系统调用和接口,使得应用程序可以与硬件设备进行交互,方便应用程序开发。

  • 设备树:设备树以文本描述的方式表达硬件结构,与平台无关,方便硬件的移植和维护。可以为不同的硬件平台提供一致的接口,简化驱动程序的开发。

因为随身WIFI的根文件系统中没有Linux源码,所以要想看到设备树和驱动程序的源码,估计需要解包boot.img镜像。太复杂了,没有再深入探究。

1.5 霓虹灯

做点有趣的事,随身WIFI有红 绿 蓝 三个LED灯,尽管不能控制灯的亮度,但应该依旧可以组合出黄色(红+绿),洋红色(红+蓝),青色(绿+蓝),混合(绿+蓝+红)4种颜色。我们来写一个shell脚本,让LED在这些颜色中交替变化吧

for i in $(seq 1 20)
do
  echo none > /sys/class/leds/green:internet/trigger
  echo none > /sys/class/leds/blue:wifi/trigger
  echo none > /sys/class/leds/red:os/trigger

  echo 1 > /sys/class/leds/green:internet/brightness
  sleep 0.25
  echo 0 > /sys/class/leds/green:internet/brightness

  echo 1 > /sys/class/leds/blue:wifi/brightness
  sleep 0.25
  echo 0 > /sys/class/leds/blue:wifi/brightness

  echo 1 > /sys/class/leds/red:os/brightness
  sleep 0.25
  
  echo 1 > /sys/class/leds/green:internet/brightness
  sleep 0.25
  echo 0 > /sys/class/leds/red:os/brightness
  

  echo 1 > /sys/class/leds/blue:wifi/brightness
  sleep 0.25
  echo 0 > /sys/class/leds/green:internet/brightness

  echo 1 > /sys/class/leds/red:os/brightness
  sleep 0.25
  
  echo 1 > /sys/class/leds/green:internet/brightness
  sleep 0.25
  echo 0 > /sys/class/leds/green:internet/brightness
  echo 0 > /sys/class/leds/red:os/brightness
  echo 0 > /sys/class/leds/blue:wifi/brightness  
done

echo none > /sys/class/leds/green:internet/trigger
echo none > /sys/class/leds/blue:wifi/trigger
echo none > /sys/class/leds/red:os/trigger

echo 0 > /sys/class/leds/green:internet/brightness
echo 0 > /sys/class/leds/blue:wifi/brightness
echo 0 > /sys/class/leds/red:os/brightness

这个shell脚本中,我们使用 for 循环运行 20 次,每次间隔 0.25 秒钟,最终脚本会运行 35秒钟。最后,我们再次关闭所有灯的闪烁模式,并用 echo 0 控制所有灯都熄灭。这样可以保证脚本最终状态不会有任何灯闪烁。灯光闪烁的顺序是:绿–蓝–红–黄–青–洋红–混合

image-20230517190903634

猜你喜欢

转载自blog.csdn.net/weixin_41099712/article/details/130836998