编辑
2025-03-03
记录知识
0

项目中有客户需要将设备当作纯U盘来使用,已知Linux的gadget本身就支持U盘设备,这里描述一下如何将Linux系统作为U盘使用。

一:内核配置

对于usb gadget功能,需要打开内核默认设置,主要配置如下:

CONFIG_USB_F_MASS_STORAGE=y CONFIG_USB_LIBCOMPOSITE=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_MASS_STORAGE=m

将CONFIG_USB_MASS_STORAGE作为ko的原因是需要加载时传参,如果希望固化,则可以将传参写到cmdline中。

二:制作分区

对于U盘功能,则需要单独划一块分区给U盘使用,这里可以是单独的分区,也可以是一个img文件。

如果是单独的分区,则如下:

mkfs.vfat /dev/mmc0blk1p5 insmod g_mass_stroage.ko file=/dev/mmc0blk1p5 removable=1

如果需要系统内也能看到文件修改,这里增加一个fstab即可。如下

/dev/mmc0blk1p5 /data1 vfat defaults,user,rw,codepage=936,iocharset=utf8 0 0

如果是单独的文件,则如下:

dd if=/dev/zero of=/media/usb_stroage.img bs=512 count=2097152 # (1G大小) mkfs.vfat /media/usb_stroage.img

这里可以利用fstab的挂载

/media/usb_stroage.img /data1 vfat defaults,user,rw,codepage=936,iocharset=utf8 0 0

然后加载驱动

insmod g_mass_stroage.ko file=/dev/loop0 removable=1

如果不确定loop0是否为自己的img,可以指定挂载如下

losetup /dev/loop0 /media/usb_stroage.img

三: 使用

使用就非常简单了,将otg的功能的USB接上电脑,电脑会按照U盘的方式弹出一个已经格式化好的文件。此时正常使用U盘即可。

编辑
2025-03-03
记录知识
0

客户有一个4K的屏幕,放在两个显示器上面显示,现在需要将其对半分割为两个正常的显示器。这么说不好理解,转换需求可以这样理解,一个4K的显示分辨率的显示器,需要系统将其认为两个2K的显示器显示。通过前期调研,发现了两种方法实现。分别如下

一:多个Monitor

此方案是为X增加了两个monitor,然后根据窗管的识别,将其认定为两个单独的屏幕,此方法需要修改系统代码。主要如下

1.1 修改xorg

--- xorg-server-21.1.4/randr/rrmonitor.c.orig 2022-09-30 00:09:40.458561832 +0200 +++ xorg-server-21.1.4/randr/rrmonitor.c 2022-09-30 00:09:46.298529786 +0200 @@ -528,27 +528,6 @@ continue; } - /* For each output in 'info.outputs', each one is removed from all - * pre-existing Monitors. If removing the output causes the list - * of outputs for that Monitor to become empty, then that - * Monitor will be deleted as if RRDeleteMonitor were called. - */ - - for (eo = 0; eo < existing->numOutputs; eo++) { - for (o = 0; o < monitor->numOutputs; o++) { - if (monitor->outputs[o] == existing->outputs[eo]) { - memmove(existing->outputs + eo, existing->outputs + eo + 1, - (existing->numOutputs - (eo + 1)) * sizeof (RROutput)); - --existing->numOutputs; - --eo; - break; - } - } - if (existing->numOutputs == 0) { - (void) RRMonitorDelete(client, screen, existing->name); - break; - } - } if (monitor->primary) existing->primary = FALSE; }

这里屏蔽了Xorg本身将存在的output的monitor删除的代码

1.2 修改gtk3

--- src/gtk/gdk/x11/gdkscreen-x11.c.orig 2022-09-30 16:24:00.181850959 +0200 +++ src/gtk/gdk/x11/gdkscreen-x11.c 2022-09-30 21:32:47.288912422 +0200 @@ -644,21 +644,14 @@ #undef EDID_LENGTH } - monitor = find_monitor_by_output (x11_display, output); - if (monitor) - monitor->remove = FALSE; - else - { - monitor = g_object_new (GDK_TYPE_X11_MONITOR, - "display", display, - NULL); - monitor->output = output; - monitor->add = TRUE; - g_ptr_array_add (x11_display->monitors, monitor); - } + monitor = g_object_new (GDK_TYPE_X11_MONITOR, + "display", display, + NULL); + monitor->add = TRUE; + g_ptr_array_add (x11_display->monitors, monitor); gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry); - name = g_strndup (output_info->name, output_info->nameLen); + name = gdk_x11_get_xatom_name_for_display(display, rr_monitors[i].name); newgeo.x = rr_monitors[i].x / x11_screen->window_scale; newgeo.y = rr_monitors[i].y / x11_screen->window_scale; @@ -687,7 +680,6 @@ gdk_monitor_set_connector (GDK_MONITOR (monitor), name); gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), manufacturer); g_free (manufacturer); - g_free (name); if (rr_monitors[i].primary) primary_output = monitor->output;

这里找到monitor不是通过output寻找,而是直接增加monitor,这就避免了同一个显示器上不能输出两块屏幕的问题

1.3 使用xfce4

这边尝试了metacity和mutter,均没办法正常识别,但是基于gtk3的xfce是能够正常识别到两个屏幕的。

apt install -y xfce4

1.4 其他窗管

根据如上理解,我们后续要做的工作是,将例如kwin这类的窗管,在创建屏幕的过程中,不应该绑定一个output就一个monitor的方式。而是根据所有的monitor来都创建显示display

1.5 使用方法

xrandr --delmonitor VIRTUAL-LEFT xrandr --delmonitor VIRTUAL-RIGHT xrandr --setmonitor VIRTUAL-LEFT 960/0x1200/1+0+0 DSI-1 xrandr --setmonitor VIRTUAL-RIGHT 960/1x1200/1+960+0 none xrandr --listmonitors xrandr --fb 1921x1200 xrandr --fb 1920x1200

1.6 相关补丁

https://github.com/micw/xorg-split-screen-archlinux/blob/packages/gtk3/trunk/multiple_monitors_per_output.patch https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/981/diffs?commit_id=21e569ef1e87e4dfcedbdac99216e7147e2b05ff

1.7 相关博客

https://gitlab.gnome.org/GNOME/gtk/-/issues/2013#note_1280968

二:虚假的Xrandr

通过修改xrandr的api,可以实现将x划分为多个显示接口,也就是xrandr显示的是自己设置的虚假的显示器

参考仓库地址

https://github.com/phillipberndt/fakexrandr

参考测试示例

https://gist.github.com/phillipberndt/7688785#file-fake-xinerama-L50

相应论坛信息

https://unix.stackexchange.com/questions/605755/use-xrandr-to-split-display-in-two-virtual-screens

DWM窗管支持全屏补丁

https://dwm.suckless.org/patches/fakefullscreen/dwm-fakefullscreen-20210714-138b405.diff

fakeXinerama仓库

https://github.com/Xpra-org/libfakeXinerama

xrdp补丁

https://github.com/asafge/xrdp_dualmon/blob/master/fakexinerama/Xinerama.c

参考论坛

https://gitlab.gnome.org/GNOME/gtk/-/issues/2013#note_1280968

测试例子

fakexrandr-manage.py gui

三:实验结果

通过上述两种办法试验,均可以在X86上正常切换屏幕。当前在麒麟系统上的kwin不能直接使用,需要修改代码

编辑
2025-03-03
记录知识
0

bluetoothctl是bluez协议的调试工具,用于前期的蓝牙基本功能的验证和测试。本文基于bluetoothctl工具,介绍了如何使用其进行蓝牙的基本通讯

一:确保系统蓝牙正常存在并工作

1.1 确定蓝牙bluez协议正常安装,并高于5.0

root@kylin:/home/kylin# dpkg -l | grep bluez ii bluez 5.53-0kylin3k4 arm64 Bluetooth tools and daemons ii bluez-obexd 5.53-0kylin3k4 arm64 bluez obex daemon

1.2 查看蓝牙控制器是否正常启动

root@kylin:/home/kylin# hciconfig hci0: Type: Primary Bus: UART BD Address: 9C:71:D9:BC:DD:BF ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING PSCAN RX bytes:441417 acl:200 sco:0 events:10560 errors:0 TX bytes:12117 acl:184 sco:0 commands:173 errors:0

如果蓝牙状态不是 “UP RUNNING PSCAN” 则需要手动启动蓝牙

hciconfig hci0 up

1.3 确定蓝牙功能是否被rfkill block

root@kylin:/home/kylin# rfkill list 0: bt_default: Bluetooth Soft blocked: no Hard blocked: no 1: phy0: Wireless LAN Soft blocked: no Hard blocked: no 2: brcmfmac-wifi: Wireless LAN Soft blocked: no Hard blocked: no 3: hci0: Bluetooth Soft blocked: no Hard blocked: no

如果蓝牙被rfkill block,则需要通过rfkill命令unblock,否则蓝牙功能仍是被系统关闭的

rfkill unblock hci0

1.4 测试并验证低功耗蓝牙是否正常

hcitool lescan LE Scan ... 21:0E:38:14:CE:18 (unknown) 5F:5A:FC:85:1C:05 (unknown)

如果能够探测到低功耗蓝牙设备,代表蓝牙的基本功能正常

1.5 确定蓝牙正常可以ping通

root@kylin:/home/kylin# l2ping 54:09:10:38:28:97 Ping: 54:09:10:38:28:97 from 9C:71:D9:BC:DD:BF (data size 44) ... 0 bytes from 54:09:10:38:28:97 id 0 time 9.91ms 0 bytes from 54:09:10:38:28:97 id 1 time 8.55ms 0 bytes from 54:09:10:38:28:97 id 2 time 8.48ms

二:使用bluetoothctl工具

2.1 进入交互终端

root@kylin:/home/kylin# bluetoothctl Agent registered [bluetooth]#

2.2 开启扫描

[bluetooth]# scan on

等到扫到自己的蓝牙设备之后,可以关闭蓝牙扫描

[bluetooth]# scan off

2.3 查看已经扫到的设备

[bluetooth]# devices Device 54:09:10:38:28:97 iPhone

由上可以发现,设备已经搜到蓝牙名字为iPhone,MAC为 54:09:10:38:28:97 的设备

2.4 开启代理

[bluetooth]# agent on Agent is already registered [bluetooth]# default-agent Default agent request successful

2.5 信任和配对

[bluetooth]# trust 54:09:10:38:28:97 [CHG] Device 54:09:10:38:28:97 Trusted: yes Changing 54:09:10:38:28:97 trust succeeded [bluetooth]# pair 54:09:10:38:28:97 Attempting to pair with 54:09:10:38:28:97 [CHG] Device 54:09:10:38:28:97 Connected: yes Request confirmation [agent] Confirm passkey 886360 (yes/no): yes

如果之前之前配对过,就无需配对,如果仍选择配对,会报如下错误,但不影响使用

[bluetooth]# pair 54:09:10:38:28:97 Attempting to pair with 54:09:10:38:28:97 Failed to pair: org.bluez.Error.AlreadyExists

查看已经配对过的设备

[iPhone]# paired-devices Device 54:09:10:38:28:97 iPhone

2.6 连接蓝牙

[bluetooth]# connect 54:09:10:38:28:97 Attempting to connect to 54:09:10:38:28:97 [CHG] Device 54:09:10:38:28:97 Connected: yes [iPhone]#

如果蓝牙正常连接成功,会出现蓝牙名字的终端,如 [iPhone]

2.7 查看属性协议

menu gatt [Blank]# list-attributes Characteristic (Handle 0x9240) /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0014/char0015 00002222-0000-1000-8000-00805f9b34fb Unknown

2.8 选择自定义的属性

select-attribute /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0023/char0024 [iPhone:/service0014/char0015]# attribute-info Characteristic - Unknown UUID: 00002222-0000-1000-8000-00805f9b34fb Service: /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0014 Flags: read Flags: write Flags: extended-properties Flags: reliable-write

2.9 读和写

[iPhone:/service0023/char0024]# write 1 Attempting to write /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0023/char0024 [iPhone:/service0023/char0024]# read Attempting to read /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0023/char0024 [CHG] Attribute /org/bluez/hci0/dev_60_B7_4C_51_AC_D7/service0023/char0024 Value: 01 . 01 .

三 使用手机LightBlue测试蓝牙

1.下载LightBlue 2.选择Virtual Devices 3.点击+ 4.选择默认的profile,这里默认可以是blank 5.点击Blank,进去服务 6.进入默认的uuid 2222 7.修改uuid,修改描述,修改属性 8.利用bluetoothctl进行读写操作验证
编辑
2025-03-03
记录知识
0

最近在某个项目上,需要使用字符终端的显示,并且还需要显示中文。通过网络发现,Framebuffer Console支持中文的功能默认却没在linux的主分支,但是github上有人在维护这个patch。https://github.com/zhmars/cjktty-patches 。鉴于此,本文介绍一下Framebuffer Console的配置方法以及cjktty的配置步骤

一:主线的字符终端

1.1 defconfig

# # Console display driver support # CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=80 CONFIG_DUMMY_CONSOLE_ROWS=25 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y

这样就打开了内核的字符终端

对应defconfig打开CONFIG_FRAMEBUFFER_CONSOLE即可

1.2 编译内核

make bindeb-pkg -j64

这里编译出来会产生如下包,安装即可

../linux-headers-5.10.66_5.10.66-13_arm64.deb ../linux-headers-5.10.66_5.10.66_arm64.deb ../linux-image-5.10.66_5.10.66-13_arm64.deb ../linux-image-5.10.66_5.10.66_arm64.deb ../linux-image-5.10.66-dbg_5.10.66-13_arm64.deb ../linux-image-5.10.66-dbg_5.10.66_arm64.deb ../linux-libc-dev_5.10.66-13_arm64.deb ../linux-libc-dev_5.10.66_arm64.deb

如果使用rk平台默认boot编译,可使用如下编译方法

export ARCH=arm64 export CROSS_COMPILE=aarch64-none-linux-gnu- export PATH=$PATH:$YOURSDK/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/ make rockchip_linux_defconfig make rk3588-evb1-lp4-v10-linux.img -j64

编译完成将生成boot.img

1.3 使用与缺点

在正常进入系统之后,通过组合按键

Ctrl+Alt+F{1-6} 即可进入字符终端界面

但是,默认的字符界面,没办法正常的显示中文。原系统的中文的文件显示乱码。于是找到了cjktty

二:使用cjktty

2.1 查看仓库

cjktty的patch仓库地址在 https://github.com/zhmars/cjktty-patches ,通过其README.md 可以发现其已经不断支持到最新内核上了

2.2 拉取patch

因为我们的内核版本是5.10,故拉取5.10的patch

wget https://raw.githubusercontent.com/zhmars/cjktty-patches/master/v5.x/cjktty-5.10.patch

2.3 打补丁

打补丁就简单了

patch -p1 < cjktty-5.10.patch

2.4 开启配置

CONFIG_FONT_CJK_16x16=y CONFIG_FONT_CJK_32x32=y

2.5 编译及使用

编译方法同上,使用时可以发现,该作者实际就是把两个原英文字符叠加成一个中文字符,从而显示了的中文字符

编辑
2025-03-03
记录知识
0

在使用shell环境的时候,难免会遇到对文本进行操作的情况,shell提供了一些功能强大的文本操作命令,这里做了简单汇总,有助于了解和学习这些工具,提高工作中处理文本的效率

一:grep

grep是经常使用的文本查找工具,下面列举grep常用的一些命令。当然,也有比grep更好的工具ripgrep。这个可以后续探索

1.1 查找不以#开头的文本内容,并去掉空格的行

grep -vE "^#|^$" /etc/ssh/sshd_config

-v是选中不匹配的行,-E是明确使用正则 ^$ 是没有数据的行 ^#是以#开头的行

1.2 查找指定匹配字符(忽略大小写)前后5行的内容

dmesg | grep -i cfg80211 -A 5 dmesg | grep -i cfg80211 -B 5 dmesg | grep -i cfg80211 -C 5

A after 之后的5行, B before 之前的5行, C 是A+B的合计,前后5行

-i 忽略大小写

二:cut

cut是一个字符截取命令,其命令在处理一些字符串上,可以方便的对一些字符串直接截取。如果文本内容格式比较规律的话,也可以用来筛选指定分隔符下的内容

2.1 通过ifconfig找到所有的网卡设备名

ifconfig | grep -vE "^ |^$" | cut -d ' ' -f 1 | cut -d ":" -f 1

-d 是指定分隔符, -f 是指定某个域。

-d ' ' -f 1 是以单个空格为分隔符找到第一个域

cut -d ":" -f 1 是以冒号为分隔符找到第一个域

2.2 只看内核的时间戳

dmesg | cut -b -15

三:sed

sed是重要的字符替换工具,也就流编辑器,可以方便的直接替换一些文本内容,从而不用打开文本去处理,这使得在shell内对文本替换来说十分方便

-e :添加一个命令,多个sed命令可以用这个 -i :直接修改文件内容 -n :取消自动打印,只打印模式匹配的行 -E :支持扩展表达式;

3.1 替换

cat filename | sed -e“s/text/replace/g”-e“s/text/replace/g”

-e 允许运行多个命令,s///g是替换的语法, s指的搜索,g指的全局。也就是搜索全局,然后统一替换

3.2 插入

cat filename | sed -e "4a help"

在文本第4行后添加help作为新的一行

cat filename | sed -e "4i help"

在文本第4行前添加help作为新的一行

3.2 删除

cat filename | sed -e "/^$/d"

删除空格行

cat filename | sed "s/[a-z]\|[A-Z]/[&]/g"

对文本中的所有字符加上[] 。&指的是上一次搜索到的值。 | 是或,意思可以多条规则匹配

3.3 子串匹配

echo a b | sed -E -e "s/([a-z]) ([a-z])/\2 \1/"

()可以声明这是一个字串,()声明的字串,可以通过\1 \2等通配来引用。

-E 代表使用正则,如果不加-E 则使用()的时候需要转换成 () 那么匹配一个a-z的字符需要这样表示 ([a-z])

那么不加-E 的效果如下

echo a b c | sed -e "s/\([a-z]\) \([a-z]\) \(c\)/\3 \2 \1/"

四:sort

sort是重要的字符和数字排序工具,可以直接对文本进行升序和降序操作

4.1 对任意文件按照行数反序

grep -n '.' /etc/os-release | sort -t ':' -k1 -nru

-t 指定分隔符

-k 指定分隔符划分的域

-n 指定排序方式为数字(默认为字符)

-r 指定反序

4.2 以=为分隔符对文本的第一个域的第2个字符排序,并去掉重复的行

cat /etc/os-release | sort -t '=' -k 1.2 -u

-u 去掉重复的排序行

五:uniq

uniq是找重复的工具,可以快速的识别出文本中完全重复的行,并记录次数

5.1 找到文本中重复的行,忽略大小写,并打印重复次数

cat Readme.md | uniq -dci

5.2 找到文本中所有不重复的行

cat Readme.md | uniq -u

-d 是找到完全重复的行

-c 是统计重复次数

-i 是忽略大小写

-u 是打印不重复的行

六:awk

awk模式是模式扫描及处理语言,也就是说文本处理规则太多了,我定义一个语言,你们想怎么匹配就怎么匹配

NF 一条记录的字段的数目 NR 行号,当前处理的文本行的行号 FS 定义间隔符 OFS 定义输出字段分隔符,默认空格  RS 输入记录分隔符,默认换行

awk默认格式为

awk '{pattern + action}' {filenames}

这里'{}'里面就是代码域,用于编写awk代码的地方。

最简单的打印可以如下

echo | awk '{print "Hello World"}'

直接打印hello world

echo Hello World | awk '{print $1" "$2}'

打印传过来的参数

6.1 BEGIN和END宏

cat /etc/passwd | awk 'BEGIN{count=0;print "begin is:" count} {count=count+1;print count} END{print "end is:"count}'

这里统计了passwd的文件行数

awk不仅默认{}里面填写代码,也可以在BEGIN和END宏里面填写代码,BEGIN填写的代码,在{}前运行,END填写的代码在{}后运行

ll |awk 'BEGIN {byte=0;print "统计当前目录占用字节数"} {byte=byte+$5;} END{print "当前目录字节数为:",byte}'

这里统计了当前目录的字节数,不包括下级目录

6.2 if语句

cat /etc/passwd | awk '{if(NR>=10 && NR<=20) print $1}'

这里取passwd文件的第10行到20行内容

'{}'的if语句可以和C语言一样,print可以和python语言一样。

6.3 for语句

cat /etc/passwd | awk -F '' 'BEGIN{count=0} {for(i=1; i<=NF; i++) count++} END{print count}'

这里对每个字符做计数,最后打印存在的字符总数。

6.4 while语句

echo abcdefg | awk -F '' '{i=1; while(i<=length($0)) {print $i;i++}}'

这里对一行abcdefg转换成一个字母多行

6.5 分隔符

echo "1 2,3:4" | awk -F [" ",:] '{print $1$2$3$4}'

以空格,逗号,冒号作为分隔符打印第1,2,3,4个匹配的内容

echo "1 2,3:4" | awk BEGIN{'FS="[ ,:]"} {print $1$2$3$4}'

FS宏也可以代替-F参数,需要注意的是,FS参数需要在后面加上"" 双引号

七:总结

这里介绍了grep sort uniq awk sed cut一共六个命令,每个命令都可以搭配起来使用。这里简要介绍一下在哪些情况下可以用哪些命令

1.搜索一些匹配单词的时候,可以用grep,例如 grep -nr text filename 2.面临排序问题的时候,可以用sort, 例如 sort -r 3.去重复行的时候,可以用uniq, 例如 uniq -u 4.批量替换的时候,可以用sed,例如 sed -i “s/text/replace/g” 5.对特定格式字符串进行截取的时候,可以用cut ,例如 cut b 1-3 6.在对一些列的域做划分的时候,可以用awk , 例如 awk -F ‘:’ '{print $1}' 7.对文本进行高级编辑操作的时候,awk都能完成.