2021/9/15

WM8974 driver : 增加一個control : mic bias

發現沒有寫,所以現在補一下..

Datasheet 上..
Datasheet P 19:

* Register R44: Input Control
* Bit 8
* Label: MBVSEL
* Default: 0
* Description: Microphone Bias Voltage Control
    0: 0.9 x AVDD
    1: 0.75 x AVDD
所以在 wm8974.c 中加一個 amixer control:
diff --git a/linux-4.14/sound/soc/codecs/wm8974.c b/linux-4.14/sound/soc/codecs/wm8974.c
index 61fbd7c55..7a1c492d2 100644
--- a/linux-4.14/sound/soc/codecs/wm8974.c
+++ b/linux-4.14/sound/soc/codecs/wm8974.c
@@ -66,6 +66,7 @@ static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
 static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
 static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
 static const char *wm8974_alc[] = {"ALC", "Limiter" };
+static const char *wm8974_mbvsel[]= {"0.9", "0.75"};
 
 static const struct soc_enum wm8974_enum[] = {
        SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */
@@ -85,6 +86,7 @@ static const struct soc_enum wm8974_enum[] = {
 
        SOC_ENUM_SINGLE(WM8974_EQ5,  5, 4, wm8974_eq5),
        SOC_ENUM_SINGLE(WM8974_ALC3,  8, 2, wm8974_alc),
+       SOC_ENUM_SINGLE(WM8974_INPUT, 8, 2, wm8974_mbvsel),
 };
 
 static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" };
@@ -131,6 +133,7 @@ SOC_ENUM("Equaliser EQ4 Bandwidth", wm8974_enum[9]),
 SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]),
 SOC_SINGLE_TLV("EQ4 Volume", WM8974_EQ4,  0, 24, 1, eq_tlv),
 
+
 SOC_ENUM("Equaliser EQ5 Bandwidth", wm8974_enum[11]),
 SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]),
 SOC_SINGLE_TLV("EQ5 Volume", WM8974_EQ5,  0, 24, 1, eq_tlv),
@@ -151,6 +154,8 @@ SOC_SINGLE("ALC Capture Hold", WM8974_ALC2,  4, 7, 0),
 SOC_SINGLE("ALC Capture Target", WM8974_ALC2,  0, 15, 0),
 
 SOC_ENUM("ALC Capture Mode", wm8974_enum[13]),
+SOC_ENUM("MIC Bias Voltage", wm8974_enum[14]),
+
 SOC_SINGLE("ALC Capture Decay", WM8974_ALC3,  4, 15, 0),
 SOC_SINGLE("ALC Capture Attack", WM8974_ALC3,  0, 15, 0),
 
這樣就多一個
numid=38,iface=MIXER,name='MIC Bias Voltage'
cget, set
# amixer cget numid=38
numid=38,iface=MIXER,name='MIC Bias Voltage'
  ; type=ENUMERATED,access=rw------,values=1,items=2
  ; Item #0 '0.9'
  ; Item #1 '0.75'
  : values=1
設完後,cat register-map 來看,reg 2C bit 8 有改變。

2021/9/13

bookmark : hacking CAR canbus

ref: 作者用 can-dsub, dsub-usb 然後用 usb-can bus driver 在 linux 上開啟一個 socket 來 dump CAN bus data。
然後 log,配合 影像做 reverse engineering。

最後還附上hack 完的 source code. (在 github : toyothack)。

另外的,當然是 openpilot 最多,他們有一個opendbc 描述已經decode 的車輛canbus 格式。

use repo to manage multiple projects

ref: 要用 repo/manifest 來管理現有 一堆 projects。
只要 create 一個 git project,裡面就是 manifest 的 xml 檔。
其中要有一個 default.xml, repo 會用這個做 主要的 manifest.xml
repo init -u mymanifest
mymanifest 就是放 default.xml 的 project folder


舉例來說:

假設myrepo 專案有 proj1, proj2 兩個 git source
.
├── proj1
└── proj2
想要用 repo/manifest 來管理。
就create 一個 manifests,裡面有 default.xml,也要用 git 管理:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
	<remote name="origin" fetch="./" />
	<default revision="master" remote="origin" />
	<project path='proj1' name='proj1' />
	<project path='prij2' name='proj2' />
</manifest>
然後 myrepo 下有三個 git projects:
.
├── manifests
│   └── default.xml
├── proj1
└── proj2

這樣,在 local 端,就可以用 repo init 來 clone 整個 project
mkdir testrepo && cd testrepo
repo init -u ~/myrepo/manifests
downloading Repo source from https://gerrit.googlesource.com/git-repo
remote: Counting objects: 2, done
remote: Finding sources: 100% (12/12)
remote: Total 12 (delta 0), reused 12 (delta 0)
Unpacking objects: 100% (12/12), done.
Downloading manifest from /home/charles-chang/myrepo/manifests/
remote: Counting objects: 15, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 15 (delta 4), reused 0 (delta 0)

Your identity is: charles.chang <charles.chang@loyaltech.com>
If you want to change this, please re-run 'repo init' with --config-name

repo has been initialized in /home/charles-chang/testrepo
之後 repo sync 就會拉下所有的 project (不包含 manifest,manifest 會在 .repo/manifests)
然後一樣在 repo init 時加上 --mirror 就可以產生 git server 端的目錄結構 (方便放在 git server)

現在看來,要先用 python script : follow repo/manifest.xml 做出 repo mirror 的結構.,重新安排一次 project 目錄結構。
之後才能讓人做 repo init, sync..
-- 新版的 repo 不從 manifest.xml parsing 了, manifest.xml 也不再是 link,而是一個 include name,include default.xml (或其他)。



repo 管理後,如果要create 一個版本, fix 住目前的 project revision,可以用 repo manifest, 如何導出並使用清單文件? 的方法。用 repo manifest,列出有家 option 和沒加 option 的結果:
一般:
charles-chang@rdsuper:~/testmirror$ repo manifest
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote fetch="./" name="origin"/>
  
  <default remote="origin" revision="master"/>
  
  <project name="pp/project1" path="project1"/>
  <project name="project2" path="priject2"/>
</manifest>
加上 supress-upstream-revision
charles-chang@rdsuper:~/testmirror$ repo manifest -r --suppress-upstream-revision
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote fetch="./" name="origin"/>
  
  <default remote="origin" revision="master"/>
  
  <project dest-branch="master" name="pp/project1" path="project1" revision="7c4bcfb45cd9aa2266c0acf3f850a9ea50ae5ef9"/>
  <project dest-branch="master" name="project2" path="priject2" revision="907de68553f9b6d638aceb967c7a9f55bc8fcb03"/>
</manifest>
舊可可以把這個列出的結果存成新的 myversion.xml,加到 manifests.git 中。

如果 project 在另一個 project 中...可以用 .gitignore..
例如:
.
├── priject2
│   └── pp2
└── project1
    ├── p3
    │   └── myfile
    └── pp1
p3 在 project1 裡。

manifest 是這樣:
<manifest>
	<remote name="origin" fetch="./" />
	<default revision="master" remote="origin" />
	<project path='project1' name='pp/project1' />
	<project path='priject2' name='project2' />
	<project path='project1/p3' name='p3' />
</manifest>
可以看到 project path='project1/p3' 這樣。
但是這樣在 repo sync 後,project1 下 git status 就會看到 p3 new.
所以要加 .gitignore
p3



manifest 中,project 有些會有:
 revision="36fb2aa4f7f25946e0ce3d4223095ce9601dd17f" upstream="cafe/QCLA.2.0-r00015.3"
這樣的話,project 要有 rev="36fb2aa4f7f25946e0ce3d4223095ce9601dd17f" 的 commit 存在,同時,還要有個branch nane叫 ""cafe/QCLA.2.0-r00015.3".
用 git ls-remote 可以列出 remote ref head. 可以檢查

2021/9/10

system service : report ip to another server

啟動後,等 remote server up,然後把 自己的 ip 送過去..
先把自己的 public key 送過去 (user charles-chang)。設定好 ssh 免 password.
準備 service file:
xeontitan:/etc/systemd/system# cat reportip.service 
[Unit]
Description=send my ip address file to rdsuper
Afteter=network-online.target

[Service]
User=charles-chang
WorkingDirectory=/home/charles-chang
ExecStart=/home/charles-chang/reportip.sh

[Install]
WantedBy=multi-user.target
charles-chang 自己的 shell script:
cat /home/charles-chang/reportip.sh 
#!/bin/bash
while true
do
	ping -c 1 rdsuper
	if [ $? -eq 0 ]
	then
		break
	fi
	sleep 10
done
ip addr > $HOSTNAME-ip
scp $HOSTNAME-ip rdsuper:~/
enable & start
systemctl daemon-reload
systemctl enable reportip.service
systemctl start reportip.service



改用 python 做,用 socket 直接 update /etc/hosts 的話: 叫 chatgpt 寫...
為了測試,先改 /etc/hosts_u 系統測試 OK 再改 /etc/hosts..

~$ cat updatehosts.py
import socket

def update_hosts_file(ip, hostname):
    # Read the current contents of /etc/hosts
    with open('/etc/hosts_u', 'r') as file:
        lines = file.readlines()

    # Check if the hostname already exists in the file
    exists = False
    for i, line in enumerate(lines):
        if hostname in line:
            # Update the existing entry
            lines[i] = f"{ip} {hostname}\n"
            exists = True
            break

    # If the hostname does not exist, add a new entry
    if not exists:
        lines.append(f"{ip} {hostname}\n")

    # Write the updated contents back to /etc/hosts
    with open('/etc/hosts_u', 'w') as file:
        file.writelines(lines)

def start_server(port):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(('0.0.0.0', port))
    server_socket.listen(5)
    print(f"Listening on port {port}...")

    while True:
        client_socket, client_address = server_socket.accept()
        print(f"Connection from {client_address}")

        data = client_socket.recv(1024).decode('utf-8')
        if data:
            ip, hostname = data.split(',')
            update_hosts_file(ip, hostname)
            print(f"Updated /etc/hosts with IP: {ip}, Hostname: {hostname}")

        client_socket.close()

if __name__ == "__main__":
    start_server(61234)
然後 systemd service file:
$ cat updatehosts.service
[Unit]
Description=Sender Python Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/charles-chang/updatehosts.py
Restart=on-failure

[Install]
WantedBy=multi-user.target

至於 sender 端,因為要等 dhcp ready...
要注意 nic interface name 是不是 eno1,不一定是。
要依照自己的系統修改。

$ cat sender_updatehosts.py
import socket
import time
import netifaces

SERVER_IP = '192.168.147.182' 
SERVER_PORT = 61234            

def get_ip_address(interface):
    try:
        ip_address = netifaces.ifaddresses(interface)[netifaces.AF_INET][0]['addr']
    except (ValueError, KeyError):
        ip_address = None
    hostname = socket.gethostname()
    return ip_address, hostname

def send_data(ip, hostname):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((SERVER_IP, SERVER_PORT))
        message = f"{ip},{hostname}"
        s.sendall(message.encode('utf-8'))
        response = s.recv(1024)
        print('Received', repr(response))

def main():
    interface = 'eno1'
    
    while True:
        ip, hostname = get_ip_address(interface)
        if ip:
            break
        print("Waiting for valid IP address...")
        time.sleep(5)

    send_data(ip, hostname)

if __name__ == "__main__":
    main()

2021/9/9

script to generate script : document here

ref: 用
cat << EOF > aaaa
this is line one
and two
EOF
可以用來產生 aaaa,內容就是 this is line one,
command 意思是 一直到 EOF,都 cat 出來。
後面的 > aaaa 就是把 cat 出來的東西都放到 aaaa 中。

這個command在 shell script中來create 一個 shell script。
也就是在 "this is line one" 到 EOF 的區域放要產生的 shell script 內容。

因為都是 shell script ,所以為了保險,不要讓 這個 script 處理內容出現問題,可以用
cat << "EOF"
代表 把 EOF 之間的內容都當作 字串處理。
這樣就不用擔心特殊字元的問題。

當然,特殊字元也可以用 跳脫符號 "\",但是只會對特殊字元跳脫。

2021/9/5

Mobilenet

我一直以為是數學上相等的(推導),一直到這一篇才比較清楚。
mobilenet 利用計算量少的方式,產生一樣維度的output featuremap。
至於等不等效,就用實際training 來證明。
原來是一次conv計算+一個active function 就可以得到 feature map。
變成兩次conv計算,兩次active functiom 才能得到(一樣大小.數量的)feature map。也就是說,網路的深度增加了。

depth 指的是 color,例如 RGB 三個就是 depth。而不是網路的深度(層數)
原來的 convolution 都是一個kernel 就要包含三個 matrix (R.G.B)分別對 input 的 R.G.B 做各自的 convolution 後,經過 active function加起來變成一個 matrix (feature map)。
depthwise就是三個 R.G.B 做完各自的 convolution 後,用各自的 active function 做出各自的 matrix (feature map),不要變成一個。
之後再用 1x3 的 kernel 把 R.G.B feature map 經果 activae function 轉成一個 matrix。
這樣舊跟以往的 convolution 一樣的。

做 R.G.B convolution 時,維持分開,不用一個acitvie function 加在一起,所以說是 depthwise separable convolution

2021/9/2

mender : modify product device to use local demo server

先啟動 demo server。
在 source code 中找到 demo.crt
修改 /etc/mender/mender/conf :
參考mender.io build and install client from sources 看設定為 demo 的 conf:

device 的部份:
  • 依照 mender.conf 的 Servers : ServerURL 作為 update server
  • ServerCertificate 有的話,用這個作為 跟 server 溝通的憑證
# diff /data/backup/mender.conf /etc/mender/mender.conf 
--- /data/backup/mender.conf
+++ /etc/mender/mender.conf
@@ -24,13 +24,13 @@
     "StateScriptRetryTimeoutSeconds": 0,
     "StateScriptRetryIntervalSeconds": 0,
     "ModuleTimeoutSeconds": 0,
-    "ServerCertificate": "",
+    "ServerCertificate": "/data/demo.crt",
     "ServerURL": "",
     "UpdateLogPath": "",
-    "TenantToken": "eyJI......",
+    "TenantToken": "",
     "Servers": [
         {
-            "ServerURL": "https://hosted.mender.io"
+            "ServerURL": "https://docker.mender.io"
         }
     ]
 }
ServerURL 好像一定要概,不然會出現 Error:
level=error msg="Failure occurred while executing authorization request: Method: Post, URL: https://host.mender.io/api/devices/v1/authentication/auth_requests" func="github.com/mendersoftware/me
level=error msg="Authorize failed: transient error: authorization request failed: transient error: authorization request failed: Unknown url.Error type: Host validation error" func="github.com/m
level=info msg="State transition: authorize [Sync] -> authorize-wait [Idle]" func=github.com/mendersoftware/mender/app.transitionState file="/home/pi/mender-src/app/mender.go:461"
一定要用 docker.mender.io 的原因可能是因為 demo server 的 hosts 有加:
127.0.0.1 s3.docker.mender.io
127.0.0.1 docker.mender.io
demo.crt copy 過來,mender.conf只要改成這樣, demo server 上就可以看到 request device

demo server 基本照這個。
其中,docker 的機器要改 /etc/hosts,加上上面的 mender.io 指到 127.0.0.1