2020/12/26

cuDNN

cuDNN 下載頁面,會要求輸入,完成後,確認一些...
最後就會出現 cuda versio -- 對應的 cuDNN 版本的頁面。

所以 cuDNN 不能亂裝,跟 cuda 的版本有關。

像我的cuda 是 10.2,所以:
Download cuDNN v8.0.5 (November 9th, 2020), for CUDA 10.2
Library for Linux, Ubuntu(x86_64 & PPC architecture)
cuDNN Library for Linux (x86)
cuDNN Library for Linux(Power)
cuDNN Library for Windows10 (x86)
cuDNN Runtime Library for Ubuntu18.04 (Deb)
cuDNN Developer Library for Ubuntu18.04 (Deb)
cuDNN Code Samples and User Guide for Ubuntu18.04 (Deb)
cuDNN Runtime Library for Ubuntu16.04 (Deb)
cuDNN Developer Library for Ubuntu16.04 (Deb)
cuDNN Code Samples and User Guide for Ubuntu16.04 (Deb)
所以可以知道..cuda10.2 跟 cuDNN 只有 support 到 ubuntu 18.04
ubuntu20.04 要用 cuda11.x
要選下面:cuDNN Archive,才會有對應Cuda 版本跟各平台的 lib, sample dev 的 deb 可以下載。


下載了 runtime library 跟 developer library

然後下載畫面說,到install guide 去看 cuDNN 安裝說明。
其中 deb 的安裝...
2.3.2. Debian Installation
Before issuing the following commands, you'll need to replace x.x and 8.x.x.x with your specific CUDAand cuDNN versions and package date.

Procedure:

Navigate to your <cudnnpath> directory containing the cuDNN Debian file.

Install the runtime library, for example:

 $ sudo dpkg -i libcudnn8_x.x.x-1+cudax.x_amd64.deb

Install the developer library, for example:

 $ sudo dpkg -i libcudnn8-dev_8.x.x.x-1+cudax.x_amd64.deb

Install the code samples and the cuDNN library documentation, for example:

 $ sudo dpkg -i libcudnn8-samples_8.x.x.x-1+cudax.x_amd64.deb

安裝後,驗證測試的方法(一樣是cuDNN官網
Copy the cuDNN samples to a writable path.

 $cp -r /usr/src/cudnn_samples_v8/ $HOME

Go to the writable path.

 $ cd  $HOME/cudnn_samples_v8/mnistCUDNN

Compile the mnistCUDNN sample.
 
 $make clean && make

Run the mnistCUDNN sample.

 $ ./mnistCUDNN

If cuDNN is properly installed and running on your Linux system, you will see a message similar to the following:

 Test passed!
有一個 example 缺 freeimage,所以要 install : libfreeimage3 libfreeimage-dev

ubuntu 18.04 之後的 apt 已經support install local deb.
所以可以用 apt install ./xxx.deb 來安裝,然後一樣,用apt purge 來 remove

另外,caffe 只support cudnn7,用cudnn8 會build error..

2020/12/25

shell script 中處理字串的符號

字串處理、字串合併、字串大小寫轉換

#!/bin/bash
test="0123aabbcc!q1234.ww" 
filename="Jerry_20130731.tar.gz" 
echo "原始字串 $test" 
echo "取出字元位置 2 開始取 5 的字元 : ${test:2:5}" 
echo "尋找符合的字串 12 -> #*12 = ${test#*12}.... #*12 = ${test##*12}" 
echo "取出檔名 %%.* = ${filename%%.*} ... %.* = ${filename%.*}" 
echo "取出特定特徵 %%!q* = ${test%%!q*}" 
echo "取出特定特徵 ##*. = ${test##*.}" 
xcombine=${test%%!q*}"---"${test##*.} 
echo "字串合併 %%!q* + ##*. = $xcombine" 
echo "大小寫轉換"ABcD | tr [A-Z] [a-z]
執行的結果:

原始字串 0123aabbcc!q1234.ww
取出字元位置 2 開始取 5 個字元 : 23aab
尋找符合的字串 12 -> #*12 = 3aabbcc!q1234.ww.... #*12  = 34.ww
取出檔名 %%.* = Jerry_20130731 ... %.* = Jerry_20130731.tar
取出特定特徵 %%!q* = 0123aabbcc
取出特定特徵 ##*. = ww
字串合併 %%!q* + ##*. = 0123aabbcc---ww
大小寫轉換abcd

2020/12/15

GPIO, blocking read with poll.

ref:
sys 裡面的 gpio property 有一項:edge。
用來設定 interrupt
配合 poll( ) ,可以作到 blocking read,這樣就不用一直 read (polling)

gpio 的 edge 有以下幾個可以設:
  • rising
  • falling
  • both
  • none
對 edge 寫入這幾個以外的值,會回報 error

實測結果,falling 跟 both 的效果一樣。

設完之後,對 gpio 的 value 做 polling 舊可以。

就像這一篇 的說明一樣:
# echo 4      >/sys/class/gpio/export
# echo in     >/sys/class/gpio/gpio4/direction
# echo rising >/sys/class/gpio/gpio4/edge
然後舊可以 poll..

有幾項要注意:
  • 先 read 一次,把上次 trigger 的 event 清空,之後再 poll
  • poll 的 event 是 POLLPRI,不是 POLLIN
  • 要清除 event 要做 read,之前要先 seek 回 file begin

修改好,test OK 的 example 在

2020/12/4

ulimit, core dump and gdb

Black 教的。想不到,很古老以前就有了。

程式執行錯誤,core dump 時,會受dump file 大小限制。
這是 kernel 的 參數。
用 ulimit 可以列出一堆 kernel 參數。
其中 -c 就是 core dump 的 size limit
$ulimit -c
0
$ulimit -c unlimited
unlimited
-- 系統原來是 0 (不存 core dump file),改成 unlimited, 全部都存下來。

然後寫一個 會 core dump 的程式:
#include <stdio.h>
#include <stdlib.h>

int main()
{
   int *A = NULL;
   
   *A = 0x01;
   
   return 0;
}

compile with -g option (debug ON)..
gcc -g main.c
然後執行 a,out,產生 core dump..
之後,啟動 gdb 吃下 core dump file (core) 跟 執行檔(含 debug symbol):
gdb -c core a.out
...
..
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000aaaaac4a66f4 in main () at main.c:8
8		*A = 10;
會停在發生 core dump 的 code..
然後舊可以用 gdb command 來看 source (l), backstrace (bt), 看變數 (p *A)...

這個 core 跟平台有關,所以在 arm 上產生的 core file,拿到 x86 來看的畫,要用 cross-tool 的 arm gdb 來啟動。


一些 gdb 的操作

2020/12/2

Makefile = := ?=

這一篇 說的很仔細。

make 是先解析完整個 Makefile。
然後再去執行 target 的 rule。

所以變數的值就會隨著..解析的到的位置,rule 的時間,而不一樣。
這些 = := ?= 就是來決定變數要怎麼決定(什麼時間決定)內容。

=  解析中可以改變
:= 當下決定

2020/11/25

regmap 的 reg_defaults

在 宣告 regmap_config 時,會又 reg_defaults 這個欄位。
這是說明 chip reset 後的 register default value。
並不是要 regmap 做初始話時,寫入的 value。

所以修改 reg_default[] 內的值,並不會跟心的 真正的 chip 上。

保險的作法是在 driver probe 時,把 default register 全部寫一次。

dreamsourcelab LA on WM8974 I2C decode

dreamsourcelab 的 LA 很有趣。
PC 端的軟體是 opensource 的。
所以在 linux 上使用的話,要clone github project,然後 configure, make ...



有 LA 的 decode 功能,幫你 decode 。

向上面就是 I2C 的波型。

decode 完可以 log。

上面就是做 WM8974 的 I2C log。

wm8974 因為只能 write,不能 read,所以沒變法確認write OK

用 LA log,然後寫一個程式update 每個 register 的 final value:
memo 一下 DSView 的操作:
  • 可以指定 log 的時間 (10sec),然後安下 play 開始 log
  • 滾輪是 zomm in/out
  • decode 出現的 dialog,指出要 decode 的 probe data (SDA, SCL)
  • decode 的 save 圖示,把 decode 完的結果 log 成 file

2020/11/20

wpa_supplicant & wpa_cli

ref:

wpa_supplicant
network 設定中:
mode
0 : infrastructure,預設值,會嘗試連結AP
1 : IBSS,ad-hoc, peer to peer
2 : AP
另外,
ap_scan:
0 : scan, 不connect
1 : scan, 找不道的話,舊自己當 AP
2 : scan, and connect

wpa_supplicant 的 config 檔,其中的 network { }區段。對應的就是 wpa_cli 的 add_network , set_network
所以 config 的內容,都可以用 wpa_cli 設定。

sendmail - 送不出..

phabricator 用 sendmail 寄公司內部信。
然後錢一陣子轉 vm 後,有人收不到 phabricator 的通知了。(據說是所有人都收步道..)

先看一下 /var/log/syslog...
...
Nov 20 11:20:01 franxx sm-msp-queue[9753]: My unqualified host name (franxx) unknown; sleeping for retry
Nov 20 11:21:01 franxx sm-msp-queue[9753]: unable to qualify my own domain name (franxx) -- using short name
Nov 20 11:24:34 franxx systemd[1]: Started Session 3645 of user darling.
Nov 20 11:39:01 franxx CRON[11008]: (root) CMD (  [ -x /usr/lib/php/sessionclean ] && if [ ! -d /run/systemd/system ]; then /usr/lib/php/sessionclean; fi)
Nov 20 11:39:01 franxx systemd[1]: Starting Clean php session files...
Nov 20 11:39:01 franxx systemd[1]: Started Clean php session files.
Nov 20 11:39:23 franxx sendmail[11087]: My unqualified host name (franxx) unknown; sleeping for retry
...
但是這個好像不影響,只是會慢一點。..

看一下sensmail 狀況..
$ sudo systemctl status sendmail
● sendmail.service - LSB: powerful, efficient, and scalable Mail Transport Agent
   Loaded: loaded (/etc/init.d/sendmail; bad; vendor preset: enabled)
   Active: active (running) since Mon 2020-10-26 14:14:32 CST; 3 weeks 3 days ago
     Docs: man:systemd-sysv-generator(8)
  Process: 1223 ExecStart=/etc/init.d/sendmail start (code=exited, status=0/SUCCESS)
    Tasks: 1
   Memory: 4.4M
      CPU: 53.028s
   CGroup: /system.slice/sendmail.service
           └─1615 sendmail: MTA: accepting connections 
           ov 18 15:24:34 franxx sm-mta[2047]: 0AD7L1bD018430: 0AI7OYgC002047: postmaster notify: User unknown
Nov 18 15:24:34 franxx sm-mta[2047]: 0AI7OYgC002047: to=MAILER-DAEMON, delay=00:00:00, mailer=local, pri=0, dsn=5.1.1, stat=User unknown
Nov 18 15:24:34 franxx sm-mta[2047]: 0AI7OYgC002047: to=postmaster, delay=00:00:00, mailer=local, pri=0, dsn=5.1.1, stat=User unknown
Nov 18 15:24:34 franxx sm-mta[2047]: 0AI7OYgC002047: 0AI7OYgD002047: return to sender: User unknown
Nov 18 15:24:34 franxx sm-mta[2047]: 0AI7OYgD002047: to=MAILER-DAEMON, delay=00:00:00, mailer=local, pri=0, dsn=5.1.1, stat=User unknown
Nov 18 15:24:34 franxx sm-mta[2047]: 0AI7OYgC002047: Saved message in /var/lib/sendmail/dead.letter
Nov 18 16:21:01 franxx sm-mta[3039]: 0AI8L1XF003039: from=<>, size=2253, class=0, nrcpts=1, msgid=<202011180821.0AI8L1I1003037@franxx>, pr
Nov 18 16:21:01 franxx sm-mta[3039]: 0AI8L1XF003039: to=, delay=00:00:00, mailer=local, pri=32253, dsn=4.4.3, stat=queued
Nov 18 16:21:01 franxx sm-mta[3039]: 0AI8L1XH003039: from=<>, size=2259, class=0, nrcpts=1, msgid=<202011180821.0AI8L1I2003037@franxx>, pr
Nov 18 16:21:01 franxx sm-mta[3039]: 0AI8L1XH003039: to=, delay=00:00:00, mailer=local, pri=32259, dsn=4.4.3, stat=queued
狀態正常,但是都記不出去。

看一下 phabricator: ref:testing outbound:
phabricator/ $ ./bin/mail list-outbound   # List outbound mail.
phabricator/ $ ./bin/mail show-outbound   # Show details about messages.
phabricator/ $ ./bin/mail send-test       # Send test messages.
看一下out-bound...
XXX:/opt/phabricator$ ./bin/mail list-outbound
263 Sent   D163: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
264 Sent   D162: Fix 2 issues.
265 Sent   D162: Fix 2 issues.
266 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
267 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
268 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
269 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
270 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
271 Sent   D164: Fix: If low battery, the alert sound keep ringing in security screen after PND resume.
...
284 Sent   D167: Fix 3 suspend/wakeup issues.
285 Sent   D167: Fix 3 suspend/wakeup issues.
286 Sent   D168: Fix 3 suspend/wakeup issues.
287 Sent   D168: Fix 3 suspend/wakeup issues.
288 Sent   D167: Fix 3 suspend/wakeup issues.
289 Sent   D167: Fix 3 suspend/wakeup issues.
290 Sent   D168: Fix 3 suspend/wakeup issues.
291 Sent   D168: Fix 3 suspend/wakeup issues.
292 Sent   D168: Fix 3 suspend/wakeup issues.
293 Sent   D168: Fix 3 suspend/wakeup issues.
294 Sent   D167: Fix 3 suspend/wakeup issues.
295 Sent   D167: Fix 3 suspend/wakeup issues.
果然queue住一堆..


測試一下 sendmail 吧。(ref:how to test sendmail)
$ echo "from franzz" | sendmail -v charles.chang@localtek.com
WARNING: local host name (franxx) is not qualified; see cf/README: WHO AM I?
localtek.com: Name server timeout
charles.chang@localtek.com... Transient parse error -- message queued for future delivery
charles.chang@localtek.com... queued
果然,是 dns 的問題。

轉到 vm 時,dns 沒設定,所以沒動作,test ping google 也 fail
所以把 dns 設好後用 sendmail 測試 OK

2020/11/17

regmap, 有關沒對齊的 reg, value bits 的 i2c transfer function.

regmap.c 中有...
    switch (config->reg_bits + map->reg_shift) {

    ...
    
    case 7:
        switch (config->val_bits) {
        case 9:
            map->format.format_write = regmap_format_7_9_write;
            break;
然後
static void regmap_format_7_9_write(struct regmap *map,
                    unsigned int reg, unsigned int val)
{
    __be16 *out = map->work_buf;
    *out = cpu_to_be16((reg << 9) | val);
}


所以wm8974 的 code:
static const struct regmap_config wm8974_regmap = {
    .reg_bits = 7,
    .val_bits = 9,

的確可以送出 follow wm8974 奇怪 protocol 的格式。

2020/11/14

ubuntu - unattended-upgrade, 有點煩

太煩了。把 unattended-upgrade 移除了,
如果不是每天開機,用這格反而麻煩。
偶額開機要用,要安裝 package,他卻卡住dpkg lock 好久...

每天開機的機器可能比較適合,他會自動安排更新時間。

2020/11/13

inode and partition space

在disk partition 中要能create 新檔,除了要有剩餘空間外,還有有inode 剩下才行。
一般用 df
# df -i
Filesystem              Inodes      Used Available Use% Mounted on
/dev/root                 3.6K      3.5K        66  98% /
devtmpfs                 23.6K       353     23.2K   1% /dev
tmpfs                   124.6K         1    124.6K   0% /dev/shm
tmpfs                   124.6K       384    124.2K   0% /run
tmpfs                   124.6K         6    124.6K   0% /sys/fs/cgroup
tmpfs                   124.6K         8    124.6K   0% /tmp
tmpfs                   124.6K         5    124.6K   0% /var/tmp
/dev/mmcblk0p8               0         0         0   0% /data
tmpfs                   124.6K         4    124.6K   0% /run/user/0

# df 
Filesystem                Size      Used Available Use% Mounted on
/dev/root               504.4M    422.5M     51.8M  89% /
devtmpfs                 94.2M         0     94.2M   0% /dev
tmpfs                   498.4M         0    498.4M   0% /dev/shm
tmpfs                   498.4M    268.0K    498.1M   0% /run
tmpfs                   498.4M         0    498.4M   0% /sys/fs/cgroup
tmpfs                   498.4M      4.0K    498.4M   0% /tmp
tmpfs                   498.4M         0    498.4M   0% /var/tmp
/dev/mmcblk0p8            6.6G      1.0M      6.6G   0% /data
tmpfs                    99.7M         0     99.7M   0% /run/user/0
像 df -i 中,/dev/root 已經用掉 98%,剩下 66 個 inode。
touch 66 個 file 後,inode 剩下 0
這時候,就算是 df 中 /dev/root 還有 50M 的空間,也沒辦法再 create 新檔了。

另外,..
du --inode folder
也會列出 folder 內的inode 用量。
其中根目錄會列出subfolder 的inode 用量總和。


如果是慢慢漲起來的..可以用 find . 然後依照 file time sorting,找出新增的檔案...
find . -type f -name '*.kk' -printf "%T+ %p\n" | sort

一般embedded system 是在 rootfs 遭遇這個問題,rootfs 又是一個 block device,用 loopback 做出來。
可以用tune2fs 來看,不用真的 mount 起來..
$ tune2fs -l ext4 
tune2fs 1.44.1 (24-Mar-2018)
Filesystem volume name:   
Last mounted on:          
Filesystem UUID:          a34e7a5d-cb27-4f62-bdce-3d68b3e55537
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal dir_index extent
Filesystem flags:         signed_directory_hash 
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Unknown (continue)
Filesystem OS type:       Linux
Inode count:              3712
Block count:              468226
Reserved block count:     23411
Free blocks:              29952
Free inodes:              129
First block:              1
Block size:               1024
Fragment size:            1024
Blocks per group:         8080
Fragments per group:      8080
Inodes per group:         64
Inode blocks per group:   8
Last mount time:          n/a
Last write time:          Thu Oct 29 11:30:35 2020
Mount count:              0
Maximum mount count:      -1
Last checked:             Thu Oct 29 11:30:19 2020
Check interval:           0 ()
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:	          128
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      0e89286e-5c9d-4f0c-9aad-37b2cd127b29
Journal backup:           inode blocks

ref:

2020/11/12

紀錄 make, linking with libnl-3...

 fatal error: netlink/genl/genl.h: No such file or directory
 #include <netlink/genl/genl.h>

找一下..因為已經有 install lib-nl-3-dev 了...
apt-file search genl.h
..
libnl-3-dev: /usr/include/libnl3/netlink/genl/genl
所以修改 Makefile..
加入
CFLAGS += -I/usr/include/libnl3

然後出現..
/usr/bin/ld: cannot find -lnl-genl-3

然後一樣用 apt-file
apt-file search libnl-genl

libnl-genl-3-dev: /lib/aarch64-linux-gnu/libnl-genl-3.a
libnl-genl-3-dev: /lib/aarch64-linux-gnu/libnl-genl-3.so

但是用 find ..
$ sudo find . -name libnl-genl*
./lib/aarch64-linux-gnu/libnl-genl-3.so.200.24.0
./lib/aarch64-linux-gnu/libnl-genl-3.so.200
./var/lib/dpkg/info/libnl-genl-3-200:arm64.symbols
./var/lib/dpkg/info/libnl-genl-3-200:arm64.triggers
./var/lib/dpkg/info/libnl-genl-3-200:arm64.list
./var/lib/dpkg/info/libnl-genl-3-200:arm64.md5sums
./var/lib/dpkg/info/libnl-genl-3-200:arm64.shlibs
./usr/share/doc/libnl-genl-3-200
所以.. 自己建 link ?:
姊果一直說 fail,沒版法建,只好直接 copy, rename..
cp libnl-genl-3.so.200.24.0 libnl-genl-3.so
之後再 make 舊 OK

WM8974 , 奇怪的 audio codec..

在linux kernel 中,很久以前,就有 wm8974 的 driver 了。
datasheet 看到這個不叫 i2c,叫 2 wire。

從 2 wire command diagram 來看.. 的確很奇怪:

address 部份跟一般 i2c 一樣,前 7 個是 address,最後一個 bit 是 read/write bit
接著是 reg , 只有 7 bit,所以最後一個 bit 是 data 的 highest bit

wm8974 的 reg 只有 7 bit,data 有 9 bit
register value 說明也真的有定義第9bit..

所以 i2c protocl:
1: chip address(7)+R/W(1)
2: reg index(7) + Data 8th bit(1)
3: Data 7-0 bit (8)
跟一般 I2C 裝置不一樣。

因為這樣,wm8974 沒有 read 動作。
也就是說,不能 read register。 --- 不然 protocol 要怎樣....



Linux driver 的部份:

古老的 wm8974 driver 使用自己提供的 i2c_read, i2c_write,看得出這個奇怪的動作:
static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec * codec,
	unsigned int reg)
{
	u16 *cache = codec->reg_cache;
	if (reg == WM8974_RESET)
		return 0;
	if (reg >= WM8974_CACHEREGNUM)
		return -1;
	return cache[reg];
}

/*
 * write wm8974 register cache
 */
static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec,
	u16 reg, unsigned int value)
{
	u16 *cache = codec->reg_cache;
	if (reg >= WM8974_CACHEREGNUM)
		return;
	cache[reg] = value;
}

/*
 * write to the WM8974 register space
 */
static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int value)
{
	u8 data[2];

	/* data is
	 *   D15..D9 WM8974 register offset
	 *   D8...D0 register data
	 */
	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
	data[1] = value & 0x00ff;

	wm8974_write_reg_cache (codec, reg, value);
	if (codec->hw_write(codec->control_data, data, 2) == 2)
		return 0;
	else
		return -EIO;
}
i2c_write 內容有看到把 data shift 到 reg 一個bit
然後沒有提供 i2c_read

然後 driver 註冊時...
static int wm8974_init(struct snd_soc_device *socdev)
{
	struct snd_soc_codec *codec = socdev->codec;
	int ret = 0;

	codec->name = "WM8974";
	codec->owner = THIS_MODULE;
	codec->read = wm8974_read_reg_cache;
	codec->write = wm8974_write;
..
read 用的是 read_reg_cache



然後新版的kernel (3.1 以上),新增加了 regmap 這個 結構,
就是把 register map cache 起來,write 時同時更新 cache,
read 時就拿 cache 值,不用真的去 read。
-- 當然也可以真的去 read

同時 regmap 也增加了 reg_bits, val_bits 這兩個 properties。
所以新版的 wm8974 driver,已經有:
static const struct regmap_config wm8974_regmap = {
    .reg_bits = 7,
    .val_bits = 9,

    .max_register = WM8974_MONOMIX,
    .reg_defaults = wm8974_reg_defaults,
    .num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
    .cache_type = REGCACHE_FLAT,
};

比較漂亮的寫法就是用regmap : regmap, 有關沒對齊的 reg, value bits 的 i2c transfer function.

用了 regmap,cache type 用 FLAT,就會 使用 cache,這樣,read 就會從 cache 做,
這時候,要 dump register 舊只能用 regmap support 的地方:
# cat /sys/kernel/debug/regmap/2-001a/registers 
00: 0000
01: 002e
02: 0000
03: 0000
04: 0010
05: 0001
06: 0120
07: 0000
08: 0000
09: 0000
0a: 0041
0b: 00d7
0c: 0000
0d: 0000
0e: 0100
0f: 00ff
10: 0000
11: 0000
12: 012c
13: 002c
14: 002c
15: 002c
16: 002c
17: 0000
18: 0032
19: 0000
1a: 0000
1b: 0000
1c: 0000
1d: 0000
1e: 0000
1f: 0000
20: 0038
21: 000b
22: 0032
23: 0000
24: 001b
25: 0001
26: 0133
27: 0066
28: 0000
29: 0000
2a: 0000
2b: 0000
2c: 0003
2d: 0010
2e: 0000
2f: 0000
30: 0000
31: 0002
32: 0000
33: 0000
34: 0000
35: 0000
36: 0025
37: 0000
38: 0001

2020/11/11

Face Recognition : FAR and FRR

ref: 在臉部辨識上提到的這兩個名詞
  • FAR : False Acceptance Rate
  • FRR : False Rejection Rate
Face recognition 用的手都是參數化的方法,NN 把臉部圖形轉成一組 128 個數值的向量。
和 data base 中每個人的 參數比較,計算出"引力"(距離平方反比),跟誰引力最大,就是誰。

但是也有 "不認識","不屬於 database 中" 的情況出現。
這時候,就要把 "距離" 加上一個 threshold,要引力大於這個值才算,否則就是 "不認識" 的人。

而這個 threshold 舊決定了 FAR 跟 FRR。

FAR 隨著threshold 增加而降低。
FRR 隨著threshold 增加而增加。

兩個剛好在左右兩端達到最大。
所以最佳 threshold 的值就是 FAR, FRR 都最小的中間數值。



感想:看完上面ref 的內容,感覺 face recognition 蠻不准的....

2020/11/10

bookmark : CRA (Chief Ray Angle)

Image Sensor 用的參數。

Image Sensor 的每個 pixel 上都會有一個 micro-lens。
micro-lens 用來聚焦光線到 pixel 上。

lens 有 FOV (field of view),所以必須要和外接的鏡頭搭配,讓經由鏡頭篇折的光線,進入 micro-lense 後,能夠正確的落在 pixel 上。
如果沒有批配的話,光線進入 micro-lense 後,就會落掉旁邊的 pixel ,造成雜訊點或是影像失真。

所以 sensor 的 CRA 必須要和鏡頭設計一起考慮。


實際測試的姊果,lens fov 與 CRA 符合的 camera,影像較 CRV 0 的清楚很多,相較起來,CRV0 的影像好像是對焦沒對好。

2020/11/8

opencv document: cross build

這篇很詳細講opencv cross build for arm 的方法,基本上和上次寫的cmake cross build 的方法一樣。
opencv 寫好了platform,XXX.cmake。
所以只要準備好要的cross-tool,然後用opencv 的 toolchain cmake 就可以。

其他如果有需要的library,可以參考上次寫的。放在set_ 裡面。

其實embeddes system opencv port,比較重要的是 bsp 有沒有hardware support,還有opencv 要怎麼link 到 bsp 的hardware 加速library。
另外,還要build 出 python support module,放在target system 得 python class loading path 中,這樣 target system 的 python 才能 import。

python 3 and opencv3.4.2 ..imshow fail. --- centor of contours

一個 imshow 就 fail 掉:
cv2.error: OpenCV(3.4.2) /tmp/build/80754af9/opencv-suite_1535558553474/work/modules/highgui/src/window.cpp:632: 
error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. 
If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, 
then re-run cmake or configure script in function 'cvShowImage'

結果follow 這一個:
conda remove opencv
conda install -c conda-forge opencv=4.1.0
..意思是說..3.4.2 板的沒有enable WITH_GTK=ON ?

haha 6 月的時後,已經發生過了...

另外,很有趣,python 因為可以return tuple type,所以function 把 rc code(success, fail) 和 process result 包成一個 tuple 傳回來。
所以,以 opencv 的 threshold( ) function:
rc, out = cv2.threshold(blurred,60,255,cv2.THRESH_BINARY)
rc 是 成功或失敗,out 是 threshold 處理以後的結果。
如果要直接拿結果,不管成功失敗,可以直接取 tuple 的 elememt:
out = cv2.threshold(blurred,60,255,cv2.THRESH_BINARY)[1]


依照這篇文章,利用findContour找出輪廓,再用moments 找出輪廓中心座標的 code,在: 加上了最小面積偵測,如果太小就不採用。(實際上是遭遇到雜訊點面積為0的錯誤)
另外,為了考慮能porting 到 embedd system,所以拿掉而外的 module。
參考文章說的,findcontours 的傳回格式跟opencv 版本有關。

這一篇是同樣方法的中文版本,說得更清楚,也有用實際照片做例子
-- 看起來這是標準的方法...

這一篇是用C++的example,如果python porting 不上去,或是 bsp 的 opencv port 沒有support python時,可以用C++做。
-- 參考他的作法,改成跟python 版 一樣的 algorithm 版本的 C++ code,一樣在 github project 中。

沒用用到什模特殊的,最後一個 commit,把 show image 的部份刪除就可以在 target board 上 run 了,用存檔來檢查每一個 process 的結果。

2020/11/6

pthread return value

pthread 可以 return value 給 parent process (who create it)
這個 方法:
#include <pthread.>
#include <stdio.h>
void *myThread()
{
   printf("in thread now\n");
   return (void *) 42;
}

int main()
{
   pthread_t tid;
   int status;

   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, (void*)&status);

   printf("%d\n",status);   

   return 0;
}  
 
.. 這個 status 的宣告...
要測試 一下..

等等... 感覺怪怪的...
因為 return 一個 cast 成 (void*) 的 scalar value
...
要是看這一篇的話,thread要為return value alloc一塊記憶體,不能隨thread 退出兒消失。
經由把指標return 給 creator 後,creator 負責 free 掉。


有關 return 跟 exit() :
這一篇說明看起來好可怕...
對C++來說,return 會 call 所有 local scope 物件的 destructor,一一release 完再結束,而exit( )不會這樣做,它直接結束。
-- 可以寫sample code 試試,看看 1.不寫 2.return 3.exit( ) 對於 local 物件有蛇麼差別。


實際上用 g++ -S main.cpp 產生 assembly file 來看有 return 跟沒 return 的差別。
只插在 有return 的,多一個 intruction 把 return value 放到 eax,沒return 的,就放一個 nop (為什麼要放?)

add read/write function in i2c_client driver function

snd_soc_codec_driver
裡面有:
  • write : i2c_write
  • read : i2c_read
如果沒有指定,就會用 platform 內的。

所以如果想要 debug snd_soc_code driver,知道該 driver 對 i2c 的動作。
可以自己寫 i2c_read, i2c_write 放進去。
static unsigned int my_i2c_read(struct snd_soc_codec *codec, unsigned int reg)
{
    struct my_priv *mypriv = snd_soc_codec_get_drvdata(codec);
    int ret = -1; 
    unsigned char tx[1], rx[1];

    struct i2c_msg xfer[2];
    struct i2c_client *client = mypriv->i2c;

    tx[0] = reg;
    rx[0] = 0;

    /* Write register */
    xfer[0].addr = client->addr;
    xfer[0].flags = 0;
    xfer[0].len = 1;
    xfer[0].buf = tx;

    /* Read data */
    xfer[1].addr = client->addr;
    xfer[1].flags = I2C_M_RD;
    xfer[1].len = 1;
    xfer[1].buf = rx;

    ret = i2c_transfer(client->adapter, xfer, 2);

    if (ret != 2)
        printk("\t%s error ret = %d\n", __func__, ret);

    return (unsigned int)rx[0];

}

static int my_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
                unsigned int value)
{
    struct my_priv *mypriv = snd_soc_codec_get_drvdata(codec);
    int ret = -1;
    unsigned char tx[2];
    size_t  len = 2;

    if(reg==1)
        value |= 0x02; // don't power off spk 

    tx[0] = reg;
    tx[1] = value;

    printk("\t %s: (addr,data)=(%x, %x)\n", __func__, reg, value);

    ret = i2c_master_send(mypriv->i2c, tx, len);

    if (ret != len)
        return -EIO;

    return 0;
}
但是要struct my_priv 要把 probe 時,register 的 i2c client 田進變數
struct my_priv {
    struct i2c_client *i2c;
     ...
然後 module probe function...
static int my_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
    struct my_priv *mypriv;
    mypriv = devm_kzalloc(&i2c->dev. sizeof(struct my_priv), GFP_KERNEL);
    
    i2c_set_client_data(i2c, mypriv);
    mypriv->i2c = i2c;
    ...
這樣,這個 driver call snd_soc_read/write 時,就會 call 到 自己的 i2c_read/write function.
然後舊可以加 debug message...
但是這樣舊沒用到 regmap,所以 sys/kernel/debug/regmap/XXXX/registers 的內容不會顯示。

2020/11/5

nginx : get auth failcount behind proxy

proxy 後方的 restful server 要知道nginx 端 login fail 的次數。
可能要參考這一篇。
改用 auth_request module.
然後把 fail 頁面倒到令一個 restful api 上,並且把 failcount 放進 parameters..

.. 還沒試過..

使用 auth_request 的方法。可以參考這一篇

或是用 basic_auth,然後在 error page 時,導到 resetful server. 大概是這樣做

2020/11/3

記 一下 i2c tool 的動作, i2cget , i2cset

其實單獨執行。不加 argument 的時候,都會有 help.

# i2cdetect 
BusyBox v1.31.1 (2020-02-18 12:01:00 CST) multi-call binary.

Usage: i2cdetect -l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]

Detect I2C chips

	-l	List installed buses
	-F BUS#	List functionalities on this bus
	-y	Disable interactive mode
	-a	Force scanning of non-regular addresses
	-q	Use smbus quick write commands for probing (default)
	-r	Use smbus read byte commands for probing
	FIRST and LAST limit probing range


# i2cdetect -y -a 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- UU -- -- -- -- -- UU -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 


# i2cdump 
BusyBox v1.31.1 (2020-02-18 12:01:00 CST) multi-call binary.

Usage: i2cdump [-fy] [-r FIRST-LAST] BUS ADDR [MODE]

Examine I2C registers

	I2CBUS	I2C bus number
	ADDRESS	0x03-0x77
MODE is:
	b	Byte (default)
	w	Word
	W	Word on even register addresses
	i	I2C block
	s	SMBus block
	c	Consecutive byte
	Append p for SMBus PEC

	-f	Force access
	-y	Disable interactive mode
	-r	Limit the number of registers being accessed


# i2cdump -fy 2 0x12
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: c9 06 48 01 60 50 0b 23 00 00 60 00 e1 e1 f0 00    ??H?`P?#..`.???.
10: 18 1e fc fc fc fc 07 03 03 d0 1f 60 20 00 10 00    ???????????` .?.
20: 00 0f 33 05 10 29 22 f6 bd 00 73 3e 79 e1 1d 03    .?3??)"??.s>y???
30: 92 39 3a e6 00 10 f1 1d 00 00 00 00 00 00 00 00    ?9:?.???........
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................


# i2cget
BusyBox v1.31.1 (2020-02-18 12:01:00 CST) multi-call binary.

Usage: i2cget [-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]

Read from I2C/SMBus chip registers

	I2CBUS	I2C bus number
	ADDRESS	0x03-0x77
MODE is:
	b	Read byte data (default)
	w	Read word data
	c	Write byte/read byte
	Append p for SMBus PEC

	-f	Force access
	-y	Disable interactive mode


# i2cget -fy 2 0x12 0
0xc9
# i2cget -fy 2 0x12 1
0x06


# i2cset
BusyBox v1.31.1 (2020-02-18 12:01:00 CST) multi-call binary.

Usage: i2cset [-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]

Set I2C registers

	I2CBUS	I2C bus number
	ADDRESS	0x03-0x77
MODE is:
	c	Byte, no value
	b	Byte data (default)
	w	Word data
	i	I2C block data
	s	SMBus block data
	Append p for SMBus PEC

	-f	Force access
	-y	Disable interactive mode
	-r	Read back and compare the result
	-m MASK	Mask specifying which bits to write
# i2cset -fy 2 0x12 0 0xc8
# i2cget -fy 2 0x12 0
0xc8

clang, disable optimize for latter pass

這一篇,用 llvm-11 的話,opt 的指令沒有效。
stack overflow 有說。
在 compile 時,如果沒有加上 -O,在產生的 ll file, function 錢會有 optnone,避免 reg2mem 做 optimization:
; Function Attrs: noinline nounwind optnone uwtable
define i32 @add(i32, i32) #0 {
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 %0, i32* %3, align 4
所以 compile 時要加場上 -O
clang -S -emit-llvm -O  main.c
這樣就不會有 optnone 的標記:
; Function Attrs: norecurse nounwind readnone uwtable
define i32 @add(i32, i32) local_unnamed_addr #0 {
  %3 = add nsw i32 %1, %0
  ret i32 %3
}
但是也optimize 過了...

如果不要他先 optimize,又要加
clang -S -emit-llvm -O -Xclang -disable-llvm-passes main.c
這樣才能完成跟街學文章一樣的code
; Function Attrs: nounwind uwtable
define i32 @add(i32, i32) #0 {
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 %0, i32* %3, align 4, !tbaa !2
  store i32 %1, i32* %4, align 4, !tbaa !2
  %5 = load i32, i32* %3, align 4, !tbaa !2



最後,用 as 和 ld link 出 exeutable file,
要指定 crt1.o, crti.o,但是最終還是無法執行。

可能是 default library 的關係。
用 gcc assembly front-end 舊可以..
gcc main.s -no-pie -o main
用 -v 可以看一下 gcc ld 的 default crt.o 和 library
或許照著寫舊可以用 ld 成功 link..

這一篇 就是這樣做
ld -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 test.o  /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/gcc/x86_64-linux/4.3/crtbegin.o -lc /usr/lib64/gcc/x86_64-linux/4.3/crtend.o /usr/lib64/crtn.o
用了 ld-linux-x86-64.so crti.o crtbegin.o

依照 error mesaage,最後。minimum:
ld main.o /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o -lc
但是link 出來的 a.out 執行出現 'No such file or directory'

這一篇 的回答好像才是重點,interpreter 的問題。
用 gcc compile 的 a.out 和 ld link 出來的 a.out,用 readelf -l 看, interpreter 不一樣。

用 patchelf 的話..
$ patchelf --print-interpreter a.out 
/lib/ld64.so.1
$ patchelf --print-interpreter gmain 
/lib64/ld-linux-x86-64.so.2
不一樣。
實際上沒有 /lib/ld64.so.1
所以 Error message 是 'No sunch file or directory'

用 patchelf 設定正確的 interpreter;
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 a.out 
所以。最後,正確 ld 的 command 是:
ld -o a.out -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o -lc  /usr/lib/x86_64-linux-gnu/crtn.o main.

這一篇 有詳細講crtX.o 和 interpreter 之間的關係和實驗。

2020/11/2

https 基本原理

Browser, Server 都先準備好自己的 private/public key pair

  • Browser 透過 https 向 Server 發出 request
  • Server 把自己經過 CA 認證的 site.crt 送給 browser,(crt 裡面有 server 的 public key 和 CA 的 sign
  • Browser 收到 crt, 先用 CA 的 public key 確認 crt 裡,CA 的 sign 是正確的,還有 checksum 正確,代表 crt 沒被竄改
  • Browser 把 crt 裡的 public 拿出來,加密自己的 public key,送給 Server
  • Server 收到 Browser 的 public key 了
完成以上動作後,Browser, Server 就互相有對方的 public key 了。

兩人用對方的 public 加密送資料給對方。
對方就可以用自己的 private key 解開。

用 tls 通訊 Boost 的 example

boost asio 有 ssl 的 programming example: 但是沒有操作說明。

這一篇是 操作說明,可惜是以 windows 為 platform
.. 現在在 linux 上試試看。

這一篇 也有產生 key, crt 和example 修改的範例
這一篇用 boost asio ssl 模擬 browser 對 https 的 request 動作。



先亂寫一下...,不知道政不正確...

SSL certication
  • Cryptographic Key
  • server/domain , organization name
某網站的公鑰

然後這個 certication 是經果某個機構認證的。
機構:Cerfitication Authority (CA)

把自己的 public key 和自己的 location, domain name 包成 CSR (Certificate Signing Request) 格式,交給 CA
CA 會去檢查你是不是就是這個 CSR 內的 domain owner
-- 會要求你提供一堆資料。

CA 確認的話,CA 就會寄一份 SSL certification 給你,內容包含你的機構名稱,public key。
然後你就可以把這個SSL certication 放在你的 server 中。

CA 寄給你的 SSL certification 會包另一個 " trust root" 的 certification。

Browser 都會內建一堆 CA 機構的的 Root certification。
這樣舊知道你的 SSL certification 是不是真的。

browser 收到你用 private 加密的內容。
browser 有你的 SSL 憑證,包含一個CA root 的認證。好確保這個憑證是真的。
裡面有你的 public key,可以用來解開你用 private key 加密的內容。


CSR 送給 CA 機構,他確認正確後,就會把CSR 的資料斷做 checksum,然後用CA 自己的 private key 加密後,附在你的 CSR 後面。t
這就是CRT 了。
CA 會把 CRT 寄給你。


browser 都有內建一堆 CA 的 public key.
所以收到某網站的 CRT,他先用 CA 的 public key 確認這格 CRT 真的是 CA 認可(sign) 過得。
然後因為 checksum 的關係,。同時確認這格 CRT 沒有被修改。
這樣他就可以相信這個 CRT 裡的 public key 跟 domain 資料。
舊可以用 public key 來解開/確認這格 domain 用 private key 加密過後的資料。



openssl 可以作到所有的事,也可以用來列出 CSR, CRT, Key 的內容。

產生 private key
openssl genesa -out mypriv.key 4096
用private key 做出 CSR
openssl req -out mysite.csr -key mypriv.key -new



這一篇 使用 openssl 產生 private/public key pair。
然後各自加密檔案,再用對方解密。
同時還說明 crt 中用來 verify signature 的方法(command)


這一篇直接寫出command.
# Generate keys
openssl genrsa -out key.pem
openssl rsa -in key.pem -out key.pub -pubout

# Encrypt and Decrypt a file (using public key to encrypt)
echo --pass-- >> pass.txt
openssl rsautl -in pass.txt -out pass.enc -pubin -inkey key.pub -encrypt
openssl rsautl -in pass.enc -out pass.dec -inkey key.pem -decrypt
cat pass.dec

2020/10/29

hybrid : ISG : integrated Starter and Generator

先是 SUZUKI 說會出一款 hybrid,低價。
去看一下,基本沒什麼不同。
就是 以前 starter 的位置,變成一個 ISG
這個 ISG 就是 啟動器和發電機 一體。

因為 starter 連著傳動軸,所以也可以用來提供動力。
也因為連著傳動軸,所以也可以用來發電。

然後這種 hybrid 就是...
放開油門或是採煞車時,進入發電機模式,發出來的電,用來充鋰電池。
需要額外動力 (加速),或是啟動的時候,進入starter mode,利用鋰電池的電能,轉動 starter,提供動力。

這個 ISG 的位置,好像在離合器的地方,所以大部分目前的汽油車都可以改成這樣。
車上有兩顆電池,一個是以往的鉛酸電池,供發動汽油和一般(冷氣,大燈...etc)用。
另一棵是鋰電池。供 ISG 回充或是提供動力用。

原來依照使用電力的階段,可以分為 Micro. Mild,Full, Plugin (ref)

然後依照 ISG 與動力連接的方式,分為兩種: CiSG (crankshaft-integrated motor generator) 和 BiSG (belt-integrated starter generato)


依照這一篇(中文) 的說明,hybrid 的介入分類,是以ISG 能提供的動力來分類,同時,能提供的動力越多,ISG 的電壓也越高。

這一篇 有畫出 CiBG 與 cranshift 的關係,因為在引擎跟變速箱之間,有兩個離合器,所以可以隔離引擎。
ref:

2020/10/27

Boost asio http request, test with served

served 的 example : handler,有印出 post request 的 body..
    // GET or POST /handlers/{id}/{number:[0-9]+}
    mux.handle("/handlers/{id}/{number:[0-9]+}")

        .post([](served::response & res, const served::request & req) {
            res << "id: ";
            res << req.params["id"];
            res << ", number: ";
            res << req.params["number"];

            std::cout << "POST: " << req.body() << std::endl;
        })
先用 curl 測試一下...
參考這個,依照上面的 url path 修改一下...
curl -X POST -H "Content-Type: text/plain" --data "this is raw data" http123/handlers/id/123
結果 served example : eg_handler 正確送出:
$ ./eg_handlers 
Try this example with:
 curl http://localhost:8123/handlers
 curl http://localhost:8123/handlers/test
 curl http://localhost:8123/handlers/test/10
 curl http://localhost:8123/handlers/test/NaN
POST: this is raw data

對應的 tcp stream code:
#include <boost/asio.hpp>

int main()
{
	boost::asio::ip::tcp::iostream s("127.0.0.1","8123");
	s << "POST /handlers/test/10 HTTP/1.1\r\n";
	s << "Host: 127.0.0.1\r\n";
	s << "Content-Type: text/plain\r\n";
	s << "Content-length: 2\r\n";
	s << "\r\n";
	s << "bb\n";
	s << "\r\n";
}
使用上面修改過的 eg_handler 作為 REST server。可以正確..
Try this example with:
 curl http://localhost:8123/handlers
 curl http://localhost:8123/handlers/test
 curl http://localhost:8123/handlers/test/10
 curl http://localhost:8123/handlers/test/NaN
POST: bb
收到 body : bb

測試 PUT 命令:
用 served example : reset_resource,修改,印出body 和 parameter
   mux.handle("/customers/{id}")
        .get([](served::response & res, const served::request & req) {
            (void) res;
            (void) req;
            // read customer req.params["id"]
            std::cout << "get" << std::endl;
        })
        .put([](served::response & res, const served::request & req) {
            (void) res;
            (void) req;
            // update customer req.params["id"]
            std::cout << "put" + req.params["id"] << std::endl;
            std::cout << "header" << req.header("Content-Length") << std::endl;
            std::cout << "version" << req.HTTP_version() << std::endl;
            std::cout << req.body() << std::endl;
        })
對應使用 asio tcp stream 的 client code:
#include <boost/asio.hpp>

int main()
{
	boost::asio::ip::tcp::iostream s("127.0.0.1","8123");
	s << "PUT /customers/abc HTTP/1.1\r\n";
	s << "Host: 127.0.0.1\r\n";
	s << "Content-Type: text/plain\r\n";
	s << "Content-length: 2\r\n";
	s << "\r\n";
	s << "bb\n";
	s << "\r\n";
}
-- 其實跟 post 一樣…只是 url path 跟 request cmd 不一樣。
節果 eg_reset_resource 一樣正確取得 parameter 跟 body
putabc
header2
versionHTTP/1.1
bb

HOST: 可以不送。
重點是 content-type,沒有這個 key 得話,收不到 body
還有每一行都要是 \r\n 結尾,不可以只用 \n


有關 RESETful client server 的 debug..
client 可以用 curl 和 postman 來發送標準的 http request
然後用 whireshark log HTTP 來比對自己寫的 client 和 postman 送的有什麼不同。

順便記一下,httpie 是 command line 的 http api client, opensource 的
-- 其實或許跟 curl 一樣。

served 的 example,如果要對所有 nic interface 都listen 的話,就用 "0.0.0.0"
這樣舊可以用外部測試了。
-- ref:boost asio tcp server bind to any

programming with Boost library,

在 ubuntu 系統中使用 boost library
首先要安裝 boost dev library: libboost-all-dev

然後分為:

只有用到 boost 的 header: boostlambda.cpp
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;

    std::for_each(
        in(std::cin), in(), std::cout << (_1 * 3) << " " );
}
這樣build command 就不用特別加什麼:
g++ boostlambda.cpp

如果包含 library,以這個例子,用到 boost_regex : boostregex.cpp
#include <boost/regex.hpp>
#include <iostream>
#include <string>

int main()
{
    std::string line;
    boost::regex pat( "^Subject: (Re: |Aw: )*(.*)" );

    while (std::cin)
    {
        std::getline(std::cin, line);
        boost::smatch matches;
        if (boost::regex_match(line, matches, pat))
            std::cout << matches[2] << std::endl;
    }
}
這樣 build command 就要加上 boost library
g++ boostregex.cpp -lboost_regex



如果是要 cross build for embedded.列如 for arm.
先 cross build boost library,假設build 好都放在 /dm1lib/ (include & lib)

compiple 就只要指定 additional include path (-I)和 additional libary path (-L)就可以...
aarch64-linux-gnu-g++ fexist.cpp -I/dm1lib/include -lboost_system -lboost_filesystem -L/dm1lib/lib

http PUT request

最清楚簡單的 example 在 這裡
還有這一篇 有詳細的 example 和 server response 的解釋。

這一篇 有說,如何用 curl 下 PUT request

使用 Boost asio 來發。這篇 的回答有比較詳細的(但是是 POST request),可以參考。
這一個 pdf 中也有 tcp stream 的寫法:
tcp::iostream s("www.boost.org", "http");

s.expires_from_now(std::chrono::seconds(60));

s << "GET / HTTP/1.0\r0.2cm\n";
s << "Host: www.boost.org\r\n";
s << "Accept: */*\r\n";
s << "Connection: close\r\n\r\n";
And then receive and process the response:
std::string header;
while (std::getline(s, header) && header != "\r")
 std::cout << header << "\n";
std::cout << s.rdbuf();
If at any time there is an error, the tcp::iostream class’s error() member function may be used to determine the reason for failure:
if (!s)
{
 std::cout << "Socket error: " << s.error().message() << "\n";
 return 1;
}

所以用 boost::asio 來寫一個 PUT request: boostasio.cpp
#include <boost/asio.hpp>

int main()
{
	boost::asio::ip::tcp::iostream s("127.0.0.1","8123");
	s << "PUT /customers/23 HTTP/1.1\n";
	s << "Host: 127.0.0.1\r\n";
	s << "Content-length: 0\r\n";
	s << "\r\n";
//	s << std::flush;
}
build command:
g++ boostasio.cpp -lboost_system -lpthread

配合 json 作為 PUT 的 body 要參考這裡:
PUT /echo/put/json HTTP/1.1
Accept: application/json
Content-Type: application/json
Content-Length: 85
Host: reqbin.com

{
  "Id": 12345,
  "Customer": "John Smith",
  "Quantity": 1,
  "Price": 10.00
}

如果要看 server 的 reponse,這一篇 有簡單的 example,
就是..
ip::tcp::iostream stream;
stream.expires_from_now(boost::posix_time::seconds(60));
stream.connect("www.boost.org", "http");
stream << "GET /LICENSE_1_0.txt HTTP/1.0\r\n";
stream << "Host: www.boost.org\r\n";
stream << "Accept: */*\r\n";
stream << "Connection: close\r\n\r\n";
stream.flush();
std::cout << stream.rdbuf();

RESTful Client Library in C++


restc-cpp

  • 使用 Boost
  • 支援https
  • 支援 Json
看example,寫起來簡單漂亮。
make 是用 cmake


webcc

  • 使用Boost Asio
  • 支援 https
  • 支援json
  • 有 client 跟 server
看 example,有很多,
寫起來稍微比 restc-cpp 需要多一些 code

感覺功能比較多,還有keep-alive, file-download/upload ..等等功能
一樣用 cmake


Unbuffered socket iostreams

就是直接用 Boost.Asio 的 tcp::iostream 來操作。

感覺很厲害,,,就是 hard-coding http request....

2020/10/20

follow 安裝 add-apt-reposity
add-apt-repository 後,follow 這一篇 把 pgp key 加近來

原來是locale 的關係。
LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php
指定 encode 就可以。


然後就是 apt install phabricator
會裝 apache2 跟 mysql 跟 php...
還有
apt install python-software-properties software-properties-common 
LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej
apt update
apt upgrade

apt-get install git nginx mysql-server
要輸入 mysql 的 root password

2020/10/19

dell inspiron

LXDE 改用,Qt 了!? 而memory 沒有多很多,那就來試試看吧,剛好上次修NB 的 win10竟然到期了!
安裝 lts (20.04) 好了。

wifi 竟然部會洞..
lspci 看一下是 bcm4313, 參考這一個,安裝 package firmware-b43legacy-installer ,再裝 linux-firmware,之後 reboot 在 右下network 舊可以選了。

chewing (酷音)安裝:
apt install fcitx fcitx-chewing
裝完之後,要重新開機,在 fcitx configuration 就可以看到 chewing 輸入法了。
-- fcitx 的chewing可以調整的地方不多,像不能用shift快速換中英輸入。只能固定用左邊shift key

miniconda
其實就是download...
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
然後run 就可以。



2024-01-21 update

因為GLIBC 不夠新。所以加上 2024 (jammy) 到 sources.list,安裝後 break distribution package。
所以想乾脆更新好了,所以用 upgrade 而不是重新安裝。
在 /etc/update-manager 下有一個 do-dist-release,就 run 這個 script 就可以。
無痛安裝完畢,之後開啟 additional driver,wifi default 就 OK 了,另外選擇安裝propriety STA driver 也 OK

totolink 的 usb-wifi,安裝完 usb-modeswitch 之後, /lib/udev/rules.d/ 下就會有 40-usb_modeswitch.rules,follow 以前那篇,加上 totolink 的 rules 後,reboot,插入 usb-wifi,就自動啟動了,不用再自己拉 driver source 下來 build.


2024/02/24 update

更新後重開機,wifi 就打不開了。
用 rfkill 看,wlan 是 hardware blocked
代表網卡開關是關掉的,這個要用 bios hotkey 來開關,通常在 windows 才支援。
所以只好去bios 把所有rf (bt, wlan, wwan) 的support 改成 None,然後把default 都 enable。
開啟 ubuntu,wifi 就不是hardware blocked,也可以開了。

另外在安裝注音時,出現問題。

順序應該是:
在 language\Location 中安裝Chinese(Tranditional)
然後要重開機。
然後 install ibus-chewing,有時候已經安裝了。
之後reboot
去 "設定" -- Keyboard
加入 Chinese(Chewing),要去下面 ... 那格,之後選 Other 才會出現。

2020/10/16

/etc/fstab and systemd-fsck

systemctl status rc-local.service
systemd-fsck 是用來自動 fsck 的 daemon(?),分為兩個:
  • systemd-fsck.root.service : 負責對 root filesystem 做 fsck
  • systemd-fsck@.service : 負責對其他(非 root) 的 filesystem 做 fsck
他會根據 /etc/fstab 的內容,決定哪些 partition 需要檢查。
就是 fstab 中最後一個 field : pass
  • 0: 不檢查
  • 1: root用,要檢查
  • 2: 其他 parttition,要檢查
他會call fsck.XXX (XXX = filesystem type) 來做 fsck,所以要有對應的 fsck tool


另外,fsck (沒有.XXX) 會依照 /etc/fstab 的內容,自動 call 對應的 fsck.XXX 對 pass 不是 0 的 partition 檢查。

2020/10/13

bookmark : ADAS 的鬼影 和 魔鬼剋星

這一篇 用投影的方式欺騙 影像形式 的 ADAS 系統。
從影片看來非常有效..

這就像以前說的,單鏡頭無法分辨 3D 投影圖案是真的還是假的。
另外,用內嵌影像在影片中的方式,讓人眼沒感覺 (1/30 sec),但是 ADAS 鏡頭偵測得到。
還有投影路標線到道路上 (這個台灣舊一堆道路分隔現是亂七八糟的),讓 ADAS 誤判。

文章用 Ghost 來形容這些欺騙 ADAS 的物體。

然後。最後,他用一個model 來偵測這些 Ghost,network 就叫 GhostBuster...

... 但是他只有說有效,沒有示範影片。

我是覺得連人都會誤判的,要叫 Video type ADAS 系統分辨出來,是有點難了些...
而且誤判物件而停車減速。總比未偵測到而撞上來好得多...(像那個有名的貨櫃車翻車影像)


另外 這一篇 就是,..burger king 的廣告招牌讓 ADAS 誤判而慢下來...
-- 達到廣告效果 ?

可見以後 Video Type ADAS 系統普及後,會有更多利用他的廣告作法...

2020/10/12

nginx as a https reverse proxy to served test program and enable basic authentication

served 沒有 support https,所以用 nigx 做 reverse proxy,將 https 轉成 http 給 served.

served 部份就用 example 來測試。所以重點就是 nginx 左為一個 https reverese proxy 的設定..
  • 啟動 https
  • 將 https 轉為 http ,送到 served。(reverse proxy)
  • 啟動 basic authentication, 要求登入

nginx 要啟動 https,要先有 ssl 憑證。
因為是local 測試用,所以就自己產生一個就好。

ref 的網站說明一樣,用 openssl 產生:
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
其中 common name (FQDN) 就用 ip address : 172.16.200.11 這樣就可以。

產生 test.crt, test.key 兩個檔。放到 /etc/nginx/ssl/ 下。

然後修改 /etc/nginx/sites-available/default
加入:
       listen 443 ssl default_server;
       listen [::]:443 ssl default_server;

       ssl_certificate /etc/nginx/ssl/test.crt;
       ssl_certificate_key /etc/nginx/ssl/test.key;
重新啟動,測試一下,應該能看到 nginx 的 welcome page

reverse proxy 部份好像不分 https 還是 http,一樣是在 location 區塊加上
       proxy_pass http://localhost:8123/;
這樣舊可以。

啟動 served 的 example...
/served/bin$ ./eg_hello_world
Try this example with:
 curl http://localhost:8123/hello
這樣在其他機器上用 https://172.16.200.11/hello 舊可以看到 ...

最後就是啟動 basic authentication

需要有 user:password 檔。
簡單的方法是用 apache2-utils 的 htpasswd 產生。
但是在 embedd system 要 cross-build htpasswd 很麻煩,就用 openssl 來產生。
-- openssl 在啟動 openssl-server 時會一起build

這裡提供了一堆產生 password 的方法。都不用 apache2-utils 的 htpasswd

這裡用一般的,openssl passwd 的方法:
sudo sh -c "echo -n 'sammy:' >> /etc/nginx/.htpasswd"
sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
* password 好像要6 個 character,用 1234 個的話每次都會 login fail

這樣舊產生好 user: sammy 的 password 。
然後在 nginx 的 location 區段加上
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
重新啟動 nginx 後,在 https://172.16.200.11/hello 就會跳出login 對話盒,輸入username, password 就會出現 served 的 hello world 字樣。


設定完後,可以用 openssl 來看你的 CA chain 和 TLS version....
$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validat$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.comion Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com

2020/10/8

Makefile for building served liked program

要使用cross build 好的 served library 的話,要指定 boost library 和 served lib/include path。

先找出 CMake build example 的 build command..

把CMakeLists.txt 的 VERBOSE 打開。make 一次,然後 touch hello_world/main.cpp 再 make 一次。找出 make command:
/usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-g++   
-I/home/charles-chang/githubgitlab/served/src 
-I/tmp/boost/include  
-std=c++11 -Wall -pedantic -Wextra -Wno-missing-field-initializers   
-o CMakeFiles/eg_hello_world.dir/main.cpp.o 
-c /home/charles-chang/githubgitlab/served/src/examples/hello_world/main.cpp



/usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-g++   
-std=c++11 -Wall -pedantic -Wextra -Wno-missing-field-initializers  -rdynamic 
CMakeFiles/eg_hello_world.dir/main.cpp.o  
-o /home/charles-chang/githubgitlab/served/bin/eg_hello_world  
-L/tmp/boost/lib 
-Wl,-rpath,/tmp/boost/lib:/home/charles-chang/githubgitlab/served/lib: /home/charles-chang/githubgitlab/served/lib/libserved.so.1.4 /tmp/boost/lib/libboost_system.so 
-lpthread 
分別是 compile 和 link

所以 Makefile...
CC=aarch64-linux-gnu-g++
CFLAGS=-I/home/charles-chang/githubgitlab/served/src -I/tmp/boost/include -std=c++11 -Wall -pedantic -Wextra -Wno-missing-field-initializers
LDFLAGS=-std=c++11 -Wall -pedantic -Wextra -Wno-missing-field-initializers -rdynamic
LLIBS=-L/tmp/boost/lib -Wl,-rpath,/tmp/boost/lib:/home/charles-chang/githubgitlab/served/lib: /home/charles-chang/githubgitlab/served/lib/libserved.so.1.4 /tmp/boost/lib/libboost_system.so -lpthread


%.o: %.cpp
    $(CC) $(CFLAGS) -c -o $@ $< 


hello_world: main.o
    $(CC) $(LDFLAGS) -o $@ $^ $(LLIBS)

2020/9/30

CMake cross-build -- served

用 CMake 來做 cross-build
-- 其實是因為大多使用 CMake 的 project 都是 host - target 同一系統,所以 detect, config 都是自動。但是現在要 build for target,就要讓 CMake 可以做 cross build.

看起來,是要用 -DCMAKE_TOOLCHAIN_FILE=maytoolchain.cmake
然後寫 mytoolchain.cmake
裡面指定toolchain path, name 和一堆 flag, library 等...

然後goole CMAKE_TOOLCHAIN_FILE 可以找一堆 sample,,



cross build served..

準備好 toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(TOOLCHAIN_PATH /usr/local/linaro-aarch64-2018.08-gcc8.2)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PATH}/bin/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH}/bin/aarch64-linux-gnu-g++)

run cmake....
served.build$ cmake -DCMAKE_TOOLCHAIN_FILE=~/toolchain.cmake ../served
Error:
CMake Error at /usr/share/cmake-3.10/Modules/FindBoost.cmake:1947 (message):
  Unable to find the requested Boost libraries.

  Boost version: 1.65.1

  Boost include path: /usr/include

  Could not find the following Boost libraries:

          boost_system

  No Boost libraries were found.  You may need to set BOOST_LIBRARYDIR to the
  directory containing Boost libraries or BOOST_ROOT to the location of
  Boost.

in case cross-build boost: .. 結果沒用到,target system 的 boost 1.66.0 也可以用。所以不用 port boost

依照Error message,把 target system 的 boost package folder copy 到/tmp
要安排一下,把lib 和 header(include) 依照下面方式放好..
/tmp/boost/include/boost
/tmp/boost/lib
並且把 修改 toolchain.cmake,加入
set(BOOST_ROOT /tmp/boost)
一樣..
served.build$ cmake -DCMAKE_TOOLCHAIN_FILE=~/toolchain.cmake ../served
-- The C compiler identification is GNU 8.2.1
-- The CXX compiler identification is GNU 8.2.1
-- Check for working C compiler: /usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-gcc
-- Check for working C compiler: /usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-g++
-- Check for working CXX compiler: /usr/local/linaro-aarch64-2018.08-gcc8.2/bin/aarch64-linux-gnu-g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Warning at /usr/share/cmake-3.10/Modules/FindBoost.cmake:801 (message):
  New Boost version may have incorrect or missing dependencies and imported
  targets
Call Stack (most recent call first):
  /usr/share/cmake-3.10/Modules/FindBoost.cmake:907 (_Boost_COMPONENT_DEPENDENCIES)
  /usr/share/cmake-3.10/Modules/FindBoost.cmake:1558 (_Boost_MISSING_DEPENDENCIES)
  CMakeLists.txt:71 (FIND_PACKAGE)


-- Boost version: 1.66.0
-- Found the following Boost libraries:
--   system
-- Could NOT find RAGEL (missing: RAGEL_EXECUTABLE) 
-- Could NOT find RAGEL (missing: RAGEL_EXECUTABLE) 
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
-- Performing Test COMPILER_SUPPORTS_CXX11
-- Performing Test COMPILER_SUPPORTS_CXX11 - Success
-- Performing Test COMPILER_SUPPORTS_CXX0X
-- Performing Test COMPILER_SUPPORTS_CXX0X - Success
-- Configuring done
-- Generating done
-- Build files have been written to: /home/charles-chang/githubgitlab/served.build
成功了...

到 served/bin/ 下 check file ,都是 ARM aarch64 ELF 沒錯。

放到 target board 上 run ..
  • 把 served/lib/ 下的so copy 到 /lib/ 下
  • 有用到 boost_system.so,所以要記得把 target build system 的 so 也 copy 到 /lib/ 下

RESTful server (library) in C++

直接link 到 main program 好像比較方便,不用再透過 interface call programm..
所以找 C++ library


有附example 和用 curl 的測試方法。
依照說明clone 下來,用 cmake 產生 Makefile 後 make 舊可以。
在 clone 的folder 下的bin 會有所有 example 的 執行檔,可以一一執行。
同時會印出 用 curl 的測試 command

example 的 main( ) 內容也很簡單。

build 好的 library 只有一個。
include 檔整個和 source code 合在一起。

剩下的問題就是 cmake 系統 porting 到 aarch64 的問題。




這個應該是最有名的,但是 example 看起來好像比剛剛的 served 複雜一些。


其他還有 microsoft 的 c++ rest api,這個 example 看起來更複雜:


上面的 library 比較簡單,所以沒有提供 authentication (login) 功能。
要有 login 的話,要用...

這個就有 authentication,同時支援 http 和 https,但是 library 比較大,使用起來也比較複雜。



這個也有支援 basic 跟 token authentication.
也有 https
也是依照callback, url hanelder 寫程式。


其他

cuda in docker

因為這一篇 說,照一般安裝也可以用。
當然,他提供了三種方法。
所以想試試看直接安裝的方法。
--- 上次在docker 中使用 nvidia ffmpeg,是用 nvidia 的docker。

follow 這一篇,無腦的裝了。

test 有 Error, 要 follow 這一篇 加上 nvidia 的 source list
才能裝
$ sudo apt install nvidia-container-toolkit
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libnvidia-container-tools libnvidia-container1
The following NEW packages will be installed:
  libnvidia-container-tools libnvidia-container1 nvidia-container-toolkit
0 upgraded, 3 newly installed, 0 to remove and 51 not upgraded.
Need to get 850 kB of archives.
After this operation, 2,623 kB of additional disk space will be used.
Do you want to continue? [Y/n] 
重新啟動 docker
systemctl restart docker
然後在 container 舊可以正確run nvidia-smi
因為 host 是 10.2:
~/gpuindocker$ cat Dockerfile 
FROM nvidia/cuda:10.2-base
CMD nvidia-smi

build image and run
~/gpuindocker$ docker build . -t nvidia-test

~/gpuindocker$ docker run --gpus all nvidia-test
Thu Oct 29 08:07:02 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.100      Driver Version: 440.100      CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  TITAN RTX           Off  | 00000000:01:00.0 Off |                  N/A |
| 30%   46C    P0    31W / 280W |      0MiB / 24218MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
這樣在container 中也能正確 access gpu

原來是docker 19.03 版之後,可以不用 nvidia-docker2 來 access gpu
可以直接支援 gpu


2020/9/28

memo .. about nmea parsing..

stringstream 的特性..
先用 getline( whole, sub, ',') 取出以 ',' 區分的字串。
然後用 sub >> float type 直接舊可以轉成 floating type 了。

讀取的部份,還是只能一次一次的,把 char buffer 讀進來,再轉 stringstream。

不行,stringstream getline 雖然會記住processing 的位置,但是 stringstream 本身不會消失,所以一直 append 的話,會越來越大,必須要刪除掉處理過的部份。


ref:

改用 string,find $ 之後找 '\n' 完成一個substring,assign 給stringstream。
然後再reassgin 剩下的substring 給自己。

read : char[]
find : string
parsing : stringstream

bookmarks: veracrypt , open source volume encrypting tool for Linux, android and Windows

2020/9/25

vim plug in

vi 有自己的 script language
vi plugin 就是用這些script language 寫的,用來完成特殊功能。

vim 有規定 plugin 的安裝方式:VIM REFERENCE MANUAL by Bram Moolenaar

這一篇有說明 vim 對 plugin 的運作原理。
vi 啟動,執行.vimrc
然後 search .vim/ 下所有的目錄,找 pack/*/start.
找到後執行他。

為了方便管理 plugin,也有人寫了 plugin 來方便 plugin 的安裝。

Vundle

所以要安裝其他plugin之前,要先安裝這個。
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
先把 Vundle clone 到 .vim 的folder..
然後修改 .vimrc,把 這個folder 加到 vim 的環境變數裡
set rtp+=~/.vim/bundle/Vundle.vim
接著 call Vundle 的 begin 和 end function..
在這兩個function 中間的 plugin,vundle 就會幫你安裝和管理。
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'
Plugin 'tpope/vim-fugitive'
call vundle#end()            " required
filetype plugin indent on    " required

以dart 來舉例,照著這一篇 做..
修改 vimrc,加入 Plugin 'dart-lang/dart-vim-plugin':
set nocompatible  
filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'
Plugin 'dart-lang/dart-vim-plugin'
call vundle#end()
filetype plugin indent on 
開啟vim,輸入 :PluginInstall,之後會開啟 Plugin List,然後出現Done!,舊完成了。
ls ~/.vim/bundle 可以看到..
dart-vim-plugin  Vundle.vim
已經幫你下載 dart-vim-plugin 了。

ref:

上面是第一次安裝,使用 plugin 的時候,可能參考到 Vundle ..所以寫的。
之後,又遇到,chatgpt 建議,用 vim-plug
其實vim 有 啟動後,自己到特定目錄load vim script file 的動作,所以手動把 plugin (也就是 vim script file) copy 到個特定目錄下也可以。
但是為了管理方便,有人就用 vim script 寫了 plugin 管理程式。
基本上自己也是一個 vim script。
vim script 提供一堆 function /command,要執行的話,就是再 vim 下 的命令 :function ,其中 function 就是 script 提供的 function 名稱。

所以,要安裝 vim-plug,就是把github 網站的 plug.vim 單一檔案,下載到 .vim/autoload/ 下。
這樣啟動的時候,vi 就會去 load 他了。
另外,要在.vimrc 寫:
call plug#begin('~/.vim/plugged')

"Put your plugin here

call plug#end()
這樣,vi 啟動後, run .vimrc,就會執行 call plug, 分別begin 跟 end.
讓 vim-plug 去處理 安裝的 plugin。

所以,把要安裝的 plung 寫在 .vimrc 的 begin(), end() 之間就可以。

2020/9/22

request_firmware : read file from kernel

kernel driver 可以從 filesystem 中讀檔。
用 request_firmware( ) 這個function。

file 的 path 呢?
在 driver/base/firmware_class.c:
/* direct firmware loading support */
static char fw_path_para[256];
static const char * const fw_path[] = {
    fw_path_para,
    "/lib/firmware/updates/" UTS_RELEASE,
    "/lib/firmware/updates",
    "/lib/firmware/" UTS_RELEASE,
    "/lib/firmware"
};

/*
 * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH'
 * from kernel command line because firmware_class is generally built in
 * kernel instead of module.
 */
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
其中 fw_path_para 是 啟動 kernel 時指定的

2020/9/21

Bookmark: denoise , deblure with NN.

這個很有趣,Super Resolution W.N.N

作者有 opensouerce 喔
* SRWNN Mobile : 是用 flutter 包 tenerlite。

upscale 的 GAN 部份是參考waiful2x 也有為準備training data 寫的 tool:PuixivUtil2

NN 的部份是基於ESRGAN,這個有詳細的實做和 training 方法
然後這個E2_ESRGAN 就是 Tensorflow 的實做
這個是 SuperResolutionWaifuNN的實做。

2020/9/17

自動駕駛的等級..

0-5 個 level 各是什麼很難記。
看到這個,原來是這個意思。

開車需要用到
  • 眼睛
所以,,,
  • 0 : 全用到
  • 1 : 不用腳
  • 2 : 不用手
  • 3 : 不用眼睛
  • 4 : 不用腦
  • 5 : 全部都不用之外,駕駛也不用了

2020/9/15

Prepare minimum kernel sources for building external module

build external module

由於 build module 需要用到 kernel 的 Makefile (和 Kbuild)。
所以必須要有 kernel 的 Makefile。
而用 make headers_install 做出來的 kernel headers 是不含 Makefile 。
所以必須要完整的 kernel source。

另外,必須要知道 kernel 的 配置,所以要包含 target 的 .config。
另外,還包含 arch link 和 generated header。
簡單的說,就是 source 還必須要 build 過。

Makefile 中,可以用 -C 指定 source,O 指定 output (當初build kernel 的 output)。
不然,就要放在一起。用 -C 指定。

先用標準的方法來試試看...
這個 就是hello.ko。
先 clone and build kernel:
  • git clone --depth=1 https://github.com/raspberrypi/linux -b rpi-5.4.y pilinux
  • git clone https://github.com/raspberrypi/tools.git pitool
  • export PATH="/home/charles-chang/pitools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin:$PATH"
  • cd pilinux
  • make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
  • make -j 40 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
這樣就完成了需要的 kernel source

之後,一樣把 path 設好,到 helloko 下 make 舊可以 build 出給 pi 用的 hello.ko 了。


這是用完整的kernel source,但是make external module 只需要 Makefile, Kbuild, header,config。
所以可以把所有的 .c, .o, configs 目錄,都刪掉,


build kernel module 就是利用 kernel source 的 Makefile。
kernel 的 Makefile 有 support 一堆 option..
ref:kernel makehelp

helloko 的Makefile 用到..
  • V=1 : 印出所有的 make 時的動作
  • CROSS_COMPILE=arm-linux-gnueabihf-
  • ARCH=arm
  • -C $(KERNEL_DIR) : kernel source 位置
  • M=$(PWD) : module 位置


遇到很有趣的事...
在把 cypress wifi 移出 kernel source ,改 external module 來 build 的時候...
Kbuild 中,有..
DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH=$(BCMDHD_FW_PATH)
BCMDHD_FW_PATH 是環境變數,在 make 前先 export 好..
因為是字串,所以用 esc '\' 來加 '"' 符號...
export BCMDHD_FW_PATH="\"/lib/firmware/cypress/cyw88373/fw_cyw88373.bin\""
結果 fail..
source code 中說 BCMDHD_FW_PATH 是 null..

對照成功的 log (build within kernel source),發現這個字串包含 esc code..
所以再esc 一次..
export BCMDHD_FW_PATH="\\\"/lib/firmware/cypress/cyw88373/fw_cyw88373.bin\\\""
就 OK 了。

從一般的SDK 的 kernel source 準備一份可以 build external module 的 kernel header 的方法:
  • make kernel image OK (好像是 make config 跟 make prepare 就可以?)
  • copy kernel source (include hidden file)to /tmp/linuxheader
  • copy kernel out (include hidden files) to /tmp/linuxheader
  • remove all *.o,*.c,*.cmd
  • copy kernel source/Makefile to /tmp/linuxheader because it was overwritten by the out source
  • modify driver Makefile, obj-$(DRIVER_TYPE) += 要改成 obj-m :=

2020/9/14

IIS2DLPC accelerometer, polling mode. datasheet and driver

IIS2DPLC Datasheet

ODR : output data rate
依照 High-Performance/ Low-Powerer Mode 而有不同的值:
  • 0: power down
  • 1: 12.5/1.6Hz
  • 2: 12.5Hz
  • 3: 25Hz
  • 4: 50Hz
  • 5: 100Hz
  • 6: 200Hz
  • 7: 400/200Hz
  • 8: 800/200Hz
  • 9: 1600/200Hz
但是 driver 的寫法卻是 high-performance/lowe-power mode 都是一樣

Driver Code 看起來,用hrtimert 做 polling,跟 ODR 沒有同步。
只是根據 ODR 設定 timer polling time

因為 implement 成 input device,所以會依照 timer 主動 report input event

2020/9/11

aplay with repeat option, and cross build

aplay 竟然沒有自動repeat 的選項。
所以clone 一個版本下來改。

aplay 屬於 alsa-utils,但是github的版本,需要自己產生 configure 檔。
要做 cross-compile 的話很麻煩,
所以用 LFS 的 1.0.26 板來改。

只是在找到 最後read file to pcm 的地方,重複做而已。
然後記住 開丟到 pcm 的file position

另外,因為r, l 都被用掉了。只有選 'b' 了.

放在 alsa-utils-1.0.26-with-repeat

aplay -b myfile.wav
要停止舊只能 Ctrl-C 了...


cross build

他要兩個 library:
  • ncurses
  • alsa-lib
export 好 path to toolchain.
然後宣告 CC
export CC=aarch64-linux-gnu-gcc
再來 ru ./configure..
LDFLAGS+=”-L/tmp/ncurse/lib -lpthread -lm -lc”; CFLAGS+=”-I/tmp/ncurses/include -I/tmp/ncurses/include/ncurses”; ./configure --build=i686-linux --host=arm-linux --prefix=/tmp/alsa/utils --with-alsa-prefix=/tmp/alsa-lib/lib --with-alsa-inc-prefix=/tmp/alsa-lib/include --disable-alsamixer
其中 /tmp/XXX 是需要的 library,把target 的 library copy 到...

然後舊可以 make 了...

Get current file position , lseek()

Linux 的低階 IO,提供 open, close, read, write 和 lseek。
lseek 就是用來移動 read. write position
參考 lseek definition in gnu
off_t lseek (int filedes, off_t offset, int whence)
其中的argument 都是設定用的,用來修改 read/write posisiton

那要如何知道目前的position 呢?
因為每次呼叫 lseek(),他都會傳回修改後的position (鄉對於開始)。
所以就做一次 dummy set 舊可以了..
stackoverflow: ftell on a file descriptor
position = lseek(fd, 0, SEEK_CUR);

bookmark : comparison chart of libc , 其實是在看 musl-libc

其實是因為看到musl-libc,想說怎麼沒看過。
甚至有些distribution 用這個 C library
光看官網介紹也無法了解為什麼要再做一個新的。

這一篇列出各 c library 的性能比較。

... 雖然是這樣,好像還是看不出再重新寫一個的目的是...?

alphine採用 musl-libc 來看,可能是因為 size 最小,
然後這一篇 說,musl 的 malloc 好像有點問題...

這一篇 有很好的範例說明如何使用 musl-libc
的確,為了方便,需要 build 一個 default 使用 musl-libc 的 toolchain(gcc)
clone 下來,./configure , make 之後 舊 OK (make install ?)
同一份source code ,用 gcc build,就 link glibc
用musl-gcc build,舊 link musl-libc
然後舊可以比較 size. speed... etc

2020/9/10

bookmark : drunk, sober , face.

Drunk-Detect

如果有清醒(Sober) 時的資料,以此判斷他是否清醒(的臉),好像比較可行。

dif dataset of intoxicated faces for drunk person identification

這個是用來training 的database,還有用比較的方式(LSTM) 來偵測 drunk person

2020/9/8

cross build ncurses library

ncueses 的 6.1, 6.2 在 cross build 的時候都會有這個問題...
make install 會 Error,說 strip error

原因是install 這個tool用到host 的strip,這個解決方法比較....

查到 install --help,有..
--strip-program=PROGRAM
的option,所以修改每一個有 target: install 的 Makefile...

結果這一篇也有說。
--- a/configure	2018-01-19 19:27:18.000000000 -0500
+++ b/configure	2018-03-14 19:18:39.136573491 -0400
@@ -13716,7 +13716,7 @@
 
 if test "$with_stripping" = yes
 then
-	INSTALL_OPT_S="-s"
+	INSTALL_OPT_S="-s --strip-program=${STRIP}"
 else
 	INSTALL_OPT_S=
 fi
他修改configure,吃 STRIP 這個環境變數。
同時,所有Makefile 都會改到。

這樣改完,重新 configure 後,6.1 的 make install 沒問題了。
6.2 還有問題,是 color 什嗎的問題,還沒解決..

2020/9/7

flutter plugin: get external sd card path : path_provider_ex

plugin: path_provider_ex

其實只是用來找到 SD card 在系統的 full path

plugin 的 example 在有sdcard 的手機和沒有sd card 的手機 (pixel2) 分別顯示不同的內容:


現在把example 轉成 android project, 放在 github: pathproviderex

啟動log 程式,靜止,log 1min。取得校正點。
地心引力 g 的方向(三軸分量)

之後持續log ...

對照

1sec內所有的 data 做 average
果然變得很smooth,很漂亮。

2020/9/4

flutter : 修改 package 來用

寫flutter 就是要用一堆別人寫好的 package.
但是如果 package 不是100% 符合需求呢?
可不可以clone 下來改?

ref:How to modify plugins Dart code flutter

原來我們pub get 完的 package(plugin) 都會在 ~/.pub-cache/hosted/pub.dartlang.org/ 下面。
一個package/plugin, 一個 version 一個folder

找到要改的plugin folder,copy 到自己的 project home 下 (跟 pubspec.yaml 同一層),rename folder name.
然後改自己的 pubspec.yaml,原來 depencies 部份:
sensors:
加上 path:
sensors:
  path: ../mynewfoldername/
這樣就可以了。

做了一個把 sensor 拿進 project 的 code: accelerlog

原本是想修改 sensor onListen 的 frequency 的,可惜沒有效。
最後還是用 check second value changed 的方式。

2020/9/3

flutter_logger : android version

就是這篇文章:
A Flutter file logger (for iOS and Android simulators)


裡面的 code,我把他放到 Android Run
然後把不能動的地方修改一下..
  • AndrodManifest.xml 加上 user-permission for external storage read/write
  • main( ) 要加上async, 和 ensureInitialized( ) 不然會 compile Error 跟 run 不起來
  • 要用 getExternalStorageDirectory(), 不然雖然執行沒問題,但是沒辦法用 FileManager 找到位置
Project 放到github 了。

附帶寄一下..

用 getApplicationDocumentsDirectory() 的話,位置是:/data/user/0/com.example.flutter_logger/app_flutter/back_to_now.txt
這個用 adb 去要 root 才能打開。

用 getExternalStorageDirectory(),位置是 /storage/emulated/0/Android/data/com.example.flutter_logger/files/back_to_now.txt。
不用 root 舊可以看了。

還有,用上面兩個位置。都不需要用 permission_handler 來 request access permission,只要修改 AndroidManifext.xml 舊可以

flutter: synchronized

在看flutter logger 的時候看到,writelog 時,要用synchronized 這個 package

這跟 async 有什嗎關係?

synchronized 的官方說明 中的 example 有很好的說明。
他的 write(1234) 剛好符合這個 logger 的狀況。

因為writelog( ) 是一個 critial section (mutex ?)
一個 writelog 沒寫完時,下一個 writelog 的function 要 wait.
因為 writelog 又是 async function,所以需要 synchronized 這格 package,把 write( ) 的 code section guard 起來。

2020/9/2

flutter : permissions

其實是要做file read/write 的,結果卡在 external storage permission...

太久沒寫,user-permission 要寫在那一層都忘了...
寫在最外層,跟 application 同一層。(不是application 之下)
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.example">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<application android:name="io.flutter.app.FlutterApplication" android:label="example" android:icon="@mipmap/ic_launcher">
<activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
然後是pubspec.yaml
dependencies:
flutter:
sdk: flutter
simple_permissions: ^0.1.9
path: '>=1.5.1 <3.0.0'
path_provider: '>=0.4.0 <3.0.0'
這個simple_permissions 最後沒有成功,因為用了舊版sdk 的樣子。
所以還要去修改 android 的 gradle.
-- 這樣舊失去了 flutter 的意義。

後來用了 permission_handler

參考了Request Permissions in Flutter as a Service 的 example code,放在project file:github: permissionhand

根據plugin 的官方 example 做的 project 在: phexample

2020/8/26

flutter : 竟然支援 desktop 了 -- linux. gtk

ref: 跟 support web 一樣,flutter config --enable-linux-desktop
測試過,要 branch dev 才有,beta 的話 enable OK,但是不會真的 create linux folder(device)
enable 完,upgrade 後,run doctor 有 Error...
[✗] Linux toolchain - develop for Linux desktop
    ✗ clang++ is required for Linux development.
      It is likely available from your distribution (e.g.: apt install clang), or can be downloaded from https://releases.llvm.org/
    ✗ ninja is required for Linux development.
      It is likely available from your distribution (e.g.: apt install ninja-build), or can be downloaded from https://github.com/ninja-build/ninja/releases
    ✗ GTK 3.0 development libraries are required for Linux development.
      They are likely available from your distribution (e.g.: apt install libgtk-3-dev)
    ✗ The blkid development library is required for Linux development.
      It is likely available from your distribution (e.g.: apt install libblkid-dev)
就 follow instruction...
apt install clang ninja-build libgtk-3-dev libblkid-dev
然後舊真的可以 run 了...

最後要 build release 的話,就在 project 下
flutter build linux
要記得,flutter app 包含很多 library,所以要執行 release/bundle/ 下的執行檔,而不是 release 下的
目前支援 linux 跟 macos (是,windows 沒有)

更正:
ref:flutter and desktop

所以是有support windows 的,只是還在更初期階段,master branch
一樣,flutter channel master, upgradeconfig --enable-windows-desktop

之後到舊project 去 flutter create . 一下,再 flutter run -d windows 舊可以。

最後在 windows folder 下會有 visual studio 的 sln 檔。似乎可以用 visual studio 打開。
flutter doctor 可以看到有檢查 Visual Studio 有沒有安裝。
-- 我有安裝 community 版