2022/12/28

Try coverity scan for opensource project

coverity scan有提供 opensource 專案免費使用的服務。
就是用你的 github 帳號登入後,按下上面頁面的 "find your project"。
他就會列出你所有的 github project。
你就可以選一個你的 project (為了安全起見,最好選有 opensource license 的project,為你的project 增加 LICENSE 聲明可參考github 說明)。
然後就跟隨網頁說明,一步一步做..
接著就是 submit build

build 的動作要在自己的 local 完成。
download 他提供的 build (and analysis ?)tool,build project 後,把結果upload 到 coverity 網站。
他就會產生分析結果。

2022/12/22

simple example : swagger-py-codgen, ui and flask-resetful server

就是..從朽 api.yaml 開始,然後 codegen, 寫api.py,啟動 ui and restful sever,最後用 ui 測試 server 的 api

先寫一個簡單的 myapi.yaml: (copy from pet.yaml)
openapi: 3.0.0
info:
  version: 1.0.0
  title: Hello API
  description: An API to return hello in request language

servers:
  - url: http://127.0.0.1:5000/v1
    description: local server

paths:
  /api:
    get:
      tags:
        - Hello
      description: Return hello in specified language
      parameters:
        - in: query
          name: lang
          required: true
          description: language
          schema:
            type: string
            example: es

      responses:
        '200':
          description: hello in
          content:
            text/plain:
              schema:
                type: string
                example: hoa
然後 codegen..
$swagger_py_codegen --swagger-doc myapi.yaml site --ui --spec
然後為 api get 增加動作:
diff --git a/v1/api/api.py b/v1/api/api.py
index 2efe114..50aacd3 100644
--- a/v1/api/api.py
+++ b/v1/api/api.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from __future__ import absolute_import, print_function
 
-from flask import request, g
+from flask import request, g, make_response
 
 from . import Resource
 from .. import schemas
@@ -10,6 +10,6 @@ from .. import schemas
 class Api(Resource):
 
     def get(self):
-        print(g.args)
+        print(request.args)
 
-        return None, 200, None
\ No newline at end of file
+        return make_response(request.args['lang'],200)
然後到 site/site 下啟動 resetfule and ui server:
python __init__py
開啟覽器,到 swagger-ui 位置: http://127.0.0.1:5000/static/swagger-ui/index.html
就可以用 swagger-ui,測試剛剛寫的 restfule server。


有些要注意的地方..

因為啟動的 __init__.py 有設定 :
    app.register_blueprint(
        v1.bp,
        url_prefix='/v1')
所以會在後面 v1/routes.py 中, path-handler 定義的位址加上 /v1/:
routes = [
    dict(resource=Api, urls=['/api'], endpoint='api'),
]
上面 /api 會變成 /v1/api,所以 myapi.yaml 的 servers 就要加上 /v1 ,這樣 swagger-ui 才能對正確的 url 動作。
這個github project 就是上面的說明,增加了 new user, userlist 的 api: 有比較多的 api 可以測試。

restful api and flask-restful

restful api 除了 http 的 PUT,GET,POST,DELETE 之外,有兩個地方可以"傳遞"參數給resetful server (flask)
  • url : /device/<devicde_id>/voltage/<meter_id>
  • body : 一般用 json 格式傳遞內容

其中 url 的部份, flask 用 api.add_resource(devicevoltage,'/device/<devicde_id>/voltage/<meter_id>)
產生變數 device_id, meter_id 在 devicevoltage 這個實做 http handler class 的 api入口,作為 參數:
class devicevoltage(Resource):
  def get(self,device_id,meter_id):
    ..
至於 body 的部份,在 flask-resetful 中,就會用 request 這個公用變數(? module?) 來提供:
   email    = request.get_json().get('email')
   username = request.get_json().get('username')

2022/12/20

swagger-py-codegen, modify source, build and test

因為在 api yaml 中有 date-time 型別,做 codegen 時加上 --spec (因為要 run swagger-ui),就會出現 Error:
    raise TypeError(f'Object of type {o.__class__.__name__} '
    TypeError: Object of type date is not JSON serializable
查。這邊 ,和這邊,都說是因為用 python 內建的 json package,在對 datetime 做 dump 時出現的 error。

所以自己寫一個tostring 的 class
from datetime import datetime,date

class myobjtostr(json.JSONEncoder):
    
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        
        if isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, obj)
然後在call dump 的地方改成:
      json.dumps(mydata, cls=myobjtostr)

出現Error 的地方式..
  File "/home/charles-chang/miniconda3/envs/swagger3.7/lib/python3.7/site-packages/swagger_py_codegen/command.py", line 200, in generate
    for code in generator.generate():
  File "/home/charles-chang/miniconda3/envs/swagger3.7/lib/python3.7/site-packages/swagger_py_codegen/base.py", line 47, in generate
    for code in self._process():
  File "/home/charles-chang/miniconda3/envs/swagger3.7/lib/python3.7/site-packages/swagger_py_codegen/flask.py", line 216, in _process
    yield Specification(dict(swagger=json.dumps(swagger, indent=2)))
所以是 flask.py line 216
修改:
diff --git a/swagger_py_codegen/flask.py b/swagger_py_codegen/flask.py
index 92f58c8..589bedf 100644
--- a/swagger_py_codegen/flask.py
+++ b/swagger_py_codegen/flask.py
@@ -6,6 +6,8 @@ from .base import Code, CodeGenerator
 from .jsonschema import Schema, SchemaGenerator, build_default
 import six

+from datetime import date,datetime
+
 SUPPORT_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']


@@ -116,6 +118,15 @@ def _location(swagger_location):
     }
     return location_map.get(swagger_location)

+import json
+class myobj2str(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, datetime):
+            return obj.strftime('%Y-%m-%d %H:%M:%S')
+        if isinstance(obj, date):
+            return obj.strftime('%Y-%m-%d')
+        else:
+            return json.JSONEncoder.default(self.obj)

 class FlaskGenerator(CodeGenerator):
     dependencies = [SchemaGenerator]
@@ -213,7 +224,7 @@ class FlaskGenerator(CodeGenerator):
             swagger.update(self.swagger.origin_data)
             swagger.pop('host', None)
             swagger.pop('schemes', None)
-            yield Specification(dict(swagger=json.dumps(swagger, indent=2)))
+            yield Specification(dict(swagger=json.dumps(swagger, indent=2,cls=myobj2str)))

         yield Validator()

修改完後,follow 這一篇,用source code 中寫好的 setup.py 來 test build and run.
其中 developement mode:
$ python setup.py develop
這樣就可以run swagger_py_codegen,而且是 run 在 swagger-py-codegen 里的 code。
所以如果有錯,直接修改就可以。
不用再 install (run setup.py)

這樣改完的確不會再發生 error

改完的code:
另外,不知什麼原因,有的python 環境有simplejson 的會出現 error : module simplejson has no dump()。
所以要修改:
diff --git a/swagger_py_codegen/flask.py b/swagger_py_codegen/flask.py
index 403df02..8c51936 100644
--- a/swagger_py_codegen/flask.py
+++ b/swagger_py_codegen/flask.py
@@ -216,10 +216,7 @@ class FlaskGenerator(CodeGenerator):
         for view in views:
             yield View(view, dist_env=dict(view=view['endpoint']))
         if self.with_spec:
-            try:
-                import simplejson as json
-            except ImportError:
-                import json
+            import json
             swagger = {}
             swagger.update(self.swagger.origin_data)
             swagger.pop('host', None)
不要用 simplejson。

2022/12/16

step by step. mender yocto kirkstone

export BRANCH="kirkstone"
mkdir mender-kirkstone && cd mender-kirkstone
repo init -u https://github.com/mendersoftware/meta-mender-community \
           -m meta-mender-raspberrypi/scripts/manifest-raspberrypi.xml \
           -b ${BRANCH}
repo sync
然後...
$ source setup-environment raspberrypi
You had no conf/local.conf file. This configuration file has therefore been
created for you from /home/charles-chang/mender-kirkstone/sources/poky/meta-poky/conf/local.conf.sample
You may wish to edit it to, for example, select a different MACHINE (target
hardware). See conf/local.conf for more information as common configuration
options are commented.

You had no conf/bblayers.conf file. This configuration file has therefore been
created for you from /home/charles-chang/mender-kirkstone/sources/poky/meta-poky/conf/bblayers.conf.sample
To add additional metadata layers into your configuration please add entries
to conf/bblayers.conf.

The Yocto Project has extensive documentation about OE including a reference
manual which can be found at:
    https://docs.yoctoproject.org

For more information about OpenEmbedded see the website:
    https://www.openembedded.org/


### Shell environment set up for builds. ###

You can now run 'bitbake <target>'

Common targets are:
    core-image-minimal
    core-image-full-cmdline
    core-image-sato
    core-image-weston
    meta-toolchain
    meta-ide-support

You can also run generated qemu images with a command like 'runqemu qemux86'

Other commonly useful commands are:
 - 'devtool' and 'recipetool' handle common recipe tasks
 - 'bitbake-layers' handles common layer tasks
 - 'oe-pkgdata-util' handles common target package tasks
kirkstone 的 target 比較多...
然後就是
bitbake core-image-full-cmdline
build OK. dd boot,果然有 ssh server.

2022/12/13

mender-yocto build test.

  • 必須要enable mender-client 的 dbus 功能。
  • 數於 add-on
  • mender-connect 有 opensource,有 build from source 的說明
這一篇有 mender 的 yocto for rpi3 的 build instruction。
build 完,dd 發現沒有 enable ssh server。
參考這一篇,選 target : core-image-full-cmdline 就會包含 ssh server。
或是修改 build/conf/local.conf ,用 EXTRA_IMAGE_FEATURES 變數加上 ssh-server-openssh

其實..依照說明O:
export BRANCH="dunfell"
source setup-environment raspberrypi
之後,就會進入 build 目錄,然後顯示:
You can now run 'bitbake <target>'

Common targets are:
    core-image-minimal
    core-image-sato
    meta-toolchain
    meta-ide-support

其中 core-image-sato 就是有dropbear (小型 ssh server) 的 config。

core-image-sato 的話,出現 Error:
ERROR: File system image of partition None is larger (417792 kB) than its allowed size 204800 kB
sato 好像包含x11, 太大了。
在 build/conf/local.conf 中,comments 有:
 Mender storage configuration
#
# More details on these variables is available at
#    https://docs.mender.io/devices/yocto-project/partition-configuration#configuring-storage
#
# Also, please be sure to check other config files as other
# layers, config fragments, etc may attempt to set values
# for specific platforms.  Using "bitbake -e "
# can help determine which files are setting these values
# in a given configuration.
#
# MENDER_STORAGE_TOTAL_SIZE_MB = "2048"
# MENDER_BOOT_PART_SIZE_MB = "16"
# MENDER_DATA_PART_SIZE_MB = "1024"
# MENDER_STORAGE_DEVICE = "/dev/mmcblk0"
# MENDER_BOOT_PART = "${MENDER_STORAGE_DEVICE_BASE}1"
# MENDER_DATA_PART = "${MENDER_STORAGE_DEVICE_BASE}4"
# MENDER_ROOTFS_PART_A = "${MENDER_STORAGE_DEVICE_BASE}2"
# MENDER_ROOTFS_PART_B = "${MENDER_STORAGE_DEVICE_BASE}3"
可能可以用來改 partition 大小。
加入 MENDER_STORAGE_TOTAL_SIZE_MB = "4096" 後,好像就 build OK 了。

這個 target run 起來沒有 uart console。所以還是不能用。
最後是用 core-image-full-cmdline
run 起來後有 ssh
但是 mender authorize 還是有問題。

ref: 說明 meta-mender layer
下面的各個 layer:

meta-mender-core:
  • build command
  • image partition
  • bootloader

meta-mender-community: 一堆板子相關的設定

meta-mender-demo 跟 demo 板有關。
build for production有說明如何build profuction image (不是跟 demo server 連線?)

要先remove meta-mender-demo layer。
要準備好 cert.ca,如果server 是 self signed,那還要有 server 的 ca.


對應的 mender server,不要做demo mode,做 production mode。參考installation with docker compose

依照3.4.0 板來做,最後 ./run up -d 之後,user-admin 這個container 一直 fail, restart。
用 docker log 看,是 key 的 permission。
發現是依照keygen 的 production/key-generated/keys/useradm/private.key 和 deviceauth/private.key 的 attrib 沒有 rw,都改 777 後再啟動就 OK 了。

另外,browser 要對 domain name,不能對 ip 作用。

結果 server.crt 還是沒 build 進去,因為缺了 meder-server-certifaction 這個 layer.
查,dunfell 這個branch 還沒有這個 layer..

yocto 的 branch name : Release

所以dunfell 後的LTS 是 Kirkstone
嘗試用這格 branch 試試..

一樣先follow 這個,只是 BRANCH=kirkstone。
作完setup-environment 後,在 build 下,依照這篇 修改 local.conf
certification 那邊,就抄local.conf 的, copy 過來,果然是新版bitbake 的語法。

這個..參考yocto: fetching from local directory:
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
是真的 project folder 下有一個 files 目錄。
然後..下面這個file..
SRC_URI += " file://app.tgz"
是說,找local file,不是到網路上的link..

2022/12/12

bookmark : 68xx area scanner

mmwav industrial toolbox , area scanner
這個 labs example 可以偵測固定跟移動的物件。
也就是說,靜止不動的物件不會被 clutter removal 當作背景移除。
另外,他的TLV 輸出也有分為 polar 跟 cartesian 座標系。

2022/12/11

chatGPT 寫的 cfar 的 code

# 定義 CFAR 演算法
def cfar(signal, reference_region_size, guard_region_size, threshold):
  # 創建空的列表,用於存儲檢測結果
  detections = []
  
  # 從信號的第一個元素開始遍歷整個信號
  for i in range(len(signal)):
    # 將當前檢測到的信號元素與前面和後面的信號元素組成一個參考區域
    reference_region = signal[max(0, i - reference_region_size):i + reference_region_size + 1]
    
    # 在參考區域的前面和後面各添加一個保護區域,用於消除边界效應
    guard_region = signal[max(0, i - reference_region_size - guard_region_size):max(0, i - reference_region_size)]
    guard_region += signal[min(len(signal) - 1, i + reference_region_size + guard_region_size + 1):min(len(signal) - 1, i + reference_region_size + 1)]
    
    # 在參考區域中找到最大值,並將最大值減去保護區域中的平均值,以獲得阈值
    reference_max = max(reference_region)
    reference_threshold = reference_max - sum(guard_region) / len(guard_region)
    
    # 如果當前檢測到的信號大於阈值,則將該信號加入檢測結果中
    if signal[i] > reference_threshold * threshold:
      detections.append(signal[i])
      
  return detections
  
# 測試 CFAR 演算法
signal = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
detections = cfar(signal, reference_region_size=2, guard_region_size=1, threshold=1.5)
print(detections)  # 輸出
有 guard.

2022/12/1

Ti mmwave : developement with EVB.

大概是要先從Out of Box Demo User Guide開始。
然後其中 Build 完,Exceute the Lab 有兩個 Mode:Deloyment, Debug
Debug 就是 CCS Debug Mode.
然後就 Link 到:using ccs debug 這個說明。

Ti mmwave EVM 用 debug mode 時,EVM 要燒一個 stub program,在 sdk 中有提供: ccsdebug
這個 stub program 啟動後就是一個 for loop,等待把 program load 到 ram 里 run
--- 所以不是真的的 JTAG debug (?)

所以build 完 project,不管要不要用 debug mode 來 run,都要先燒錄(bin 或 ccsdebug 的差別而已)。
EVM 要切換 flash Mode,燒完後切回 function mode。
每個板子的切換方式寫在: evm setup operational mode

CCS Debug Mode 要用到 ICE,就是 XDS110,這個在 AWR8642AOP EVM 上沒有(因為板子很小),需要接上 MMWAVEICEBOOST 板才行。
就是EVM Setup Operatiional Mode的 "AOP With mmWaveICBoost Attached"

CCS 的 JTAG debug mode 是在 "View -- Target Configurations" 中設置的,不是跟著 project。
自己要為要接的 EVM new 一個 configuration (*.ccxml),他沒有內建好的。
New Configurtation,給名子。選 XDS110 USB Debug Probe connection。
勾選 AWR6843AOP,
Save 後就可以選 Test Connection..下面就是AWR6843AOP + ICEBoost board 的 log..
[Start: Texas Instruments XDS110 USB Debug Probe_0]

Execute the command:

%ccs_base%/common/uscif/dbgjtag -f %boarddatafile% -rv -o -S integrity

[Result]


-----[Print the board config pathname(s)]------------------------------------

C:\Users\CHARLE~1.CHA\AppData\Local\TEXASI~1\
    CCS\ccs1210\0\0\BrdDat\testBoard.dat

-----[Print the reset-command software log-file]-----------------------------

This utility has selected a 100/110/510 class product.
This utility will load the adapter 'jioxds110.dll'.
The library build date was 'Sep 20 2022'.
The library build time was '12:28:44'.
The library package version is '9.9.0.00040'.
The library component version is '35.35.0.0'.
The controller does not use a programmable FPGA.
The controller has a version number of '5' (0x00000005).
The controller has an insertion length of '0' (0x00000000).
This utility will attempt to reset the controller.
This utility has successfully reset the controller.

-----[Print the reset-command hardware log-file]-----------------------------

The scan-path will be reset by toggling the JTAG TRST signal.
The controller is the XDS110 with USB interface.
The link from controller to target is direct (without cable).
The software is configured for XDS110 features.
The controller cannot monitor the value on the EMU[0] pin.
The controller cannot monitor the value on the EMU[1] pin.
The controller cannot control the timing on output pins.
The controller cannot control the timing on input pins.
The scan-path link-delay has been set to exactly '0' (0x0000).

-----[Perform the Integrity scan-test on the JTAG IR]------------------------

This test will use blocks of 64 32-bit words.
This test will be applied just once.

Do a test using 0xFFFFFFFF.
Scan tests: 1, skipped: 0, failed: 0
Do a test using 0x00000000.
Scan tests: 2, skipped: 0, failed: 0
Do a test using 0xFE03E0E2.
Scan tests: 3, skipped: 0, failed: 0
Do a test using 0x01FC1F1D.
Scan tests: 4, skipped: 0, failed: 0
Do a test using 0x5533CCAA.
Scan tests: 5, skipped: 0, failed: 0
Do a test using 0xAACC3355.
Scan tests: 6, skipped: 0, failed: 0
All of the values were scanned correctly.

The JTAG IR Integrity scan-test has succeeded.

-----[Perform the Integrity scan-test on the JTAG DR]------------------------

This test will use blocks of 64 32-bit words.
This test will be applied just once.

Do a test using 0xFFFFFFFF.
Scan tests: 1, skipped: 0, failed: 0
Do a test using 0x00000000.
Scan tests: 2, skipped: 0, failed: 0
Do a test using 0xFE03E0E2.
Scan tests: 3, skipped: 0, failed: 0
Do a test using 0x01FC1F1D.
Scan tests: 4, skipped: 0, failed: 0
Do a test using 0x5533CCAA.
Scan tests: 5, skipped: 0, failed: 0
Do a test using 0xAACC3355.
Scan tests: 6, skipped: 0, failed: 0
All of the values were scanned correctly.

The JTAG DR Integrity scan-test has succeeded.

[End: Texas Instruments XDS110 USB Debug Probe_0]
test Connection OK,就可以 "Launch Configuration",然後就會出現 Debug View。裡面出現 ICE chain 上的 device : XDS110/Cortex_R4, XDS110/C674X
在要用到的 device 上一一做 "connect" 後,ICE 就ready 了。

Load to Run 的動作不是自動的,不是你開了那一個 project,按下 Run - Load 之後就會 Load 那個 program。
Run -- Load 後,會開啟 file/projecrt explorer 要你找要 load 的 xer4f 檔。

2022/11/17

antenna geometry . xWR6843AOP

SDK 和 example/labs 中,有用來描述 TX/RX 相對位置的資料。
xWR6843AOP 的 TX/RX 排列是
    R4R2
    R3R1
T1  

T3  T2
一格是1/2波長。
所以在sdk : antenna_geometry.c 中...
以tx, rx左上角為0.0。右,下為正。單位是 1/2 波長...
ANTDEF_AntGeometry gAntDef_IWR6843AOP = {
     .txAnt = {
                {0, 0},
                {2, 2},
                {0, 2}
       },
     .rxAnt = {
                {1, 1},
                {1, 0},
                {0, 1},
                {0, 0}
              }
};
而在 labs source 中,用 antGeometry0.1 來描述 tx,rx 的排列。
但是是用 virtial antenna 的方式..
因為 T1.T2.T3的排列方式。RX 可以視為:
R04 R02
R03 R01
R12 R10 R08 R06
R11 R09 R07 R05
定義:
  • antGeometry0: azimuth offset of all available virtual antennas
  • antGeimetry1: elevation offset of all available virtual antennas
然後以左上為原點,左上為正
antGeometry0 -1 -1  0 0 -3 -3 -2 -2 -1 -1  0  0
antGeometry1 -1  0 -1 0 -3 -2 -3 -2 -3 -2 -3 -2
:::

2022/11/14

bookmark : progress , check cp. progress

作者說明怎嘛做:
It simply scans /proc for interesting commands, 
and then looks at directories fd and fdinfo to find opened files and seek positions, and reports status for the largest file.

It's very light, and compatible with virtually any command.
apt install 就有了...

2022/11/10

Code Composer 12.1.0 in Linux, build project.

CCS 安裝就 download linux 版 tar.gz,解開後 執行 *.run 這個 script。
就會安裝。

裝完,點 icon 啟動,到 reosurce explorer。
到 automotive toolbox 右邊 ':', Install
會裝 SDK..
之後會重開。
然後就可以選需要的 example project 的 import to IDE.

build IDE 的化,會 fail,因為一堆 sdk/packages/scripts/ImageCreator/ 下的 tool 都是用 exe 呼叫。
到 project -- properties --- build -- steps -- post-build-step 去看,都是用 exe。
然後到 ImageCreator 去看,除了 out2rprc 只有 exe 之外,其他都有兩個檔,一個沒有 .ext 是給 linux 用。有 exe 給 windows 用。
out2rprc 用 file 看是 .NET,所以依照說明 apt install mono-runtime 之後,就可以 run 了。
所以修改剛剛 post-build-step 的每個,除了 out2rprc.exe 之外,其他的 .exe 附檔名都刪掉。
這樣就 build OK 了。

mmwave sdk , algorithm 與 主程式的關聯

mmwave sdk 的 example (labs sample) 的 source code,trace 主程式不太容易看到 對 chirp/frame 處理的code。
里如怎麼決定 algorithm, 哪裡會去執行 fft, aoa , cfar 的 code..

trace overhead_mount_occupy 這個 example 中,object detection hardware 的 code,找到 DPC_ObjectDetection_execute 這個 function。
就是做 處理的地方,然後它被放在DPM_ProcChainCfg 這個 structure 里。

從這個 structure 來找...應該是 interface 吧...
sdk/packages/ti/control/dpm/dpm.h
typedef struct DPM_ProcChainCfg_t
{
    DPM_ProcChainInitFxn                      initFxn;
    DPM_ProcChainStartFxn                     startFxn;
    DPM_ProcChainExecuteFxn                   executeFxn;
    DPM_ProcChainIoctlFxn                     ioctlFxn;
    DPM_ProcChainStopFxn                      stopFxn;
    DPM_ProcChainDeinitFxn                    deinitFxn;
    DPM_ProcChainInjectDataFxn                injectDataFxn;
    DPM_ProcChainChirpAvailableCallbackFxn    chirpAvailableFxn;
    DPM_ProcChainFrameStartCallbackFxn        frameStartFxn;
}DPM_ProcChainCfg;
這個 interface 是給誰用的?
從 member executeFxn 來找找看,他是被 DPM_execute( ) 呼叫:
int32_t DPM_execute (DPM_Handle handle, DPM_Buffer* ptrResult)
    ...
    ptrDPM = (DPM_MCB*)handle;
    ...
    retVal = ptrDPM->procChainCfg.executeFxn (ptrDPM->dpcHandle, ptrResult);
所以呼叫 DPM_execute 時,準備好的參數: handle. 就包含了將要 run 的 function (algorithm)


拿 overhead_mount_occupancy 的 mss 來看。這個 structure 在哪裡宣告。

在 project source 的 src/common/dpc/objdetrangehwa/src/objdetrangehwa.c 中,先把這個 functiontable(interface): gDPC_ObjDetRangeHWACfg 的內容 implement好,把表填好
DPM_ProcChainCfg gDPC_ObjDetRangeHWACfg =
{
    DPC_ObjectDetection_init,            /* Initialization Function:         */
    DPC_ObjectDetection_start,           /* Start Function:                  */
    DPC_ObjectDetection_execute,         /* Execute Function:                */
    DPC_ObjectDetection_ioctl,           /* Configuration Function:          */
    DPC_ObjectDetection_stop,            /* Stop Function:                   */
    DPC_ObjectDetection_deinit,          /* Deinitialization Function:       */
    NULL,                                /* Inject Data Function:            */
    NULL,                                /* Chirp Available Function:        */
    DPC_ObjectDetection_frameStart       /* Frame Start Function:            */
};
在 mss_main.c 的 initTask( ) 時,放在要給 DPM 的 parameter, handle structure 中,
然後呼叫 DPM_init( ) 初始化,並且把這個 structure 放到 objDetDpmHandle 中:
    dpmInitCfg.ptrProcChainCfg  = &gDPC_ObjDetRangeHWACfg;
    ...
    gMmwMssMCB.objDetDpmHandle = DPM_init (&dpmInitCfg, &errCode);
然後在後來 create 的 Task : mssDPMTask( ) 中,呼叫 DPM_execute 時,傳入這個structure 做 parameter.
static void mmwDemo_mssDPMTask(UArg arg0, UArg arg1)
{
    ...
    while (1)
    {
       ...
       errCode = DPM_execute (gMmwMssMCB.objDetDpmHandle, &result);

2022/11/8

bookmark : bartlett vs Capon beamforming,

Bartlett Beamformer and MVDR Beamformer in the Browser

用 javascript 做出兩個 algorithm,然後讓你調整參數看二者的不同。
可以看出 Capon 容許較大 noise (調整 SNR 來看),有比較大的鑑別度。

有關這兩個 beamforming 的方法,這一篇 : "Beamforming algorithms - beamformers" -- Norsonic tech notes, by Jørgen Grythe, Norsonic AS, Oslo, Norway 有白話的說明。

2022/11/2

SonarQube , install and test

用 Docker 安裝。
官方是用 docker-compose.: example-compose-files

要run 的主機,要先把 file limit 相關增加
sudo sysctl -w vm.max_map_count=262144
sudo sysctl -w fs.file-max=65536
ulimit -n 65536
ulimit -u 4096
這樣做,reboot 後又要重新設定,可以修改 /etc/sysctl.conf 和 /etc/security/limits.conf

然後就可以在 docker-compose.yml 目錄下: docker-compose up -d
之後一些message 結束後,可以用 docker ps 看是不是有兩個 container 在 run:
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                                       NAMES
39b76878cb7f   sonarqube:community   "/opt/sonarqube/bin/…"   39 minutes ago   Up 39 minutes   0.0.0.0:9000->9000/tcp, :::9000->9000/tcp   compose-sonarqube-1
bd6b6e8ef34b   postgres              "docker-entrypoint.s…"   39 minutes ago   Up 39 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   compose-db-1
如果有沒起來的,用 docker ps -a 看,然後用 docker start container-id -a 看啟動 log,找找看 Error message。
啟動完成,開啟 browser,到 http://host-name:9000 就會顯示 login 畫面,default 是 admin, admin,登入完成會立刻要求修改 passowrd (+123)

follow instruction,先 create 一個 new project,用 local,然後就會產生一個 key。之後就會指示要你download 一個 zip,做 scan 用。
依照你要 run scan 的平台(windows, linux, mac), download 不一樣的 zip 檔。

zip 解開後,在 sonar-scanner-4.7.0.2747-linux/bin/ 下就是 sonar-scanner 執行檔。
在 ~/bin/ 下建一個link,讓自己可以 invoke 到。
如果要給所有人都可以 run, 就要 copy 到 /usr/opt/ ,然後建 link 到 /bin/

回到 server,gen 完 token 後,第二步要你download zip,後面就是 sonar-scanner 的 example command。
用 sonarqube 的 example 來測試:
https://github.com/SonarSource/sonar-scanning-examples.git
cd sonar-scanning-examples/sonarqube-scanner
copy剛剛step 2 的 command 來 run
sonar-scanner   -Dsonar.projectKey=test1   -Dsonar.sources=.   -Dsonar.host.url=http://i9rtx3090:9000   -Dsonar.login=sqp_87a27fdf903c31857f1349b47bee1aa31706e427
執行完,server 網頁就變了...
把節結果顯示出來..

可以看看 example 中的 sonar-project.properties 和剛剛 command 的 -D overwrite 裡面的定義。


麻煩的是,如果要 scan c++,sonar 須要知道code是怎麼 build 的,所以跟 build system 有關 (bazel, msbuild.. etc)
需要另一個tool: build-wrapper
然後 server 好像要是 developer editiion 以上,community edition 不支援的樣子..

這一篇 有說,好像有 opensource implement C++ extension

2022/10/20

Stable-Diffusion-Webui

Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.
所以
python webui.py --listen
結果是看這一個
要 clont source,還要另外 download model.ckpt。

然後啟動 webui.py

最近的吃面輸出..我的是..


這一篇有一些 animate model,一開始還有用 command line download magnet 的 package 安裝
這個是一個給 linux 用的 install script,預先用conda create 好python3 的環境。
然後這一篇 是官方的安裝說明?
還有說要一些其他的 package ,例如
Linux 安裝大概就是:

安裝 python 3.10 環境 (conda ?)
git clone git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui
copy ckpt 到 models/Stable-diffusion 下,rename model.ckpt
run webui.sh
它會create venv,再裡面安裝 requirments.txt
所以要單獨run webui.py 的話,要自己install requirement.txt
然後還是有一些沒裝, clip, gdown,
看 webui.sh,啟動 venv 後就 run launch.py
launch.py 安裝 gfpgan, clip, xformers, deepdanbooru, pyngrok
再 install requirements.txt

2022/10/13

set default gw metrics for multiple NIC

因為有兩張網卡,都是m dhcp,所以最後會有兩個 metric 都是 100 的 default gw。
因為這兩個網卡網段不一樣。所以連線就會 fail。
要在 netplan 設定 route metrics。依照說明是用:
  enp3s0:
    dhcp4: true
    dhcp4-overrides:
      route-metric: 200
大概是這樣,把 metric 設為 大於 100,就不會優先用他。
但是修改完用 netplan try,出現 Error: Error while loading /etc/netplan/50-cloud-init.yaml
所以只好用另一個方法:
cp /run/systemd/network/10-netplan-enp4s0.network /etc/systemd/network/
然後修改 /etc/systemd/network/10-netplan-enp4s0.network:
[DHCP]
RouteMetric=200
..

scp指定 NIC

要單獨取的某 interface 的 ip (v4)
ip -4 addr show enp3s0 | awk '/inet/ {print $2}' | cut -d/ -f1

要指定 scp 使用哪個 interface,就要...
scp -o BindAddress=192.168.145.58 myfile remotehost:~/
如果要在 ip addr 的輸出中篩出來,就要先用 grep 過濾,
grep -A 2 enp3s0: ip-addr-out-file
-A 2 就是show 後面兩行。

2022/10/12

cross compile mener (mender-client) for aarch64

其實就是照 官方文件 說的..
  • cross build openssl
  • cross build xz
  • cross build mender (client)
原先想用target board 上 buildroot build 好的 openssl 跟 xz,結果在 make 的時候,說找不到 libz.so
即使有把 libz.so 也放到 -L libpath,結果也一樣。
應該是沒有加上 -lz

所以只好依照官方文件,corss build openssl,這樣就會 disable zlib support,就不會需要 libz。
最後是偷懶把 openssl, xz 的 include/* copy 到 mylib/include,把 lib/* copy 到 mylib/lib

先加入 cross-compile toolpath
在宣告 cross compile tool:
export CC=aarch64-linux-gnu-gcc
然後 make
make CGO_CFLAGS="-I/home/charles-chang/mylib/include" CGO_LDFLAGS="-L/home/charles-chang/mylib/lib" CGO_ENABLE=1 GOOS=linux GOARCH=arm64 TAGS=nodbus
如果要 dbus 的話,還要 cross compile glib

其他這注意事項:
用 go 1.10 版失敗,先是說 main.go app 找不到,他一定要在 $GOPATH/src/github.com/mendersoftware,
但是照著 set GOPATH,clone ,error 變成語法錯誤。
最後還是改用 go 1.13 直接就成功了。

就 apt install golang-1.13,然後手動改 /usr/bin/go link 到 ../lib/go-1.13.0/bin/go

2022/10/11

cross-compile openssl for linux-aarch64

Configure 有:
   CROSS_COMPILE => env('CROSS_COMPILE'),
所以猜..

用 linaro 的話,安裝在 /usr/local/linaro-aarch64-2020.09-gcc10.2-linux5.4/bin/
toolchain prefix 是 aarch64-linux-gnu

Configure 中也有:
--cross-compile-prefix=
結果用了這個configure:
./Configure linux-aarch64 --cross-compile-prefix=aarch64-linux-gnu- --shared --prefix=/home/charles/myssl
竟然就 build OK ?!
打開 configure 出來的 Makefile 看...
OPTIONS=--cross-compile-prefix=aarch64-linux-gnu- enable-shared --prefix=/home/charles-chang/myssl no-afalgeng no-asan no-buildtest-c++ 
 no-crypto-mdebug no-crypto-mdebug-backtrace no-devcryptoeng no-ec_nistp_64_gcc_128 no-egd no-external-tests no-fuzz-afl no-fuzz-libfuzzer
 no-heartbeats no-md2 no-msan no-rc5 no-sctp no-ssl-trace no-ssl3 no-ssl3-method no-ubsan no-unit-test no-weak-ssl-ciphers no-zlib
 no-zlib-dynamic
原來所有 support lib option 都 off 了。


附帶 liblzma (xz) 的 cross-compile:
看 configure..
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
其他就沒了,所以猜是
./configure --host=aarch64-linux-gnu --prefix=/home/charles-chang/myxz
果然這樣make 就 OK 了。

其他看 configure 可以知道,要 build static libary 的話,就 --enable-static (--enable-shared 是 default 就有的)

2022/9/29

Compile.h Error on building kernel w clang

./include/generated/compile.h:7:24: warning: missing terminating '"' character [-Winvalid-pp-token]
#define LINUX_COMPILER "Android (7284624, based on r416183b) clang version 12.0.5 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee)
                       ^
./include/generated/compile.h:8:1: error: unknown type name 'Found'
去看 error source,是在 kernel source 里:
kernel-4.19/include/generated/compile.h
在產生 compile.h 的時候...
#define LINUX_COMPILER "Android (7284624, based on r416183b) clang version 12.0.5 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee)
Found CUDA installation: /usr/local/cuda, version 11.0, LLD 12.0.5 (/buildbot/src/android/llvm-toolchain/out/llvm-project/lld c935d99d7cf2016289302412d708641d52d2f7ee)"
define 不支援斷行...

init/Makefile:
   $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@   \
    "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)"    \
    "$(CC) $(KBUILD_CFLAGS)" "$(LD)"
然後 mkcompile_h 中:
TARGET=$1
ARCH=$2
SMP=$3
PREEMPT=$4
CC=$5
LD=$6

..

( echo /\* This file is auto generated, version $VERSION \*/
  if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi

  echo \#define UTS_MACHINE \"$ARCH\"

  echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"

  echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\"
  echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\"

  CC_VERSION=$($CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//')
  LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
              | sed 's/[[:space:]]*$//')
  printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION"
) > .tmpcompile
這個script 在 kernel 5.X 之後由 Kconfig 取代了。

測試一下 CC_VERSION 的產生: $CC -v
Android 這邊是用 prebuild 內的 clang。
執行結果:
prebuilts/clang/host/linux-x86/clang-3289846$ bin/clang -v
Android clang version 3.8.275480  (based on LLVM 3.8.275480)
Target: x86_64-unknown-linux
Thread model: posix
InstalledDir: /home/charles-chang/Android12/prebuilts/clang/host/linux-x86/clang-3289846/bin
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64
Found CUDA installation: /usr/local/cuda, version unknown
果然出現 CUDA,因為也有 version 字樣,所以有出現在後面的 grep 結果。

所以把 grep ' version ' 改 'clang version ' 試試...
好像 OK, compile.h 有問題的部份變成...
#define LINUX_COMPILER "Android (7284624, based on r416183b) clang version 12.0.5 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee), LLD 12.0.5 (/buildbot/src/android/llvm-toolchain/out/llvm-project/lld c935d99d7cf2016289302412d708641d52d2f7ee)"
--- 但是要是不是用 clang 就會 fail 吧...
改只取line 1 好了...
kernel-4.19$ git diff
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 19de4cdef1ec..b1e1d7540b9c 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -73,7 +73,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
   echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\"
   echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\"
 
-  CC_VERSION=$($CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//')
+  CC_VERSION=$($CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//' | head -n 1)
   LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
                      | sed 's/[[:space:]]*$//')
   printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION"

intel I219 NIC, ubuntu 20.04

這個 PCI NIC 要到 22.04 才有support,所以這版只能自己 build。
intel 官網有 source code,但是是手動,所以要是kernel 更新,就要手動 build 一次。
所以依照網路說,用dkms support 版
依照說明,copy source 到 /usr/src 後,用 dkms command 做
cp -r e1000e-dkms/usr/src/e1000e-3.8.7 /usr/src/
dkms add -m e1000e -v 3.8.7
dkms build -m e1000e -v 3.8.7
dkms install -m e1000e -v 3.8.7
這樣build 完,手動 modprobe e1000e,就可以用 dhcpclient 取得 IP

但是,開機後不會自動 load..
所以參考這一篇,新增:
$cat /etc/modoprobe.d/e1000e.conf
e1000e
這樣開機就會自動 load 了,
剩下不會自動取得 IP,所以參考這一篇,修改 /etc/netplan/00-instale-config.yaml
network:
 ethernets:
   eno1:
     dhcp4: true
   version: 2
這樣就 OK 了。


另外,這一篇 說明從 intel source code 改成 dkms 的方法。

2022/9/27

Dockerfile : FROM scratch

就是一個空的,什麼都沒有的 base image。
所以如果要用來 run 自己的 program,一定要是 static linked。
最好的說明就是docker 的hello-world image。
clone 下來以後,到 amd64/hello-world 看,就是做出 hello-world image 的 程式(hello) 和 Dockerfile。
用 file 來看 hello ,就是 statically linked, executable program

Dockerfile 就很簡單:
FROM scratch
COPY hello /
CMD ["/hello"]
然後 build image:
docker build -t myhello . --no-cache
run image:
docker run myhello

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
這個 image 很小,就跟 hello 一樣大:
docker images
EPOSITORY                              TAG                            IMAGE ID       CREATED          SIZE
myhello                                 latest                         03cc4ebe3142   48 seconds ago   13.3kB

ls -l hello 
-rwxrwxr-x 1 charles-chang charles-chang 13256 Sep 27 15:55 hello


另一個,簡單,用 go 做 example。一樣的 hello :building minimal docker image for go application

main.go:
package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println("Hello World!")
		time.Sleep(1 * time.Second)
	}
}
build for static:
$CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main
然後Dockerfile 一樣:
FROM scratch
ADD main /
CMD ["/main"]
然後就跟上面一樣,build image, run ....


以前好像寫過,go cross build 好方便,上面那個 GOARCH=arm64 就是 build for aarch64

2022/9/13

create, mount veracrypt sd partition in device.

在 pi 上 build 好 static linked veracrypt 後,放到 target board 上 ,先測試 mount 已經 create 好的 partition:
# /data/veracrypt /dev/mmcblk1p1 /sd
Enter password for /dev/mmcblk1p1: 
Enter PIM for /dev/mmcblk1p1: 
Enter keyfile [none]: 
Protect hidden volume (if any)? (y=Yes/n=No) [No]: 
Error: No such file or directory:
dmsetup

VeraCrypt::Process::Execute:88
意思是需要 dmsetup 這個 tool。是 device-mapper tool

另外,這個 Error:
Error: /dev/mapper/control: open failed: No such device
Failure to communicate with kernel device-mapper driver.
Check that device-mapper is available in the kernel.
Incompatible libdevmapper 1.02.167 (2019-11-30) and kernel driver (unknown version).
Command failed.
是 kernel 沒有 DEVICE-MAPPER support
Device Driver -- Multiple device driver support(RAID and LVM) -- Device mapper support -- Crypt target support
mount OK. 做 dd test:
# dd if=/dev/zero of=./100M bs=1000000 count=100
100+0 records in
100+0 records out
100000000 bytes (95.4MB) copied, 19.239889 seconds, 5.0MB/s
和沒有用 veracrypt 的 sd card 比較:
# dd if=/dev/zero of=./100M bs=1000000 count=100
100+0 records in
100+0 records out
100000000 bytes (95.4MB) copied, 18.150534 seconds, 5.3MB/s
至於 cpu useage,用 uptime 來看,沒有差別。


Create encrypted partition
ref: command:
# /data/veracrypt -t -c --volume-type=normal /dev/mmcblk1p1 --encryption=aes --hash=sha-512 --filesystem=fat -p 12345 --pim=0 -k "" --random-source=/dev/urandom

Done: 100.000%  Speed: 5.3 MiB/s  Left: 0 s                

The VeraCrypt volume has been successfully created.
非常慢...2G 的 card 花了10 min..
查到有 --qick 做 quick format.. 測試..
# /data/veracrypt -t -c --volume-type=normal /dev/mmcblk1p1 --encryption=aes --hash=sha-512 --filesystem=fat -p 12345 --pim=0 -k "" --random-source=/dev/urandom --quick

Done: 100.000%  Speed: 115 MiB/s  Left: 0 s             

The VeraCrypt volume has been successfully created.
大概 15sec..

mount
# /data/veracrypt -p 12345 --pim=0 -k "" --protect-hidden=no /dev/mmcblk1p1 /sd
大概要 10sec.

這樣 create 出來的 disk 在 windows 系統,可以使用 veracrypt mount 起來。 read.write OK

2022/9/12

static build VeraCrypt for aarch64

用 cryptsetup 可以 open veracrypt disk/partiton,但是不能 create veracrypt disk/partition。
必須要安裝 veracrypt,但是 veracrypt 沒有在 distibution 中。
要加 ppa,或是 build from source..

需要 yasm, libfuse-dev,
在 aarch64 pi 上面 build 就跟在 x86 上 build 一樣。
就算是只要 console 板,也需要 wxWindows。
所以依照 官方說明,可以download wxWindows 3.0 (.5) source 下來,解開。veracrypt Makefile 會包含 build 他的 instruction。
所以先 build wxWindwos 再 build veracrypt 就可以:
cd src
make NOGUI=1 WXSTATIC=1 WX_ROOT=~/wxWidgets-3.0.5 wxbuild
make NOGUI=1 WXSTATIC=1
結果就會在 src/Main/veracrypt

如果要 build static linked program,可以修改 src/Makefile,在 一開始的 LFLAGS 加上 -static
export LFLAGS := -static
再 build 就可以。

要注意的是,因為 .gitignore 有把一些 build, config 的 file 加入 ignore。
但是make 得時候又會參考,
所以 change option 時,make clean 沒辦法完全清乾淨,導致會有make error。

test build Tag: VeraCrypt_1.25.9 OK

mount veracrypt partitoin in linux

因為 windows 沒有辦法 mount luks partition/disk。
在 windows 上做 disk /partition encryption 就只有 support truecrypt,對應的 application (open-sourced) 就是 veracrypt
反過來,在 linux 上mount veracrypt encrypt 的 sd card..

參考:
~$ sudo cryptsetup --type tcrypt --veracrypt open <device> <name> 
先把 sd card create 好 partition。

參考veracrypt 說明:
create Volume -- create none-system partition/drive -- standard veracrypt volume -- volume location (select sd card drive name) -- created encrypted volume and format it -- Encryption Algorithm AES, Hash Algorithm SHA-512 -- volume size -- password

這樣就 create 好了一個 trucrypted partition。
可以用 veracrypt -- Mount 功能,mount 進 windows driver。

在 linux 上,可以用上面的
cryptsetup --type tcypt --veracrypt open /dev/sdb1 mysd
輸入 password 後,會出現在 /dev/mapper/mysd
然後:
mount /dev/mapper/mysd /sd
就會在 /sd 下看到了。

mount luks disk in wsl

ref: 大概就是:
要 windows 11,先在 powershell 下把 volume mount bare 給 wsl,這樣wsl 就看得到partition/disk 了。
然後在 wsl 下用一般 mount command 來 mount (所以也可以用 cryptsetup..)

依照 ref:How to mount a LUKS encrypted drive in Windows:

在 powershell :
C:\Users\miguel> GET-WMIOBJECT -query "SELECT * from Win32_DiskDrive"
列出所有的 disk, partition.(的name),然後選要給 wsl 的,做:
PS C:\Users\miguel> wsl --mount \\.\PHYSICALDRIVE1 --bare
然後到 wsl 的 linux(debian, ubuntu) 下:
$ lsblk
就可以看到剛剛給 wsl 的 disk 了,之後就用一般 linux 的 command:
$ sudo cryptsetup luksOpen /dev/sdc1 TOSHIBA2TB
$ sudo mount /dev/mapper/TOSHIBA2TB /mnt/TOSHIBA2TB/

2022/8/29

rknn toolkit install log

流水帳:

don't know why it needs 1.11.0, and suggested python version is 3.5
but tesnorflow 1.11.0 say: protobuf requires Python '>=3.7' but the running Python is 3.5.6 but... with python 3.6.13, install OK

the origional requrement.txt:
tensorflow==1.11.0
torchvision==0.4.0
torch==1.5.1
mxnet-cu101==1.5.0
tochvision 0.4.0 need torch 1.2.1,
so remove the version label. install OK.
result: (pip list)
torch               1.5.1
torchvision         0.6.1
final : install local whl
python 3.6, so choose cp36
pip install rknn_toolkit-1.6.0-cp36-cp36m-linux_x86_64.whl
test:
$python
Python 3.6.13 |Anaconda, Inc.| (default, Jun  4 2021, 14:25:59) 
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from rknn.api import RKNN
>>>
另外要run test.py 的話,還要 install opencv-python


更新:

根據 Rockchip github repo 的說明。
最新版本已經到 1,7.3,已經support ubuntu 20.04 了,猜已經 update 了 requirement packages dep
並且,因為 whl 檔案太大,沒有放到 git repo 中,改為到release 下載 zip file

2022/8/12

依照時間切割影片

ref: 我用一個"%" 才成功
 ffmpeg -i C0.avi -c copy -map 0 -segment_time 8 -f segment video%03d.avi
8 的單位是 sec

然後,只有第一個file 能播,所以.. 加上 -reset-timestamps 1
ffmpeg -i C0.avi -c copy -map 0 -segment_time 60 -f segment -reset_timestamps 1 C0_%02d.avi


一些 ffmpeg transcode 的 option 說明:

2022/8/9

grep binary as text

ref: 有時候grep 會出現:
Binary file messages.0.txt matches
然後一堆string 都沒搜尋出來。

因為 grep 的文件中有 none-ascii code。
如果要 grep 不管 none-ascii,一律當 ascii 來搜尋,可以用 '-a' option
grep -a history mymessages

2022/8/8

CVAT 標示 object detection 資料

安裝

follow Installation 官網說明。
CVAT 是用 Docker compose 寫的一堆服務組成,所以要用 docker run
clone docker compose yml 後,依照需要修改 docker compose file。
再啟動所有的 containers.
CVAT default 對 127.0.0.1 服務,如果要改變,可以用環境變數 : CVAT_HOST 來改變。
container 啟動後,必須要執行 container 中的 shell command 來 create superuser (不是Default 就 create 好)
然後,就可以用這個帳號 login 了。
git clone https://github.com/opencv/cvat
cd cvat
export CVAT_HOST=your-ip-address
docker-compose up -d
docker exec -it cvat bash -ic 'python3 ~/manage.py createsuperuser'
輸入 admin 和 password。
然後就可以用 browser 開啟剛剛設定的 your-ip-address:8080/ 進行登入。


標示

先 follow 這個 create 一個標示的 task。
在 "select file" 的階段,選擇影片檔 (AABB.mp4)。

然後到 Jobs 去打開剛剛 create 好的 task
進入標示的 UI
以 object detection 來說,最有用的就是左邊 menu 的 'Draw New Retangle', mouse 靠近後,會顯示內容,'shape' 跟 'track'。
選 track 的話,他就會自動在下一個 frame 標示。
選 track 後,在畫面上框出 object。
右邊panel 就會出現框出來的 object。
點選上方control 的 '>' 會到下一個 frame,剛剛的匡會繼續。
可以多跑幾個 frame 後,等object 跑遠了,但是框都沒跟上,把框拉到正確位置。
這時候,用 '^lt;' 看一下前幾個 frame,他就會依照移動比例,移動框了。
對於 tracking,CVAT 把手工調整過的,叫 key frame,他會把相應兩個 key frame 間的 frame,依照比例,改變其中的 frame 的框。
所以可以用 'F', 'D' 顯示前,後 frame,如果是線性就不用調整。有太大改變再手動調整。

ref:track mode advanve

Export

CVAT export supporty Yolo 的格式,標好,save 後,選左上menu 的 export,格式選 yolo v1 ,跟 save image ,就會把 image, txt 輸出成 zip file
export 的 image 格式是 PNG,檔案很大。
可以參靠convert png to jpg 的作法:
mogrify -format jpg *.png

bookmark : docker compose commands

ref: 大概就跟 docker command 一樣,只不過,docker-compose 要在docker-compose.yml 所在目錄下,才會正常動作。

啟動 (-d 代表 daemon)
# docker-compose up -d 

要是有修改 docker-compose.yml,就用
# docker-compose up -d --no-recreate

看看所有(相關的) container 狀態:
# docker-compose ps

停止所有(相關的)docker container:
# docker-compose stop

刪除所有(相關的)container:
# docker-compose rm -f

刪除所有(相關的) volume:
# docker-compose rm -v

2022/8/4

OpenBmc test build (for raspberry pi 3)

git clone https://github.com/openbmc/openbmc
cd openbmc
git checkout 2.11.0
export TEMPLATECONF=meta-evb/meta-evb-raspberrypi/conf
. openbmc-env
修改 build/conf/local.conf:
我把
MACHINE ??= "raspberrypi3"
和加上
GPU_MEM = "16"
IMAGE_FSTYPES += " rpi-sdimg"
讓輸出成 sd card img 格式。

然後修改 meta-phosphor/classes/image_types_phosphor.bbclass
FLASH_SIZE ?= "131072"
不然build 完會有 too large 的 Error.

就可以到 build 下開始 build
bitbake obmc-phosphor-image
build 完,在 /build/tmp/deploy/images 下的 *sdimg 就是燒錄檔。
dd 到 sdcard 後,mount 回來,在 boot partition (vfat) 家上
enable_uart=1
插入 pi3 開機,等一下就可以在 uart console 看到 login prompt (沒有 boot log)
default root password 是 0penBmc (zero-bmc)


OpenBmc 就是一個標準的 linux,沒什麼特別的,只是裝了一些 bmc 的 tool,以往的 bmc snmp, rest4, gprc web 等服務,都是 linux 標準 packages.

2022/7/28

install node from source, then run VoTT

distribution 的 node 版本太舊 8.10.0,VoTT 說node 至少要 10 以上。
所以只好 install node from source.

先決定版本...
因為 kernel 版本太舊(4.15),所以只能用 v17 之前的版本。
因為 gcc 版本太舊 (7.5),所以只能用 v14之前的版本。
  --prefix=PREFIX       select the install prefix [default: /usr/local]
所以..
./configure --prefix=/home/myname/node14
make -j4
make install
然後再寫 PATH 的 env 到 node14/bin 就可以。

結果一樣,出現 Error:
error: no matching function for call to ‘v8::Value::ToBoolean(v8::Local<v8::Context>)’
所以版本再往前...
改 checkout v10.19.0 (ref ubuntu20.04 的版本)
一樣的 build install, 之後, 到 VoTT ,, npm ci, npm run start
OK。
但是因為 server 上已經有另一個 nodjs server 正在run,所以出的是那個 server 的內容。
修改 package.json,把 nf start -p 3000 改成 4000 之後就 OK 了。

2022/7/21

Video Labeling Tools

這個可以從影片開始 labeling,並且可以裝 objection detection 跟 tracking 的 module。
是 local, X, standalone 的。


這個安裝時要指定 opencv-contrib-python==4.1.2.30,這只有 python 3.7 才有。
ref:安裝 opencv-contrib-python

分成 server 和 client (GUI), server 的 requirements.txt,torch 版本太低 (0.4.1),所以拿掉,手動安裝 cuda 板。
-- 不行,cuda 版本需求numpy 版本,requirements 中的版本太低。有人修改到 torch 1.9.0 但是 run failed


這個有比較多人用,也可以半自動 detect,也可以吃video。
但是 export format 沒有 support yolov5 的 txt format,但是有很多人寫了python script,和nodejs script
他有copy - paste 功能,
Ctrl-A : 選擇這個 frame 所有的 box
Ctrl-C : 複製
right arrow : 到下一個 frame
Ctrl-V : 貼上所有的 box
因為 frame 到 frame 的差異很小,所以對video 很方便。

結果,沒有寫好的 vott_csv to yolo 的 script (因為太簡單?)。
所以..
vott_csv 的 head line 有列出 column 內容:
image xmin ymin xmax ymax label
yolov5 的 format 是:
label x_center y_center width height
並且是 normalize 後的數值(0~1 之間的小數)

vottcsv2yolo.py:
import csv
import os

W = 1920
H = 1080

file = open('../vott_target/vott-csv-export/tt2-export.csv')
csvreader = csv.reader(file)

header = next(csvreader)
rows = []
for row in csvreader:
    rows.append(row)

myrows = iter(rows)
filename=None;
yolofile=None;
while (a := next(myrows,None)) is not None:
    if a[0]!= filename:
        filename=a[0]
        if yolofile != None:
            yolofile.close()
        yolofile = open((filename.split('jpg')[0]+"txt"),'w')
    xmin = float(a[1])
    ymin = float(a[2])
    xmax = float(a[3])
    ymax = float(a[4])
    x_center = (xmax+xmin)/(W*2)
    y_center = (ymax+ymin)/(H*2)
    width = (xmax-xmin)/W
    height= (ymax-ymin)/H
    yolofile.write(f'0 {x_center:f} {y_center:f} {width:f} {height:f}\n')
if yolofile != None:
    yolofile.close()

然後使用 labelImg 看 yolov label 的結果:
follow labelImg 的說明:
conda create python=3 (結果是 3.10)
sudo apt-get install pyqt5-dev-tools
activate conda env for labelImg
git clone https://github.com/heartexlabs/labelImg.git
cd labelImg
git checkout v1.8.6
pip install -r requirements/requirements-linux-python3.txt
make qt5py3
然後要修改兩個地方:
~/labelImg$ git diff
diff --git a/labelImg.py b/labelImg.py
index 915ca04..3e72917 100755
--- a/labelImg.py
+++ b/labelImg.py
@@ -205,7 +205,7 @@ class MainWindow(QMainWindow, WindowMixin):
         self.file_dock.setFeatures(QDockWidget.DockWidgetFloatable)
 
         self.dock_features = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable
-        self.dock.setFeatures(self.dock.features() ^ self.dock_features)
+        self.dock.setFeatures(self.dock.features() ^ int(self.dock_features))
 
         # Actions
         action = partial(new_action, self)
diff --git a/libs/canvas.py b/libs/canvas.py
index fe355fb..d2d0e32 100644
--- a/libs/canvas.py
+++ b/libs/canvas.py
@@ -162,7 +162,7 @@ class Canvas(QWidget):
             return
 
         # Polygon copy moving.
-        if Qt.RightButton & ev.buttons():
+        if Qt.RightButton & int(ev.buttons()):
             if self.selected_shape_copy and self.prev_point:
                 self.override_cursor(CURSOR_MOVE)
                 self.bounded_move_shape(self.selected_shape_copy, pos)
@@ -173,7 +173,7 @@ class Canvas(QWidget):
             return
 
         # Polygon/Vertex moving.
-        if Qt.LeftButton & ev.buttons():
+        if Qt.LeftButton & int(ev.buttons()):
             if self.selected_vertex():
                 self.bounded_move_vertex(pos)
                 self.shapeMoved.emit()
不然開啟會有Error,還有移動滑鼠會有 Error,程式會自動關閉。

create mylabel folder, copy Vott label 好,export 的 jpg 過去。
把 run 完 vottcsv2yolo.py 的 txt 也 copy 過去。
寫好 classes.txt:
person
car
接著就可以開啟 labelImg:
cd labelImg 
python labelImg
Open Dir 到剛剛 create,放好 jpg, txt 的 folder。
data format 選 yolo
就可以看到 label 的結果了。


label and convert 完,要分成 train, valid 兩個 folder,可以參考:使用 scikit-learn 的 train_test_split() 拆分数据集
from sklearn.model_selection import train_test_split
import glob as glob
import os
import shutil

all_files = glob.glob('./*.txt')
train, valid = train_test_split(all_files,random_state=777,train_size=0.85)
print(f"train: {len(train)}, valid: {len(valid)}")

for file in train:
    shutil.move(file,f"./train/labels/{file}")
    jfile = file.replace('txt','jpg')
    shutil.move(jfile,f"./train/images/{jfile}")

for file in valid:
    shutil.move(file,f"./valid/labels/{file}")
    jfile = file.replace('txt','jpg')
    shutil.move(jfile,f"./valid/images/{jfile}")

labelImg補充:
ref:
python 3.10 才會有上面的 Error,=而且在 畫 box 時會有scroll error。
所以要用 python=3.9

之後的 requirement 也會不 match,要手動..
pip install pyqt5 lxml

2022/7/19

Fix Bluetooth Headset, Headphone function in ubuntu 20.04

想不到 ubuntu 20.04 的 pluseaudio 不 support bluetooth 的 hsp。
所以沒辦法用 bluetooth 的 microphone (因為一直用 A2DP profile)

這一篇 說,修改 /etc/pulse/default.pa。
在 module-bluetooth-discover.so 後面加上 headset=ofono

更完整的在: 但是ubuntu 20.04 找步道 ofono-phonesim
自己加:
sudo add-apt-repository ppa:smoser/bluetooth
sudo apt-get update
sudo apt-get install ofono-phonesim
至於這個說明,和這個說明,一樣修改 /etc/pulse/default.pa,加上 auto_switch=2,會讓 bluetooth 無法連線。

其他,最多,最方便(?)的大概就是用 pipewire 了,
這一篇 說:
PipeWire acts as a drop-in replacement for PulseAudio and offers an easy way to set up Bluetooth headsets. 
It includes out-of-the-box support for A2DP sink profiles using SBC/SBC-XQ, AptX, LDAC or AAC codecs, and HFP/HSP.
所以,大概可以安心用吧(?)
安裝一樣要用 ppa:
sudo add-apt-repository ppa:pipewire-debian/pipewire-upstream
sudo apt update
sudo apt install pipewire
sudo apt install libspa-0.2-bluetooth pipewire-audio-client-libraries

systemctl --user daemon-reload
systemctl --user --now disable pulseaudio.service pulseaudio.socket
systemctl --user mask pulseaudio

systemctl --user --now enable pipewire-media-session.service
然後 check service 是否...
$ pactl info
...
Server Name: PulseAudio (on PipeWire 0.3.32)
...
如果不 OK,可以..
systemctl --user restart pipewire

要 roll-back 的話,可以:
systemctl --user unmask pulseaudio

systemctl --user --now enable pulseaudio.service pulseaudio.socket
這一篇好像是最早的文章。

結果,切到 A2DP 是 OK,切到 HSP 沒聲音,phone 跟 mic 都沒聲音。
然後這一篇說,pipewire 新版的設定檔改位置了。

結果還是一樣,沒聲音。
最後是用外接 bt dongle 才成功。
所以猜是 buildin bt firmware 問題。

另外。
這樣就要 disable internal bt,use bt dongle

$ dmesg | grep Blue
[    5.531481] Bluetooth: Core ver 2.22
[    5.532182] Bluetooth: HCI device and connection manager initialized
[    5.532188] Bluetooth: HCI socket layer initialized
[    5.532190] Bluetooth: L2CAP socket layer initialized
[    5.532198] Bluetooth: SCO socket layer initialized
[    5.697901] Bluetooth: hci0: BCM: chip id 63
[    5.698891] Bluetooth: hci0: BCM: features 0x07
[    5.714899] Bluetooth: hci0: BCM20702A
[    5.714905] Bluetooth: hci0: BCM20702A1 (001.002.014) build 0000
[    5.719734] Bluetooth: hci0: BCM: firmware Patch file not found, tried:
[    5.719740] Bluetooth: hci0: BCM: 'brcm/BCM20702A1-0a5c-21f3.hcd'
[    5.719741] Bluetooth: hci0: BCM: 'brcm/BCM-0a5c-21f3.hcd'
[    6.303633] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[    6.303638] Bluetooth: BNEP filters: protocol multicast
[    6.303643] Bluetooth: BNEP socket layer initialized
[    7.276706] Bluetooth: RFCOMM TTY layer initialized
[    7.276717] Bluetooth: RFCOMM socket layer initialized
[    7.276724] Bluetooth: RFCOMM ver 1.11
在/lib/firmware/brcm/ 下真的沒找到 BCM-0a5c-21f3.hcd,只有 BCM-0bb4-0306.hcd
根據這邊 的說明:
This package intentended to provide firmware of Broadcom WIDCOMM® Bluetooth devices 
(including BCM20702, BCM20703, BCM43142 chipsets and other) for Linux kernel. 
Since February 2017, Broadcom ships their drivers directly to Windows Update service. 
依照 dmesg 的 filename : BCM2070A1-0a5c-21f3.hcd,download 下來, copy 到 /lib/firmware/brcm/ 後,reboot, dmesg 變成:
[    4.435281] Bluetooth: Core ver 2.22
[    4.435312] NET: Registered PF_BLUETOOTH protocol family
[    4.435314] Bluetooth: HCI device and connection manager initialized
[    4.435319] Bluetooth: HCI socket layer initialized
[    4.435322] Bluetooth: L2CAP socket layer initialized
[    4.435327] Bluetooth: SCO socket layer initialized
[    5.486378] Bluetooth: hci0: BCM: chip id 63
[    5.487374] Bluetooth: hci0: BCM: features 0x07
[    5.503384] Bluetooth: hci0: BCM20702A
[    5.503391] Bluetooth: hci0: BCM20702A1 (001.002.014) build 0000
[    5.508881] Bluetooth: hci0: BCM20702A1 'brcm/BCM20702A1-0a5c-21f3.hcd' Patch
[    5.942911] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[    5.942916] Bluetooth: BNEP filters: protocol multicast
[    5.942921] Bluetooth: BNEP socket layer initialized
[    6.593382] Bluetooth: hci0: Broadcom Bluetooth Device
[    6.593389] Bluetooth: hci0: BCM20702A1 (001.002.014) build 1761
[    6.958593] Bluetooth: RFCOMM TTY layer initialized
[    6.958602] Bluetooth: RFCOMM socket layer initialized
[    6.958609] Bluetooth: RFCOMM ver 1.11
然後 bt headphone 的 hsp 就正常了。

所以..
  • 安裝 pipewire
  • download .hcd
才能讓 ubuntu 20.04 的 bluetooth headphone 功能恢復正常。

其他的 ref:

ref: 一直要到 ubuntu 22.10 才會內建 pipewire.

2022/7/18

fisheye photo

大概就是參考這個人的,有寫出一般 wide angle, lens distortion 的 correction 跟 fisheye 的。
然後這邊 剛好有人寫了一樣的sourece code,放在 github
實際上會遇到像這樣這樣 的問題。
我把黑邊修掉(crop) 後才約略可以用。
最後這一個人用180 的鏡頭順利remap 出可以用的。

覺得是 remap,不是 undistortion,是要 prject 到另一格平面,例如 panorama或是 cylindre。不是 distortion 的問題。

有關一般fisheye 跟 Rectlinear 鏡的說明/計算/解釋,在這裡

opencv 有關各種 camera 的 calibration 說明: 然後有一個日本人寫了方便的各種 camera calibration, undistort 的 code
這個 是一個中國人寫的,主要是把四顆 fisheye 拼成 surround view
這個 是把 fisheye un-warp 成各種 perspective view
是把 fisheye 轉成 panoramic, spherical or perspective projection


  • 另外看到的,很有趣但是無關的是這個,一步一步教你做image stitch
  • 這一篇論文也是,做 surround view 拼街,其中有說明 Brightness Uniformity and Image Blending 的作法
  • 這一篇論文則是把 fisheye dewarp/unwarp 之後,再用 yolov3 辨識

Bookmark : augmentation with albumentation : bonding box transform

2022/7/8

ssl tunnel . and tensorboard

tensorboard default 是在 local 服務。
要給 remote view 雖然可以設定,但是有點麻煩。
簡單就用 ssl tunnel。把 tensorboard server 的 local port 傳到remote 的機器。
這樣 remote 的機器就可子藉由開啟 自己的 port 看到 tensorboard server 的 port 了。

ref: 因為 tensorboard 服務的 port是 6006,所以把 tensorboard server 的 localhost:6006 轉到我自己的 16006 port:
ssh -L 16006:127.0.0.1:6006 user@server
這樣,自己這邊開啟: localhost:16006 就可以看到 server 上 tensorboard 的輸出了。
其實在啟動 tensorboard 的時候,加上 host ip 就可以讓其他(所有人)看到輸出了:
tensorboard --host 0.0.0.0 --logdir ./logs/fit/
但是如果要加上login 檢查,就只好用ssl tunner.

2022/7/1

linux-pam, pam_securetty.so

touch /etc/pam_debug 就可以把 PAM 的 debug message 放到 system log 中。-- authpriv

manual 有:
       pam_securetty is a PAM module that allows root logins only if the
       user is logging in on a "secure" tty, as defined by the listing
       in /etc/securetty. pam_securetty also checks to make sure that
       /etc/securetty is a plain file and not world writable. It will
       also allow root logins on the tty specified with console= switch
       on the kernel command line and on ttys from the
       /sys/class/tty/console/active.

build-from source:

git clone https://github.com/linux-pam/linux-pam
版本都很舊,有些 am, config 的格式都錯,最後 checkout v1.5.2 才build OK

需要 flex
然後 document 有問題,所以要 disable。
./autogen,sh
./configure --help | less
./configure --enable-static=yes --enable-debug --disable-doc
make


securetty_perform_check
#define SECURETTY_FILE "/etc/securetty"
if (stat(SECURETTY_FILE. &ttyfileinfo)
..
#define CONSOLEACTIVE_FILE "/sys/class/tty/console/active"
最後一個檢查是盤排除 /sys/class/tty/console/activat 所寫得 tty。
所以只要 /sys/class/tty/console/activate 內寫的 tty,就一定不會被 pam_securetty block

source code 另外有 noconsole 這個 option,可以 bypass 後面的 console/active 檢查。只依照 /etc/securetty 的內容。
cat /etc/pam.d/login
 
#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so debug noconsole
..

2022/6/29

shell: ls folder only

因為 folder 最後都會加上 '/',所以就是:
ls -d ./*/
其實是想要找出最大 size 的 folder...
ls -d ./*/ | xargs du -sc | sort -n

2022/6/28

pytorch cudatoolkit version and local cuda version

ref: 使用新mb/hardware 的人都會遭遇這個問題,必須要安裝新版的 cuda,但是 pytorch 又不支援這摸新的版本。

根據以上ref 的說明,pytorch 會自帶 cuda toolkit 的 binary,部會用到 local 安裝的,所以local 甚至不用裝 cuda。

所以只要 pytorch 的cuda 版本跟 driver 是 相容可以用的,就可以了,不用管 local (host) 安裝的 cuda 版本。
-- 真正要用到 local 的 cuda toolkit,只有 build pytorch from source 的時候才需要。
另外,到 -extra-index-url https://download.pytorch.org/whl/cu113 去看,好像有 support 到 cu116..

雖然如此,package manger 版本的 pytorch 使用的 cuda 版本如果太舊,沒有支援新的 GPU,就會出現 ref:2 的錯誤。
這時候就要安裝新版本的 pytorch,或是用 url 或是 channel指定 cuda 版本。

測試一下cuda 版本與 trainning speed 有沒有關係。
titan rtx, cuda 11.2
pip 安裝 default torch 1.11,未指定 cuda 版本。
real	3m48.122s
user	4m44.344s
sys	0m15.251s



可以用 python module command 列出package content:
pip package default:
$ python -m torch.utils.collect_env
Collecting environment information...
PyTorch version: 1.11.0+cu102
Is debug build: False
CUDA used to build PyTorch: 10.2
ROCM used to build PyTorch: N/A

OS: Ubuntu 18.04.5 LTS (x86_64)
GCC version: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Clang version: Could not collect
CMake version: version 3.10.2
Libc version: glibc-2.27

Python version: 3.10.4 (main, Mar 31 2022, 08:41:55) [GCC 7.5.0] (64-bit runtime)
Python platform: Linux-4.15.0-166-generic-x86_64-with-glibc2.27
Is CUDA available: True
CUDA runtime version: 10.2.89
GPU models and configuration: GPU 0: TITAN RTX
Nvidia driver version: 460.91.03
cuDNN version: Probably one of the following:
/usr/lib/x86_64-linux-gnu/libcudnn.so.7.6.5
/usr/local/cuda-10.2/targets/x86_64-linux/lib/libcudnn.so.7.6.5
HIP runtime version: N/A
MIOpen runtime version: N/A

Versions of relevant libraries:
[pip3] numpy==1.23.0
[pip3] torch==1.11.0
[pip3] torchvision==0.12.0
[conda] numpy                     1.23.0                   pypi_0    pypi
[conda] torch                     1.11.0                   pypi_0    pypi
[conda] torchvision               0.12.0                   pypi_0    pypi
使用: url 指定 whl/cu116:
$ python -m torch.utils.collect_env
Collecting environment information...
PyTorch version: 1.12.0+cu116
Is debug build: False
CUDA used to build PyTorch: 11.6
ROCM used to build PyTorch: N/A

OS: Ubuntu 18.04.5 LTS (x86_64)
GCC version: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Clang version: Could not collect
CMake version: version 3.10.2
Libc version: glibc-2.27

Python version: 3.10.4 (main, Mar 31 2022, 08:41:55) [GCC 7.5.0] (64-bit runtime)
Python platform: Linux-4.15.0-166-generic-x86_64-with-glibc2.27
Is CUDA available: True
CUDA runtime version: 10.2.89
GPU models and configuration: GPU 0: TITAN RTX
Nvidia driver version: 460.91.03
cuDNN version: Probably one of the following:
/usr/lib/x86_64-linux-gnu/libcudnn.so.7.6.5
/usr/local/cuda-10.2/targets/x86_64-linux/lib/libcudnn.so.7.6.5
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True

Versions of relevant libraries:
[pip3] numpy==1.23.0
[pip3] torch==1.12.0+cu116
[pip3] torchaudio==0.12.0+cu116
[pip3] torchvision==0.13.0+cu116
[conda] numpy                     1.23.0                   pypi_0    pypi
[conda] torch                     1.12.0+cu116             pypi_0    pypi
[conda] torchaudio                0.12.0+cu116             pypi_0    pypi
[conda] torchvision               0.13.0+cu116             pypi_0    pypi

PyTorch, package manager and cuda support

pytorch 的安裝隨著python package manager 的不同,結果也不一樣。
依照pytorch 的安裝說明 的話,cuda or cpu only各有明確的指令。

例如:

pip 安裝, cuda support:
pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
-- cpu 的話,就 cu113 改 cpu。


conda 安裝:
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
-- cpu 的話就是 cudatoolkit=11.3 改成 cpuonly


但是看 yolov5 的 requirements.txt,其中 torch 的部份..:
torch>=1.7.0
沒有指定 ..
-- 所以會是有 cuda support ?
用 pip install torch,不加上 url。安裝完後,用 torch.cuda.is_available() 測試看看。
在有 cuda 的機器上,是 True,在沒有 cuda 的機器上,是 False。
但是用 pip freeze 看安裝的 package full name 都是 torch=1.11.0

-- 發現,若是 10.2,則pip install torch 時、不須指定 download whl。反而是 cpu 板才要。
所以 package manager 版本應該有 support 了。
測試,在 cuda 的機器上 pip install torch 指定 download whl cpu,cuda.is_available() 是 False.

結論大概是..
package manager : pip 已經把 pytorch 10.2, 11.3 都納入 package repo 中了。但是 conda 沒有。所以 conda 安裝一定要指定 cudatoolkit 和 python channel

yolov5 其實有要求 python 版本:
Python 3.7.0 required by YOLOv5

2022/6/23

test securetty in raspberry pi with buildroot

用 buildroot build 一個 system image
mkdir pibuildroot && cd pibuildroot
wget ...
tar zxvf ..
cd ..
看一下 board 下面很多 raspberrypiX 都 ln 到 raspberrypi。
裡面有 readme.txt。
有說 pi3 的話..
make raspberrypi3_defconfig
用 make help 會列出一堆 make target。
然後用 make menuconfig 去看,就是arm 的 config 了。
而且因為是 pi3, 會用 cortex A53,不是 pi 一代的 arm11

要 enable PAM (linix-pam) 的話,在 packages/linux-pam
從 packages/Config.in 可以找到 linux-pam 的 menuconfig 位置。
Target packages -- Libraries -- Other
從 linux-pam 的說明(警告),說,linux-pam 要 clibc 或是 glibc 才行。
所以menuconfig 的 toolchain 中,原來是 uclibc-ng,要改為 glibc。
這樣選完,就可以check linux-pam 了。

make 完畢,在 output/images 下的 sdcard.img,就拿來 dd 到 sdcard。
開機,console 就可以看到訊息。

沒有 check linux-pam 時,/etc 下沒有 pam.d 目錄。
check 之後,就有了。

在 /etc/pam.d/login 加一行:
auth		required	pam_securetty.so
然後新增一個 /etc/securetty 空檔案。
為了避免沒版法login,新增一個 user。

這樣reboot 後,可以發現 在 uart 已經無法用 root login 了(login incorrect),但是用剛剛新增的 user 可以。
用新增的 user login 後, su - 成 root。

su - 成 root 後,修改 /etc/securetty,加上
console
-- 因為用 w 看,login TTY 是 console,不是 tty1, ttyS0 之類,所以用 console
reboot,就發現又可以用 root login 了。

把 securetty 的console 拿掉,確認無法 login 後,再把 /etc/pam.d/login 的 auth pam_securetty.so 拿掉,是可以用 root login 的。
所以確認是 pam.d/login 的 auth pam_securetty.so 讓 /etc/securetty 生效。



有關buildroot 跟 busybox 在 PAM 上的關聯。
buildroot 的 script: package/busybox/busybox.mk: 有根據 buildroot 的 PAM 設定,自動設定 busybox 的 PAM。
# PAM support requires thread support in the toolchain
ifeq ($(BR2_PACKAGE_LINUX_PAM)$(BR2_TOOLCHAIN_HAS_THREADS),yy)
define BUSYBOX_LINUX_PAM
        $(call KCONFIG_ENABLE_OPT,CONFIG_PAM,$(BUSYBOX_BUILD_CONFIG))
endef
BUSYBOX_DEPENDENCIES += linux-pam
else
define BUSYBOX_LINUX_PAM
        $(call KCONFIG_DISABLE_OPT,CONFIG_PAM,$(BUSYBOX_BUILD_CONFIG))
endef
endif
所以會根據buildroot 的 PAM check/uncheck disable/disable busybox 的 PAM 設定。
所以要測試,enable linux-pam, disable busybox pam support 的話,就要到 output/build/busybox-1.31.1 單獨做 busybox 的 menuconfig。
的確沒有效了,root login OK

改用 util-linux 的 login。
--uncheck busybox 的 login

確認是 OK的,可以用 pam.d/login 跟 securetty 來限制 root login console

2022/6/13

Use vi to find non-ascii character

先下 command:
: set list
這樣,non ascii code 會high light 出來。
再用search:
/[^\x00-\x7F]
就會一個一個搜尋出來 (用 n)

只找一個,例如:0x9c,就用
/[\x9c]

mplay : mplay 2 videos on 2 monitors

用 mplayer 指定播放的 monitor,用 screen option
--用 man player 可以列出比較仔細的 option.

所以,在第二個 monitor,永久反覆全螢幕播放 此目錄下所有檔案:
mplayer -loop 0 -screen 0 -fs *

** 結果 mpv 跟 mplayer 是不一樣的東西...


如果是 ssh 過去,要在 機器上的monitor 播放,而不是在 ssh client 這邊播放。
ssh 過去後,要
export DISPLAY=:0
再播。

-- 結果還是不行,要用 mpv 的 screen option 才行。

ssh 連線..
export DISPLAY=:0

mpv 播放,with screen option:
mpv --screen=0 myfile.mp4
--screen=1 的話就會播到令一個 monitor

2022/6/10

2022/6/6

memo - gdb, argument and source location

大概就是...
gdb --args executablename arg1 arg2 arg3
進入 gdb 後,用指令 directory 指定source code 所在位置 (absolute path)
gdb> directory /data/

2022/6/1

Read mender-store with python code

讀取 mender-store 的內容...
(lmdb) charles-chang@e431focal:~$ python
Python 3.10.4 (main, Mar 31 2022, 08:41:55) [GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lmdb
>>> env = lmdb.open('./mender-store',subdir=False)
>>> txn = env.begin()
>>> myList = [ key for key, _ in txn.cursor()]
>>> print(myList)
[b'artifact-name', b'artifact-provides', b'authtoken']
>>> 
>>>print(txn.cursor().get(b'artifact-name'))
b'1.0.1.30rc1-deltafrom-1.0.0.28patch3'
>>> print(txn.cursor().get(b'artifact-providese'))
None
>>> print(txn.cursor().get(b'artifact-provides'))
b'{"rootfs-image.checksum":"457d85413d8dbdb2c278b4740493efb3712290f36668a919dd4297ae60ca6157","rootfs-image.version":"1.0.1.30rc1"}'

另外,lmdb 的 put/get :
>>> import lmdb
>>> env = lmdb.open('./testlmdb')
>>> txn = env.begin(write=True)
>>> txn.put(key=b'1',value=b'abc')
True
>>> txn.put(key=b'aaa',value=b'{a=1},{b=2}')
True
>>> txn.commit()

>>> txn = env.begin()
>>> for key,value in txn.cursor():
...     print(key,value)
... 
b'1' b'abc'
b'aaa' b'{a=1},{b=2}'


所以寫一個小程式,可以簡單create 這個 key-value 的 lmdb data file: 是用lmdb 的 code。

這樣,只要:
./mydb ./mender-store artifact-provides "{\"rootfs-image.checksum\":\"457d85413d8dbdb2c278b4740493efb3712290f36668a919dd4297ae60ca6157\",\"rootfs-image.version\":\"1.0.1.30rc1\"}"
就可以新增 value
然後 mylist 就是跟 python 一樣的function,列出 db 中所有 key-value record.

2022/5/27

bookmark: finding best learning rate

很有趣,用同一個起始狀太,變更 learning rate,算出 loss 變更的量。
這樣就能找出最佳的 learning rate。

2022/5/26

tensorboard in colab

在 colab 中使用 tensorboard,就是用 colab 的 shell command 啟動tensorboard ..
%load_ext tensorboard
...
...
%tensorboard --logdir {logdir} --reload_interval 1
之後,tensorboard render web page 就會 show 在colab 中,這一行code 的 output 區域中。
之後,任何得的 logdir 更新,都是在這個output section 中的 tensorboard web page 中,手動按下 "refresh" 來更新。

可以 run 這一個 keras example 看看。

2022/5/17

docker network

docker container 的 network 是可以選擇的。
可以選擇哪些 container 在同一個 LAN 中。

先列出 所有 network (LAN)
$docker network ls

NETWORK ID     NAME                             DRIVER    SCOPE
3b445b1ff6ca   bridge                           bridge    local
1cb8711ba147   compose_default                  bridge    local
bc0cb939c115   dm1cloud_dockercompose_default   bridge    local
3bab1858d569   dockers_default                  bridge    local
用 inspect 看 container,會顯示他在那一個 network..

然後啟動新 container 時,就可以用 --network dm1cloud_dockercompose_default 指定在某個 network 中。
同一個 network 中的 container,可以用 container name 取代IP。例如
docker run -network dm1cloud_dockercompose_default ping mongo-server mongo
其中 mongo-server 就是在 dm1cloud_dockercompose 中的一個 container。

2022/5/11

mongodb install

安裝依照官網: 一般的動作:
  1. 加 pgp key
  2. 加sources.list
  3. apt update
  4. apt install
裝完 default config 會在: /etc/mongod.conf
config 裡面的 ..
  • storage: /var/lib/mongodb
  • log: /var/log/mongod/mongod.log
  • net: 127.0.0.1:27017
apt 會安裝到 systemd : mongod.service


結果 在 pi3 上,用 debian 64bit 的 apt 安裝,service run fail。

單純 run docker mongo:
$ docker run -it -p 27017:27017 -v ~/mongoinstall_arm64:/mongoinstall mongo

WARNING: MongoDB 5.0+ requires ARMv8.2-A or higher, and your current system does not appear to implement any of the common features for that!
  see https://jira.mongodb.org/browse/SERVER-55178
  see also https://en.wikichip.org/wiki/arm/armv8#ARMv8_Extensions_and_Processor_Features
  see also https://github.com/docker-library/mongo/issues/485#issuecomment-970864306

需要參考mongodb under raspbian64,用另一版的 mnogodb
依照這個網頁說明,放到 mongoinstall_arm64

需要 curl, libssl-dev

所以也 用 4.4.14 看看
$ docker run -it -p 27017:27017 -v ~/mongoinstall_arm64:/mongoinstall mongo:4.4.14
Unable to find image 'mongo:4.4.14' locally
4.4.14: Pulling from library/mongo
d4ba87bb7858: Already exists 
2905e503bba5: Already exists 
7f2fbfedcbbd: Already exists 
fed819c90351: Already exists 
8c9476a7638d: Already exists 
443796fcd1a6: Pull complete 
cf4ff181511c: Pull complete 
0d3b82484af2: Pull complete 
546d4133b910: Pull complete 
7ccc69fa7857: Pull complete 
Digest: sha256:a7c77e3310e2c21cb043d2db4c46968a05d43c77644207d7d8b072d6049bb119
Status: Downloaded newer image for mongo:4.4.14

WARNING: MongoDB 5.0+ requires ARMv8.2-A or higher, and your current system does not appear to implement any of the common features for that!
  see https://jira.mongodb.org/browse/SERVER-55178
  see also https://en.wikichip.org/wiki/arm/armv8#ARMv8_Extensions_and_Processor_Features
  see also https://github.com/docker-library/mongo/issues/485#issuecomment-970864306

{"t":{"$date":"2022-05-16T07:55:40.604+00:00"},"s":"I",  "c":"CONTROL",  "id":23285,   
"ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"}
{"t":{"$date":"2022-05-16T07:55:40.613+00:00"},"s":"W",  "c":"ASIO",     "id":22601,   
"ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"}
{"t":{"$date":"2022-05-16T07:55:40.615+00:00"},"s":"I",  "c":"NETWORK",  "id":4648601, 
"ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."}
{"t":{"$date":"2022-05-16T07:55:40.618+00:00"},"s":"I",  "c":"STORAGE",  "id":4615611, 
"ctx":"initandlisten","msg":"MongoDB starting","attr":{"pid":1,"port":27017,"dbPath":"/data/db","architecture":"64-bit","host":"b2c120e0f9a6"}}
{"t":{"$date":"2022-05-16T07:55:40.624+00:00"},"s":"I",  "c":"CONTROL",  "id":23403,   
"ctx":"initandlisten","msg":"Build Info","attr":{"buildInfo":}
..
可以 run 起來。
所以用 docker host 端的 mongo client 來測試...

安裝完,除了用 systemctl status 看service 狀態,也可以用 mongodb client console 來測試。
ref: 新的 client 是 monogosh。
連線語法是:
mongosh mongodb://root:rootpasss@mogoserver:27017

有關 docker
docker imnage : mongo 的版本是 5.0.3 ,和一般(ubuntu 20.04) distribution 的版本 3.0 不一樣。
舊版本的 client 無法和版本連線。
所以也要用 docker 來連..
docker run -it mongo --interface mogocontainer-network mongosh mongodb://root:rootpassword@mogocontainername:27017
要跟 mogocontainer 同一個 network,才能直接用 container name 來連接。

2022/4/29

tensorboard

tensorboard 看起來就是提供log 分析跟training status 的 process。
提供一些 framework 的 libary,加入 training code 中。
輸出需要的資料。

另外,也可以分析 training 的 log。

使用方法就是...
tensorboard --host 0.0.0.0 --logdir ./logs/fit/
這樣 指定bind 的 ip,和告訴他 training log 的 path

他就會 run 起來,在 port 6006 提供服務(http server)。一直到 Ctrl-C 中斷為止。

2022/4/22

static build memteste

ref: 就是去memter download source tarball。解開。
然後修改 conf-ld,加上 -static
然後 make 就可以。

因為是在 pi 上 build,所以可以不用cross-build.

2022/4/21

mosquitto: about topics and config

ref: 大概比較重要的...

系統($SYS) topics 可以直接 subscribe。
在會把 $VAR 認作系統變數的 shell 李,要subcribe 的話。就加上 '\'

wild-card 有兩種: +, #
+ 只是 match 一個階層 (兩個 / 之間)
# 可以 match 多階層。

所以 # 一定要是 topic 的最後。

--- persistant message

一般 message 都是送出後就立刻轉給 subcriber,如果沒有 subscriber 就丟掉。
但是有一種 message 叫 persistant (retained) message。
送出後,mosquitto 會保存在database 中,一旦有人 subcribe,他就會把最新的內容送給他。
同一個 topic,區分為 retained 跟 not retained,如果新 message 不是 retained,不會覆蓋掉 retained message,只是剛好有 subscribe 的會收到 not retained message。

送一個空的 ("") retained message 就可以清掉這個 retained message。



/etc/mosquitto/mosquitto.conf 裡面很簡單,但是有說 example 在 /usr/share/doc/mosquitto/example/mosquitto.conf

大概安裝完,只有對 local (127.0.0.1) 操作。
如果要對外,要加上兩個 options:
listener 1883 0.0.0.0
allow_anonymous true

2022/4/18

memo : fread return value

fread 的 return value 是讀了多少進來。
但是常常會 "一直return 0"。

每次都要再 check 一下 function 宣告:
    #include <stdio.h>
    size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
那個中間的兩個:size, count 如果相反的話,就會一直 return 0 ,即使有正確讀到資料也一樣。
所以一般都是...這樣:
    char buf[8];
    size_t ret = fread(buf, sizeof(*buf), sizeof(buf)/sizeof(*buf), stdin);
    printf("read %zu bytes\n", ret*sizeof(*buf));

2022/4/14

ref: 開機的 message:
Memory: 192820K/1046528K available (5182K kernel code, 490K rwdata, 1464K rodata, 320K init, 225K bss, 26316K reserved, 827392K cma-reserved)
是在 mm/page_alloc.c:
void __init mem_init_print_info(const char *str)
{
 ..
 ..
         pr_info("Memory: %luK/%luK available (%luK kernel code, %luK rwdata, %luK rodata, %luK init, %luK bss, %luK reserved, %luK cma-reserved"
#ifdef  CONFIG_HIGHMEM
                ", %luK highmem"
#endif
                "%s%s)\n",
                nr_free_pages() << (PAGE_SHIFT - 10),
                physpages << (PAGE_SHIFT - 10),
                codesize >> 10, datasize >> 10, rosize >> 10,
                (init_data_size + init_code_size) >> 10, bss_size >> 10,
                (physpages - totalram_pages() - totalcma_pages) << (PAGE_SHIFT - 10),
                totalcma_pages << (PAGE_SHIFT - 10),
#ifdef  CONFIG_HIGHMEM
                totalhigh_pages() << (PAGE_SHIFT - 10),
#endif
                str ? ", " : "", str ? str : "");

2022/4/7

build static ps from source

git clone https://gitlab.com/procps-ng/procps.git
git chekcout v4.0.0
gettext,libncurses-dev,autopoint,libtool
./autogen.sh
./configure --disable-shared LDFLAGS=--static
make

2022/3/22

Bookmark : online gdb

onlinegdb

有趣的網站,線上各種語言的ide,但是可以進入 debug mode。
下面會出現 gdb 的 command prompt。
所以可以用來 test 小 code,語法。
也可以用來學習 gdb command

2022/3/21

Test Yolact

紀錄一下步驟,ref: 只是要test 一下 infer。

所以 create 一個 env,並且依照 ref:1 的說明安裝yolact 需要的 packages:
conda create --name yolact-3.7.9 python=3.7.9
conda activate yolact-3.7.9
pip install cypthon opencv-python pillow pycocotools matplotlib
然後 clone yolact project source:
git clone https://github.com/dbolya/yolact.git
然後download trained 好的 weights,在yolact 的 Evaluation 有download link。
選 yolact_resnet50_54_800000.pth
mkdir weights 並且 copy .pth 進去。

另外,安裝 pytorch,參考 ref:2
nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Wed_Oct_23_19:24:38_PDT_2019
Cuda compilation tools, release 10.2, V10.2.89
是 10.2,所以我要用 10.2
conda install pytorch torchvision cudatoolkit=10.2 -c pytorch
裝完測試一下:
python
>>import torch
>> torch.cuda.is_available()
True
OK. test infer:
python eval.py --trained_model=weights/yolact_resnet50_54_800000.pth --image=../test.jpg
source 的 save/load 只有做 weight 的部份。
所以要save model and weight 要自己改。
yolact.py : torch.save( )

2022/3/8

GT 740M, ubuntu 20.04, nvidia driver and cuda

driver 用 nvidia download and install 的話,他會叫你用 distribution 提供的。
因為這個 card 太舊了。
如果一樣安裝得話,會抱怨 kernel 用的 gcc 版本和driver 不一樣,
加入 ignore_cc_mismatch 後,build fail,一堆 function reference error

證明這個 driver source 沒有隨著 kernel 更新...

最後只好用 local script 安裝。結果都還是 fail。
fail log: /var/log/cuda-install.log,只有說 driver install failed

網路上說,/var/log/nvidia-install.log 有 driver install fail 的 log,
果然...
說是 /usr/lib/nvidia 下有 alternate-install-availeble,所以 abort

把 /usr/lib/nvidia rename 後,一樣 fail,/var/log/nvidia-install.log 說 因為有用 Nouveau driver。
所以他寫了 nvidia-install-disable,讓 nouveau 部會load。

reboot 後再 run, 一樣 fail, nvidia-installer.log 說..
NVRM: API mismatch: the client has the version 510.47.03, but this kernel module has version 470.57.02.
Please make sure that this kernel module and all NVIDIA driver compoments have the same version
所以 apt purge libnvidia-**

看到有一些 510 utility remove,結果一樣..

結論:

nvidia 的 script/deb 都沒有依照險卡決定安裝版本的功能,一律安裝最新版。
但是在nvidia 的網站,可以看到,每個險卡最新的 driver 不一樣。
以 GT 740M 來說,只有到 470,但是現在最新的 driver version 是 510 了。

而 cuda 版本右跟 driver 版本相關。
最新的 cuda 11.6 需要 driver 版本 510。

所以 GT 740M 就不能用 cuda 11,.6 了,因為 driver 版本不支援。
所以只能選(test install)到 cuda 11.4.1

--- 結果做完 apt upgrade 又 fail 了,好像 tool 去用到 510 的版本。



因為 510 (cuda_11.6 安裝) 的 tool, library 一直留在系統,移除不完整。
只好重新安裝系統,之後:
  • 開啟 softare and updater 中 "Additional",nvidia 用 propritry 的 driver 版本 470
  • 執行 cuda 11.4 local shell script,但是不安裝 driver
完成。
這樣 nvidia driver 會放到 dkms 管理,升級 kernel 時也會自動重 build initramfs,不會發生上面 update kernel 後,nvidia driver 沒有 load 的情況。


20.04 超容易 boot fail..
dev/sda1: clean, 552599/6111232 files, 7119295/24414464 blocks
follow 這一頁 的說明。
開機按下shift,啟動 grub menu,進入recovery mode。
然後
apt-get purgr nvidia*
如果是不小心把X 杉了,也會是這樣的 error,就要 apt reinstall ubuntu-desktop
這樣開進desktop gui 後,network-manager 會要修改,把 ethernet 加回去。ref:networkmanager not show
lanaguage input method 也要再 install, reboot

這樣開進desktop gui 後,bluetooth 連不上 Airpod pro,這一篇 說,要開啟 br/edr mode。
照著修改 /etc/bluetooth/main.conf:
ControllerMode = bredr
or 
ControllerMode = dual
之後,就可以連上了。