2024/11/24

Simple URL RAG with ollama locally

這篇就是翻譯下面這個 link,source code 也是下面這個 link 的 code: 文章中,embedding 用了 openai,為了作到完全 local,改用 OllamaEmbeddings

url rag 做的大概是..
列出url,把所有 url 讀進來,把內容攤平成一維
import os
os.environ['USER_AGENT'] = 'myagent'

from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# List of URLs to load documents from
urls = [
    "https://lilianweng.github.io/posts/2023-06-23-agent/",
    "https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/",
    "https://lilianweng.github.io/posts/2023-10-25-adv-attack-llm/",
]
# Load documents from the URLs
docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]
再把網頁內容分成一小段一小段
# Initialize a text splitter with specified chunk size and overlap
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=250, chunk_overlap=0
)
# Split the documents into chunks
doc_splits = text_splitter.split_documents(docs_list)
把這些一小段一小段的句子,轉成 embedding,也就是一個 N 維 tensor。
因為要 run locally,所以用 OllamaEmbeddings 來做:
from langchain_ollama import OllamaEmbeddings

embeddings = OllamaEmbeddings(
    model="llama3",
)
所有字句轉成 embedding/tensor 後,要放到一個 local 的 database 里,讓𠹌一下 user 問問題的時候,來databasae 找答案。
這邊用 SKLearnVectorStore 這個 database :
from langchain_community.vectorstores import SKLearnVectorStore
from langchain_openai import OpenAIEmbeddings
# Create embeddings for documents and store them in a vector store
vectorstore = SKLearnVectorStore.from_documents(
    documents=doc_splits,
    embedding=embeddings,
)
retriever = vectorstore.as_retriever(k=4)
RAG 的 vectorstore 和 sql 不同的地方是,在 query 時,vecrotstore 給的是最接近 query 的內容,而不是像 sql 一樣,要完全 match 的 data。

url 資料都準備好了,接下來就是 ollama 對接 LLM 的部份。
prompt template. TAG process chain.
from langchain_ollama import ChatOllama
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Define the prompt template for the LLM
prompt = PromptTemplate(
    template="""You are an assistant for question-answering tasks.
    Use the following documents to answer the question.
    If you don't know the answer, just say that you don't know.
    Use three sentences maximum and keep the answer concise:
    Question: {question}
    Documents: {documents}
    Answer:
    """,
    input_variables=["question", "documents"],
)

# Initialize the LLM with Llama 3.1 model
llm = ChatOllama(
    model="llama3.1",
    temperature=0,
)

rag_chain = prompt | llm | StrOutputParser()
做出 RAG class:
# Define the RAG application class
class RAGApplication:
    def __init__(self, retriever, rag_chain):
        self.retriever = retriever
        self.rag_chain = rag_chain
    def run(self, question):
        # Retrieve relevant documents
        documents = self.retriever.invoke(question)
        # Extract content from retrieved documents
        doc_texts = "\\n".join([doc.page_content for doc in documents])
        # Get the answer from the language model
        answer = self.rag_chain.invoke({"question": question, "documents": doc_texts})
        return answer
用這個 RAG class 來測試
# Initialize the RAG application
rag_application = RAGApplication(retriever, rag_chain)
# Example usage
question = "What is prompt engineering"
answer = rag_application.run(question)
print("Question:", question)
print("Answer:", answer)
輸出會是..
Question: What is prompt engineering
Answer: Prompt engineering is the process of designing and optimizing input prompts for language models, such as chatbots or virtual
assistants. According to Lilian Weng's 2023 article "Prompt Engineering", this involves techniques like word transformation, character 
transformation, and prompt-level obfuscations to improve model performance. The goal is to create effective and efficient prompts that 
elicit accurate responses from the model.


其他的 ref,用 web UI

2024/11/20

AI toolkit for VSCode: config to use ollama

這個雖然現在好像還沒有什麼功能,但是好像是唯一不用付錢的 ai assistant.
最新的更新支援 local ollama 了,所以來試試看。

原來 這個 extension 的說明文件都在github : doc: overview
要使用 ollama 的話,首先當然要 setup 好自己的 ollama service (ref:ollama run llama locally)
記得要對 local ip 開放。

ai toolkit 設定部分,在安裝完後,VS Code 左邊 panel 會多一個 item,ai toolkit item,
最上面,My Models 右邊的 "+" 按下去,會出現 Add remote model (1/4),意思是有四個步驟,現在做第一步。
第一步是設定 ollama url,我的就是
http://192.168.145.64:11434/v1/chat/completions
Enter 後,第二步,要 load 的 model name。
這部分,到 ollama sever 上,用 ollama list 列出,挑出要load 的 model name,要全名。
qwen2.5-coder:14b
Enter 後第三步是名子,給這格 model setup 的name,隨便。
最後一步是authetication key,ollama 不需要,所以 Enter w就可以。

2024/11/19

Try Web front end for whisper

先來試試 他是用Grandio 做 whisper 的 web front end
python 用 3.11,然後 clone source ans install requirements
git clone https://github.com/jhj0517/Whisper-WebUI.git
cd Whisper-WeUI
pip install -r requirements.txt
因為我用 conda ,所以把 start-webui.sh的 venc/bin/activate comment 掉。
然後用 public serv:
./start-webui.sh --server_name=0.0.0.0b --inbrowser=false
把影片拖到網頁,選 large-v2,輸出 srt,開始...
看 console output 是開始下載model...所以網頁的 progress bar 沒有動作。
model download 完,開始轉換....
結果出現 Error:
Unable to load any of {libcudnn_ops.so.9.1.0, libcudnn_ops.so.9.1, libcudnn_ops.so.9, libcudnn_ops.so}
參考 Downgrade ctranslate2:
pip install ctranslate2==4.4.0
之後,就沒 Error 了。

實際測試各個 model,發現並不是越大就越好。
在轉換長影片(2:30)時,越 1:00 後的文字出現問題,一直重復。

2024/11/7

Stable Diffusion and ControlNet

stable diffusion 用 webui 他會自己Download and install,雖然script 是用 VENV,但是還是用 conda create 一個python==3.8.10 的環境來run
跟平時依樣,但是第一次 run, 他會發現是第一次,然後自動 download and install
./webui.sh --listen
model checkpoint 要自己去 huggingface download.
比較多文件說明,還有沒有 license 問題的是 v 1.5 download 整個 project/file 下來,放到 models/Stable-diffusion 目錄下


安裝 ControlNet:

用 webui 來裝:
因為是在 headless server 上 run,所以要加上 --listen 允許在 lan 上access,這樣要 install extension 就會出現錯誤
 AssertionError: extension access disabled because of command line flags
所以要增加 options:
$ ./webui.sh --listen --enable-insecure-extension-access
download and install 完,console command 會出現
/mnt/hdd8t/charles-chang/stablediffusion/stable-diffusion-webui/venv/lib/python3.10/site-packages/huggingface_hub/file_download.py:797:
FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. 
If you want to force a new download, use `force_download=True`.
  warnings.warn(
Applying attention optimization: Doggettx... done.
Model loaded in 3.9s (load weights from disk: 2.8s, create model: 0.2s, apply weights to model: 0.8s).
Installing sd-webui-controlnet requirement: fvcore
Installing sd-webui-controlnet requirement: mediapipe
Installing sd-webui-controlnet requirement: svglib
Installing sd-webui-controlnet requirement: addict
Installing sd-webui-controlnet requirement: yapf
Installing sd-webui-controlnet requirement: changing albumentations version from None to 1.4.3
Installing sd-webui-controlnet requirement: changing timm version from 1.0.11 to 0.9.5
Installing sd-webui-controlnet requirement: changing pydantic version from 1.10.19 to 1.10.17
Installing sd-webui-controlnet requirement: changing controlnet_aux version from None to 0.0.9
Installing sd-webui-controlnet requirement: onnxruntime-gpu
ControlNet init warning: Unable to install insightface automatically. Please try run `pip install insightface` manually.
Installing sd-webui-controlnet requirement: handrefinerportable
Installing sd-webui-controlnet requirement: depth_anything
Installing sd-webui-controlnet requirement: depth_anything_v2
Installing sd-webui-controlnet requirement: dsine
等好久,完成,webui 會出現小字:
Installed into /mnt/hdd8t/charles-chang/stablediffusion/stable-diffusion-webui/extensions/sd-webui-controlnet. Use Installed tab to restart.
然後在 Installed 的表格最後會有:
-----------------------------------------------------------------------------------------------------------------------
|sd-webui-controlnet	| https://github.com/Mikubill/sd-webui-controlnet |	main | 56cec5b2	| 2024-07-26 04:52:52 | unknown |
ControlNet 也是一個model,所以也要 download checkpoint.

2024/10/25

install pytorch with mcp support

開啟 ssh server 後就可以用 ssh 登入。
下載 Miniconda3-latest-MacOSX-arm64.sh, 執行。
最後一樣會修改 .zshrc
一樣刪掉,放到 condaenv.sh

一樣, 但是default python 好像是 3.13 太新。torchvision 安裝會有問題。
所以要指定
conda create -n pytorch python==3.11
完成後,進入 pytorch env, follow apple support的說明 (要用 nightly channel):
conda install pytorch torchvision torchaudio -c pytorch-nightly
測試:
>> import torch
>> torch.backends.mps.is_available()
True
所以有 support metal GPU

另外,mps 是 metal GPU
Neural Engine 是 pytorch-lightning

2024/10/23

SSD 筆記 (Single-Shot Detector)

ref: 和yolov1 一樣,重點在設計最後的 output label.

把 yolov1 的最後 NxN 格換成預先定義好的框
框的大小固定的話,要怎麼fit 到不同大小的 object ?
就把不同大小的 featuremap 來用。

經過 CNN, 和 stride=2 之後的 feature map 會縮小。
在縮小的 feature map 上,同樣大小的眶,框住的比例就變大了。

所以 SSD 會把多個 layer 的 fearture map 拿出來做 CNN, 都做出該層的 框框 location 和 confidence.

好複雜

和 Yolov1 一樣,就是在設計 output label 的解釋和格式,

conv.relu - conv.relu - maxpool - ...

這樣的 network 中的某幾層,讓 stride = 2,output feature map 的 size 就會變 1/2.
(所有的 conv 都會加 padding,讓stride=2 時,output size 不變)

在末端的幾層 feature 做 object detection

2024/10/20

Set battery charge limit in ubuntu 24.04

ref: 上次買的 lenovo legion 在 windows 7 下有電池充到 80% 的功能。
覺得這樣電池好像活得比較久,所以想在ubuntu 看看有沒有一樣的功能。

看起來是 tlp 這個 package
follow 說明
sudo apt install tlp tlp-rdw
sudo systemctl enable tlp
syudo systemctl start tlp
然後修改 /etc/tlp.conf
# Battery charge level below which charging will begin.
START_CHARGE_THRESH_BAT0=65
# Battery charge level above which charging will stop.
STOP_CHARGE_THRESH_BAT0=80
然後再啟動
$sudo tlp start
TLP started in battery mode (auto).

$ sudo tlp-stat -b
--- TLP 1.6.1 --------------------------------------------

+++ Battery Care
Plugin: asus
Supported features: none available
Driver usage:
* natacpi (asus_wmi) = inactive (laptop not supported)

+++ Battery Status: BAT1
/sys/class/power_supply/BAT1/manufacturer                   = GIGABYTE
/sys/class/power_supply/BAT1/model_name                     = Aorus 15
/sys/class/power_supply/BAT1/cycle_count                    =      0 (or not supported)
/sys/class/power_supply/BAT1/charge_full_design             =   6514 [mAh]
/sys/class/power_supply/BAT1/charge_full                    =   6514 [mAh]
/sys/class/power_supply/BAT1/charge_now                     =   6258 [mAh]
/sys/class/power_supply/BAT1/current_now                    =   1066 [mA]
/sys/class/power_supply/BAT1/status                         = Discharging

Charge                                                      =   96.1 [%]
Capacity                                                    =  100.0 [%]

看來沒效,因為 laptop not supported
NB 是 Gigabyte AORUS 15X, i9RTX4090
看來還是買 lenovo 還是 asus 比較保險。

不然就要參考:優化 Ubuntu 電池壽命
另外,這邊 有 support list: ASUS, MSI, LG,Lenovo, Samsung, SONY, Toshiba. Apple
--- 所以沒有 Acer 跟 Gigabyte,要用 ubuntu 的話,記得不要買這兩家的 NB

2024/10/19

Yolov1 筆記

ref:
原來yolov1 的 label 是: object 的中心是否在這個方格中心 ?
所以不是物件影像包含的方格,label 都會有值。
只有包含物件中心點的方格,label 會有值。

然後 label 的內容,就是:
  • 物件中心的位置
  • 物件的寬和高
  • 物件的種類

在 pytorch 2.4.1 上測試 ref 的 code 會有Error,所以修改了,放在
從這個實作可以看到,yolov1 的converlution layer 用了 resnet50 的,也就是普通的CNN,後面用 兩個 fully connection layer 轉成 output.
train 的時候直接用 pretain 好的 CNN 層,甚至 fix 住,不做grade, 只靠兩個 fully connection layer,就要生出設計的 label 格式:

yolov1 設計的 output 的表示方式:
  • 7 x 7 的方塊
  • 每個方塊有一個 outputlabel 資料
  • output label 的內容是...
然後就把 VOC 的label Data轉成自己規定的格式,用這個格式去 train,讓中間的兩格 converlution layer train 出他要的結果。

所以可以說,yolo 的精隨,就是他發明的output labeling.
雖然只用了兩層 fully connection layer 就完成他要的轉換。但是這兩層各有 512 個 cell....

2024/10/4

vlc open rtsp fail, server side error message

[INFO  rtsp_demo.c:408:rtsp_new_client_connection] new rtsp client 10.42.0.1:47890 comming
[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
SETUP rtsp://10.42.0.63:554/live/0 RTSP/1.0
CSeq: 0
Transport: RTP/AVP;unicast;client_port=9298-9299

[DEBUG rtsp_demo.c:950:rtsp_handle_SETUP]
[WARN  rtsp_demo.c:980:rtsp_handle_SETUP] rtsp urlpath:/live/0 err
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 461 Unsupported Transport
CSeq: 0
Date: Fri Oct  4 16:17:52 2024
Server: rtsp_demo

[INFO  rtsp_demo.c:408:rtsp_new_client_connection] new rtsp client 10.42.0.1:47902 comming
[DEBUG rtsp_demo.c:1158:rtsp_recv_msg] peer closed
[INFO  rtsp_demo.c:427:rtsp_del_client_connection] delete client 86 from 10.42.0.1
[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
OPTIONS rtsp://10.42.0.63:554 RTSP/1.0
CSeq: 1
User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)
ClientChallenge: 9e26d33f2984236010ef6253fb1887f7
PlayerStarttime: [28/03/2003:22:50:23 00:00]
CompanyID: KnKV4M4I/B2FjJ1TToLycw==
GUID: 00000000-0000-0000-0000-000000000000
RegionData: 0
ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586

[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: ClientChallenge: 9e26d33f2984236010ef6253fb1887f7
[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: PlayerStarttime: [28/03/2003:22:50:23 00:00]
[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: CompanyID: KnKV4M4I/B2FjJ1TToLycw==
[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: GUID: 00000000-0000-0000-0000-000000000000
[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: RegionData: 0
[WARN  rtsp_msg.c:888:rtsp_msg_parse_from_array] unknown line: ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586
[DEBUG rtsp_demo.c:725:rtsp_handle_OPTIONS]
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 1
Date: Fri Oct  4 16:17:53 2024
Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN
Server: rtsp_demo

[DEBUG rtsp_demo.c:1158:rtsp_recv_msg] peer closed
[INFO  rtsp_demo.c:427:rtsp_del_client_connection] delete client 87 from 10.42.0.1

OK 的版本,使用 ffplay
ffplay "rtsp://10.42.0.254/live/0"
server 端 log
[INFO  rtsp_demo.c:408:rtsp_new_client_connection] new rtsp client 10.42.0.1:35114 comming
[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
OPTIONS rtsp://10.42.0.254:554/live/0 RTSP/1.0
CSeq: 1
User-Agent: Lavf60.16.100

[DEBUG rtsp_demo.c:725:rtsp_handle_OPTIONS]
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 1
Date: Fri Jan  1 12:16:08 2021
Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN
Server: rtsp_demo

[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
DESCRIBE rtsp://10.42.0.254:554/live/0 RTSP/1.0
Accept: application/sdp
CSeq: 2
User-Agent: Lavf60.16.100

[DEBUG rtsp_demo.c:746:rtsp_handle_DESCRIBE]
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 2
Date: Fri Jan  1 12:16:08 2021
Server: rtsp_demo
Content-Type: application/sdp
Content-Length: 479

v=0
o=- 0 0 IN IP4 0.0.0.0
s=rtsp_demo
t=0 0
a=control:rtsp://10.42.0.254:554/live/0
a=range:npt=0-
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
a=rtpmap:96 H265/90000
a=fmtp:96 sprop-vps=QAEMAf//AWAAAAMAgAAAAwAAAwCWvAk=;sprop-sps=QgEBAWAAAAMAgAAAAwAAAwCWoAEgIAURY2+7ymbgICAggAAAAwCAAAAMhA==;sprop-pps=RAHAcoaNQTZA
a=control:rtsp://10.42.0.254:554/live/0/track1
m=audio 0 RTP/AVP 97
c=IN IP4 0.0.0.0
a=rtpmap:97 PCMA/8000/2
a=control:rtsp://10.42.0.254:554/live/0/track2
[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
SETUP rtsp://10.42.0.254:554/live/0/track1 RTSP/1.0
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
CSeq: 3
User-Agent: Lavf60.16.100

[DEBUG rtsp_demo.c:950:rtsp_handle_SETUP]
[INFO  rtsp_demo.c:894:rtsp_new_rtp_connection] new rtp over tcp for video ssrc:2234567c peer_addr:10.42.0.1 interleaved:0-1
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 3
Date: Fri Jan  1 12:16:08 2021
Session: 1234567A
Transport: RTP/AVP/TCP;ssrc=2234567C;interleaved=0-1
Server: rtsp_demo

[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
SETUP rtsp://10.42.0.254:554/live/0/track2 RTSP/1.0
Transport: RTP/AVP/TCP;unicast;interleaved=2-3
CSeq: 4
User-Agent: Lavf60.16.100
Session: 1234567A

[DEBUG rtsp_demo.c:950:rtsp_handle_SETUP]
[INFO  rtsp_demo.c:894:rtsp_new_rtp_connection] new rtp over tcp for audio ssrc:2234567d peer_addr:10.42.0.1 interleaved:2-3
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 4
Date: Fri Jan  1 12:16:08 2021
Session: 1234567A
Transport: RTP/AVP/TCP;ssrc=2234567D;interleaved=2-3
Server: rtsp_demo

[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
PLAY rtsp://10.42.0.254:554/live/0 RTSP/1.0
Range: npt=0.000-
CSeq: 5
User-Agent: Lavf60.16.100
Session: 1234567A

[DEBUG rtsp_demo.c:1037:rtsp_handle_PLAY]
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 5
Date: Fri Jan  1 12:16:08 2021
Session: 1234567A
Server: rtsp_demo

[ntp.c][rkipc_ntp_update]:connect error
[DEBUG rtsp_msg.c:865:rtsp_msg_parse_from_array]
OPTIONS rtsp://10.42.0.254:554/live/0 RTSP/1.0
CSeq: 6
User-Agent: Lavf60.16.100
Session: 1234567A

[DEBUG rtsp_demo.c:725:rtsp_handle_OPTIONS]
[DEBUG rtsp_msg.c:998:rtsp_msg_build_to_array]
RTSP/1.0 200 OK
CSeq: 6
Date: Fri Jan  1 12:16:38 2021
Session: 1234567A
Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN
Server: rtsp_demo

2024/10/3

C++ Reflection

忘記列出library source 了...
這是別人的 library.

struct Node {
    std::string key;
    int value;
    std::vector<Node> children;

    REFLECT()       // Enable reflection for this type
};
REFLEC( ) 是:
define REFLECT() \
    friend struct reflect::DefaultResolver; \
    static reflect::TypeDescriptor_Struct Reflection; \
    static void initReflection(reflect::TypeDescriptor_Struct*);

所以是在 structure 中增加一個 static variable 和 一個function
Reflection,
initReflection()
然後還有宣告
/ Define Node's type descriptor
REFLECT_STRUCT_BEGIN(Node)
REFLECT_STRUCT_MEMBER(key)
REFLECT_STRUCT_MEMBER(value)
REFLECT_STRUCT_MEMBER(children)
REFLECT_STRUCT_END()
就是依序把Node struct 的 member 宣告一下。
這部份解開就是
    reflect::TypeDescriptor_Struct Node::Reflection{type::initReflection}; 
    void Node::initReflection(reflect::TypeDescriptor_Struct* typeDesc) { 
        using T = Node; 
        typeDesc->name = "Node"; 
        typeDesc->size = sizeof(Node); 
        typeDesc->members = {
        
            {"key",      offsetof(Node, key),      reflect::TypeResolver<std:tring>::get()},
            {"value",    offsetof(Node, value),    reflect::TypeResolver<int>::get()},
            {"children", offsetof(Node, children), reflect::TypeResolver<std:vector<Node>>::get()},
            
        };
    }
main( ) 在告完 Node 變數後,就呼叫:
   reflect::TypeDescriptor* typeDesc = reflect::TypeResolver<Node>::get();
看一下 reflect::TypeResolver<Node>::get*(),template 展開
struct TypeResolver {
    static TypeDescriptor* get() {
        return DefaultResolver::get<Node>();
    }
};
DefaultResolver:get 也是 template:
// This version is called if T has a static member named "Reflection":
    template <typename T, typename std::enable_if<IsReflected<T>::value, int>::type = 0>
    static TypeDescriptor* get() {
        return &T::Reflection;
    }

    // This version is called otherwise:
    template <typename T, typename std::enable_if<!IsReflected<T>::value, int>::type = 0>
    static TypeDescriptor* get() {
        return getPrimitiveDescriptor<T>();
    }
先解開
template <typename T, typename std::enable_if<IsReflected<T>::value, int>::type = 0>
用 std::enable_if 來區分要用那一個
std::enable_if<IsReflected<T>::value, int>::type = 0
enable_if 的 boolean 是 IsRlected<T>::value
IfReflected 是
    struct IsReflected {
        enum { value = (sizeof(func<T>(nullptr)) == sizeof(char)) };
    };
value 的值是 true or false:
(sizeof(func<T>(nullptr)) == sizeof(char)) 
func<T>(nullptr) 有兩個定義,由 T 沒有 member variable : Reflection 決定。Node 有,所以func 是..
template <typename T> static char func(decltype(&T::Reflection));
所以是sizeof(char),所以 value 是 true,也就是 IsReflected<Node>::value 是 true
配合 std::enable_if 用...
   template <typename T, typename std::enable_if<IsReflected<T>::value, int>::type = 0>
    static TypeDescriptor* get() {
        return &T::Reflection;
    }
所以是main( ) 中呼叫 :: get( ) 會回傳,Node::Reflection

之後 typeDesc->dump(&node);
就是 static reflect::TypeDescriptor_Struct 的 dump() :
    virtual void dump(const void* obj, int indentLevel) const override {
        std::cout << name << " {" << std::endl;
        for (const Member& member : members) {
            std::cout << std::string(4 * (indentLevel + 1), ' ') << member.name << " = ";
            member.type->dump((char*) obj + member.offset, indentLevel + 1);
            std::cout << std::endl;
        }
        std::cout << std::string(4 * indentLevel, ' ') << "}";
    }

2024/9/22

protobuf and onnx

protobuf 提供了 structure 到 binary 的讀/寫 定義方式。
在 abc.proto 中定義了 structure.
再用 protoc 產生 C or python code,就會有 serializetostring 和 parsefromstring 兩個 讀/寫 檔的 function.

onnx 就是利用 protobuf 來做onnx

2024/9/20

RV1106 luckfox pico build and download

rv1106 的燒錄工具是 Soctoolkit,不是 Rkdevtool.
Soctoolkit 的 partition layout 是在 env.image.
類似 Rkdevtool 的parmeter.txt

以 Luckfox Pico為例,要進入 bootrom (MASKROM) 的方式是按著 boot 按鍵開機。
因為 Type C 兼顧供電與通訊,所以就是按著boot 鍵,插入 usb,放掉 boot 鍵。
這樣就會進入 maskrom,然後 Soctoolkit 就會顯示 USB : MASKROM 版本

之後在 search path 選到 sdk build 玩的 image 目錄 (例如 ~\luckfox-pico\IMAGE\SPI_NAND_RV1106G-LUCKFOX-PICO-PRO-MAX.DTS_20240920.1158_RELEASE_TEST\IMAGES)
他就會自己找到 env.image, load 完後,所有 partition 和 img file 都會列出來。

2024/9/6

新 android 的一些 build 動作改變

上次做Android 是 android 6 還是 8,現在已經是14 了。
紀錄一下現在的樣子。

showcommands

已經不用 showcommands,反而是會把 build log 放到 out/verbose.log.X.gz

partitions

用 device-mapper 而不是直接 mount。
所以 mount 看到的都是 /dev/block/dm-0,1,...

另外,有包含很多 partition 的 super partition
對應 super.img 的工具有:
  • lpmake
  • simg2img
  • lpunpack

2024/9/5

test gdb step into virtual function

#include <iostream>
#include <cstdlib>
#include <ctime>

class Base {
public:
    virtual void show() {
        std::cout << "Base class show function" << std::endl;
    }
    virtual ~Base() = default;
};

class Derived1 : public Base {
public:
    void show() override {
        std::cout << "Derived1 class show function" << std::endl;
    }
};

class Derived2 : public Base {
public:
    void show() override {
        std::cout << "Derived2 class show function" << std::endl;
    }
};

void callShow(Base* obj) {
    obj->show();
}

int main() {
    std::srand(std::time(0)); // 設定亂數種子
    Base* b;

    if (std::rand() % 2 == 0) {
        b = new Derived1();
    } else {
        b = new Derived2();
    }

    callShow(b);
    delete b;
    return 0;
}

2024/9/2

gitlab api , set default branch

ref:

gitlab ce 的rest api 的url 是
http://gitlab.loyaltek.com/api/v4/
之後就是 rest api 的 api resource,例如 projects, groups, users..

gitlab 的 rest api resource 頁面,以runners 為例。
GET /runners/:id/jobs
就是說:
  • http method : GET
  • uri endpoint: /runners/:id/jobs
所以用 curl 就是:
curl -X GET -H "PRIVATE-TOKEN=XXXXX" -url "http://gitlab.loyal.com/api/v4/runners/:id/jobs"
其中 :id 是指 gitlab 中的 project。

gitlab 的所有project,都有一個 id,例如 MISC/testwebapi2:


上面例子的 :id 就是改成 3756。

:id 其實有兩種表示法,一種是剛剛說的 unique id。
另一種就是 namespaced path encoding.

以上面 MISC/testwebapi2 為例,要是完整寫進 url 中, "/" 就會跟後面的 /jobs 混淆。
所以 project 的 path 中的 "/" 要改成 "%2F" : MISC%2Ftestwebapi2

也就是說,上面的例子, :id 可以是 3756,也可以是 MISC%2Ftestwebapi2


request header 的 token 就去 gitlab 的頁面create 一個。
可以在user 的頁面create,也可以在 project, group 的setting create,每個地方 create 的 token,應用範圍不一樣。

有關 set default branch...

第一篇是說:
DEFAULT_BRANCH="develop"
sleep 5
$(curl -sS -X $METHOD \
    -H "PRIVATE-TOKEN: $GITLAB_TOKEN" \
    --url "$GITLAB_URL/projects/$1" \
    --data "default_branch=$DEFAULT_BRANCH")

例如,create new project in subgroup:
curl --request POST --header "PRIVATE-TOKEN: glpat-FtpBssK5S5U6UMdkmcvL" \
 --data "name=testwebapi2" \
 --data "namespace_id=197" \
 "http://gitlab.loyaltek.com/api/v4/projects"
這個 namespace_id 就是 subgroup 的 id,在 gitlab 的 group 頁面,會有 id: 197

project 指定可以用 id (gitlab 的subgroup, project 都有 id)
也可以用 namespace (就像是 path)
不過 path 的 '\' 要改成 %2F

所以 /misc/testwebapi2,project id 是 3756,要 create new branch 可以:
curl --request POST --header "PRIVATE-TOKEN: glpat-FtpBssK5S5U6UMdkmcvL" \
 --url "http://gitlab.loyaltek.com/api/v4/projects/3756/repository/branches?branch=newbranch&ref=master"
 
或是
curl --request POST --header "PRIVATE-TOKEN: glpat-FtpBssK5S5U6UMdkmcvL" \
 --url "http://gitlab.loyaltek.com/api/v4/projects/MISC%2Ftestwebapi2/repository/branches?branch=newbranch2&ref=master"
也就是 url中,projects 後的 id 3756 改成 MISC/testwebapi2,因為要把 "/" 改掉以免線後麵的 repository 混搖,所以規定改成 %2F



要設定 default_branch 的話,就是參考 edit project 的範例:
API 是:
PUT /projects/:id
  • METHOD : PUT
  • resource: projects
project attrib 有 default_branch, value type 是 string。
id 可以用 project id,或是用 pathname (/ 改 %2F)
所以,設定 MISC/testwebapi2 的 defultbranch 是 newbranch2:
curl --request PUT --header "PRIVATE-TOKEN: glpat-FtpBssK5S5U6UMdkmcvL" \
 --url "http://gitlab.loyaltek.com/api/v4/projects/MISC%2Ftestwebapi2" \
 --data "default_branch=newbranch"

2024/8/9

修復epub -- for google books

google books 常常會 process fail, 不知道是什麼原因。
原來有修復的方法: 原來就是用calibre這個軟體,加入 epub,然後 "ˋ轉換書本",
本來這個功能是要把 其他格式的文件轉成 epub用的,
現在是從 epub 轉 epub

轉的時候還可以加上封面。
轉完儲存就可以有新的 epub



linux 安裝 default 是裝在系統 /opt ,所以需要 root 權限。
如果裝在 自己的 home 就不用。
wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin install_dir=~/calibre-bin isolated=y
其實就 download script 下來,run 的時候再加上 option 就可以了。

2024/6/25

rearrage local repo to mirror format

用.repo提供bsp,不給 repo server access 權限的。
自己要做 repo mirror.
用repo forall 來run 這個:
$ cat pp.py
#!/usr/bin/python
import os
import subprocess

rfolder ='/home/charles-chang/rr3/'
lfolder ='/home/charles-chang/MY_Android14/'

repo_project = os.getenv('REPO_PROJECT','test/demo')
repo_path = os.getenv('REPO_PATH','repomirror')

pname = rfolder + os.path.dirname(repo_project)
print(f"REPO_PROJECT: {repo_project} {pname}")
print(f"REPO_PATH: {repo_path}")

os.makedirs(pname,exist_ok=True)
tname = rfolder + repo_project +'.git'
print(f"{tname}")

result = subprocess.run(["git","clone","--no-local","--mirror",lfolder+repo_path,tname])
就是:
repo forall -c /home/charles-chang/pp.py
就會create一個 repo server folder: rr3

第一步,repo sync -l 後,要做 git clone 其中的 project,會出現 Error:
結果是因為 symbolic link 的關係: 所以mirror 的時候要加上 --no-local

結果 .repo/project-object 裡面的 folder 安排方式就是 mirror 的方式,可惜 git 內容不是 mirror 的...

一些問題:

repo init 指定 -m XXX時,不單純只是把 manifest.xml 內容寫成 include XXX,同時會讀取 XXX 的內容,如果有問題,就會出現 Error,
然後這個 repo init 命令就會 Fail

manifests.git 所在位置和 manifest.xml 中,remote tag 的 fetch 有關,fetch="..\.." 的話,manifests.git 就要在 跟目錄的下一層通常是 platform 下。
如果直接在 project root,就用 fetch=".." 就可以。


做 repo sync動作時,會把git commit 內容輸出到 .repo/TRACE_FILE。
或是(舊版?),宣告環境變數 REPO_TRACE=1,可以輸出 Trace( ) 到 stdout.

同樣的,git 也可以輸出trace 就是用
GIT_CURL_VERBOSE=1
GIT_TRACE=1

2024/6/21

test raspberry pi 3 and camera v1.3

用的os 是: debian 11 (bullseye

camera上面有寫 "raspberry pi camera rev 1.3
這邊 的表格,v1 是 ov5647
所以到 /sys/module/ 下,果然有 ov5647 這個folder

然後看 這一篇,v1 的 camera support libcamera/raspicam
因為是 v1,所以好像不用修改 boot 的 config

測試:
$ sudo libcamera-hello -t 0
Preview window unavailable
[1:33:11.091798541] [1024]  INFO Camera camera_manager.cpp:297 libcamera v0.0.5+83-bde9b04f
[1:33:11.156468415] [1026]  INFO RPI vc4.cpp:437 Registered camera /base/soc/i2c0mux/i2c@1/ov5647@36 to Unicam device /dev/media3 and ISP device /dev/media0
[1:33:11.156605706] [1026]  INFO RPI pipeline_base.cpp:1101 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[1:33:11.158376798] [1024]  INFO Camera camera.cpp:1033 configuring streams: (0) 1296x972-YUV420
[1:33:11.159185495] [1026]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1296x972-SGBRG10_1X10 - Selected unicam format: 1296x
972-pGAA
#0 (0.00 fps) exp 33222.00 ag 8.00 dg 1.00
#1 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#2 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#3 (30.01 fps) exp 33222.00 ag 8.00 dg 1.00
#4 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#5 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#6 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#7 (30.01 fps) exp 33222.00 ag 8.00 dg 1.00
..
試拍照:
$ libcamera-jpeg -o aaa.jpg 
Preview window unavailable
[0:09:19.152281879] [3180]  INFO Camera camera_manager.cpp:297 libcamera v0.0.5+83-bde9b04f
[0:09:19.216393888] [3181]  INFO RPI vc4.cpp:437 Registered camera /base/soc/i2c0mux/i2c@1/ov5647@36 to Unicam device /dev/media3 and ISP device /dev/media0
[0:09:19.216530450] [3181]  INFO RPI pipeline_base.cpp:1101 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[0:09:19.218294460] [3180]  INFO Camera camera.cpp:1033 configuring streams: (0) 1296x972-YUV420
[0:09:19.219118835] [3181]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1296x972-SGBRG10_1X10 - Selected unicam format: 1296x972-pGAA
#0 (0.00 fps) exp 9983.00 ag 1.31 dg 1.53
#1 (30.02 fps) exp 9983.00 ag 1.31 dg 1.54
#2 (30.02 fps) exp 10284.00 ag 2.00 dg 1.00
,...
#138 (30.02 fps) exp 14603.00 ag 2.00 dg 1.00
#139 (30.02 fps) exp 14626.00 ag 2.00 dg 1.00
#140 (30.02 fps) exp 14672.00 ag 2.00 dg 1.00
#141 (30.02 fps) exp 14672.00 ag 2.00 dg 1.00
[0:09:24.419749856] [3180]  INFO Camera camera.cpp:1033 configuring streams: (0) 2592x1944-YUV420 (1) 2592x1944-SGBRG10_CSI2P
[0:09:24.426256104] [3181]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 2592x1944-SGBRG10_1X10 - Selected unicam format: 2592x1944-pGAA
Still capture image received
然後 aaa.jpg 就是。

bookmark : wifi-direct on raspberry pi

2024/6/18

LLaVA : install and run

ref: 因為要上傳/顯示 img,所以不能用text-generation,這邊的demo 是用gradio
整個架構就像示意圖說明。有三個component:
  • web ui : 負責 web interface
  • controller : 負責把 llava 的query/response 轉成 api
  • worker : 就是 llava 本體
然後 worker 又有兩種選擇: 一個就是 llava 自己,一個是 SGlang worker 轉接。
SGLang 轉接的好處是 ?


前面 web ui, controller 都是 gradio,只有 worker 是 llava 服務本體。
所以依照說明,create conda env,clone LLaVA ....之後..
文件說明是用 pin install . 把 llava 跟 gradio 安裝進 evn.
-e 是為了之後可以 update

然後要 download model checkpoint : LLaVA MODEL ZOO 例如:
git clone https://huggingface.co/liuhaotian/llava-v1.6-mistral-7b
然後啟動 controller:
conda activate llava
cd LLaVA
python -m llava.serve.controller --host 0.0.0.0 --port 10000
開啟web ui
conda activate llava
cd LLaVA
python -m llava.serve.gradio_web_server --controller http://localhost:10000 --model-list-mode reload
最後啟動 llava worker,指定 download 的 model checkout folder:
conda activate llava
cd LLaVA
python -m llava.serve.model_worker --host 0.0.0.0 --controller http://localhost:10000 --port 40000 --worker http://localhost:40000 --model-path ../llava-v1.6-mistral-7b

2024/6/12

text-generation : missing module transformers_stream_generator

要 load Qwen-1_8B-Chat 時,出現 Error, 說缺了 transformers_stream_generator,
因為是用 start_linux.sh 啟動,所以要找到他的 conda env 來安裝。
在 start_linux.sh 中有。
所以是
$ source ./installer_files/conda/etc/profile.d/conda.sh
$ conda ./installer_files/env
$ pip install transformer_stream_generator
之後run start_linux.sh,load Qwen-1_8B-Chat 時就沒有 Error 了。

另外,因為這是中國的mode,所以用簡體回答,有時候會出現 Error:
text_generation.py, line 260, in get_reply_from_output_ids
  first_token = first_token.decode('utf8')
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: unexpected end of data
StackOverflow 說,decode 時,error handling 用 'ignore' 就可以。
所以去查 first_token 是 convert_ids_to_tokens( ) 的 return varlaibe. type 是 str。
所以去查 str.decode( ) 的宣告。
改成
  first_token.decode('utf8','ignore')
就可以了。

2024/5/10

memo : ssh-copy-id

mlinux 用ssh-copy-id,windows 的話,就把 .ssh/id_rsa.pub 裡面的資料加到 server 的 .ssh/authorized_keys 就可以。

C:\User\<user-name>\.ssh

2024/5/7

enable ims service

ims 是 4G 網路提供Voice Call 的服務 (VoLTE)。
所以要在連接4G 基地站時,做Voice 的撥/接,就要啟動 ims 服務。

這個是quectel 的命令.

MBN 好像是profile之類的 config 檔。
會針對不同營運商調整,而一般,最普通,未調整的就是 ROW_Generic_3GPP.
所以這個可以連所有營運商(?)

列出目前所有mbn檔
at+qmbncfg="list"
+QMBNCFG: "List",0,1,1,"ROW_Generic_3GPP",0x0501081F,201901141
+QMBNCFG: "List",1,0,0,"VoLTE-ATT",0x0501033C,201810121
+QMBNCFG: "List",2,0,0,"hVoLTE-Verizon",0x05010140,201811131
+QMBNCFG: "List",3,0,0,"Commercial-Sprint",0x05010205,201904021
每個 list 內容是:
  • index
  • selected
  • activate
  • name
  • version
  • release date
上面的example 代表select ROW_Generic_3GPP,而且也是active.

要select 用: AT+QMBNCFG="Select","ROW_Generic_3GPP"

要deactivate 用: AT+QMBNCFG="Deactivate" 就可以

QMBNCFG 用來確認有沒有activated profile.

然後是 ims 服務.
at+qcfg="ims"
+QCFG: "ims",0,0

OK
第一個數字是configuration:
  • 0: 由 MBN file 決定
  • 1: 啟動ims
  • 2: 不啟動ims
第二個數字代表VoLTE狀態
  • 0: VoLTE is disabled
  • 1: VoLTE is enabled
設定 ims 可以用:
at+qcfg="ims",0
ok
設定完後,要重新啟動:
at+cfun=1,1
OK
之後狀態才會生效。

AT+COPS 與基地站相關的操作

列出所有的基地站
at+cops=?
+COPS: 
(1,"Chunghwa Telecom","Chunghwa","46692",7),
(2,"Chunghwa Telecom","Chunghwa","46692",2),
(1,"TWN APT","APT","46612",7),
(3,"TWN APT","APT","46605",7),
(3,"TW Mobile","TWM","46697",2),
(3,"T Star","T Star","46689",7),
(3,"TW Mobile","TWM","46697",7),
(3,"T Star","T Star","46689",2),
(1,"Far EasTone","FET","46601",2),
(3,"TWN APT","APT","46605",2),
(1,"Far EasTone","FET","46601",7),
,(0-4),(0-2)
回答的每一行的每一個item是:
(stat,long alphanumeric,short alphanumeric,numeric,AcT)
stat:
  • 0: 未知
  • 1: 可用
  • 2: 目前使用中
  • 3: 禁用
long/short aplhanumeric 就是 operator的名稱,全名和縮寫。
Act 就是基地站的技術
  • 0 GSM
  • 1 GSM Compact
  • 2 UTRAN
  • 3 GSM w/EGPRS
  • 4 UTRAN w/HSDPA
  • 5 UTRAN w/HSUPA
  • 6 UTRAN w/HSDPA and HSUPA
  • 7 E-UTRAN
所以上面的list 可以看出...目前用的是 Chunghwa, UTRAN (就是3G)

設定自動選擇基地站 at+cops=0:
at+cops=0
ok

CTZE: "+32",0,"2024/05/07,02:26:11"

+CTZE: "+32",0,"2024/05/07,02:42:37"
設玩好像重新開機,然後問目前的基地站是:
AT+COPS?
+COPS: 0,2,"46692",7

OK

手動選擇基地站要用at+cops=1:
at+cops=1,2,"46692",2
OK

+CTZE: "+32",0,"2024/05/07,02:54:36"
好像也會重開機?
1 代表 手動,後面的 2 是 format 用 numberic, 所以後面用 "46692" 也就是 Chunghwa Telecom 的 numberic 代表號,最後是基地站的技術 7 - E-UTRAN也就是 LTE.

2024/5/2

VoLTE and IMS

ref: 以前Voice 跟 Data走的路不一樣。
Voice 是 switch - 就是像以前接線生依樣,把兩端用專用的線接起來。
Data 是 IP - 就是切割成一小塊一小塊,在網路中送到對手上。
所以當 Voice時,Data就停止了。因為要切到專用線路。

後來,Voice也想改用Data那樣,切成一小塊,在網路中傳。
所以在Data 的服務中就規劃了 IMS (IP Multimedia Subsystem),負責傳這些小塊的語音資料。

這個服務就叫VoLTE,需要經過 IMS 傳送資料。

在電信系統中,IMS了傳送語音封包,還負責以前語音的一些功能,例如DTMF,SMS。
IMS 提供的服務:
  • VoLTE over IMS
  • SMS over IMS
  • Emergency call over IMS
  • DTMF over IMS
  • SRVCC over IMS (負責舊的交換機系統溝通)

2024/4/30

Docker : container access host network

就是用 "--add-host="host.docker.internal:host-gateway",docker 會再container 的dns中加入 host.docker.internal 到 host ip
測試可以用:
docker container run --rm \
  --add-host="host.docker.internal:host-gateway" \
  debian:stable-slim \
  bash -c "apt-get update && apt-get install -y iputils-ping && ping -c 3 host.docker.internal"

2024/4/26

text-generation-webui error , character 'None'

有時候開啟chat 頁面會沒反應,一開始的 hello 訊息也沒出來。
console 的 error 是:
ERROR    Could not find the character "None" inside characters/. No character has been loaded.
  ...
  ...
File "/home/charles-chang/text-generation-webui/modules/chat.py", line 673, in load_character
    raise ValueError
查source 是在 parameter tab 的 chat tab 的Character option 中,沒有選任何一個(Assistant, Example),所以是None
選了之後就好了。


download model

大多需要 lfs,所以 apt install git-lfs 之後,就可以用了。
需要license 的好像還是只能手動。

msys2. SDL2 Hello

ref: 安裝需要的 package:
pacman -S git mingw-w64-x86_64-toolchain mingw64/mingw-w64-x86_64-SDL2 mingw64/mingw-w64-x86_64-SDL2_mixer mingw64/mingw-w64-x86_64-SDL2_image mingw64/mingw-w64-x86_64-SDL2_ttf mingw64/mingw-w64-x86_64-SDL2_net mingw64/mingw-w64-x86_64-cmake make
測試:
$ sdl2-config --cflags --libs
-IC:/msys64/ucrt64/include/SDL2 -Dmain=SDL_main
-LC:/msys64/ucrt64/lib -lmingw32 -mwindows -lSDL2main -lSDL2
用上面ref 的 example:
#include &;t;stdio.h>
#include <SDL2/SDL.h>

const int WIDTH = 800, HEIGHT = 600;

int main(int argc, char *argv[]) {
  SDL_Window *window;
  SDL_Renderer *renderer;
  if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
    printf("SDL_Init failed: %s\n", SDL_GetError());
    return 1;
  }

  window = SDL_CreateWindow("Hello, World!",
                                        SDL_WINDOWPOS_UNDEFINED,
                                        SDL_WINDOWPOS_UNDEFINED,
                                        WIDTH, HEIGHT,
                                        SDL_WINDOW_ALLOW_HIGHDPI);
  if(window == NULL) {
    printf("Could not create window: %s\n", SDL_GetError());
    return 1;
  }
  
  renderer = SDL_CreateRenderer(window, -1, 0);
  SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
  SDL_RenderClear(renderer);

  SDL_RenderPresent(renderer);
  
  SDL_Event event;
  while(1) {
    if(SDL_PollEvent(&event)) {
      if(event.type == SDL_QUIT) {
        break;
      }
    }
  }

  SDL_DestroyWindow(window);

  SDL_Quit();
  return 0;
}
build:
$ gcc -o testsdl testsdl.c `sdl2-config --cflags --libs`

msys2, pacmain -s 失敗: 簽章等級不明

Error:
來自 David Macek <david.macek.0@gmail.com> 的簽章信任等級不明
然後這一篇 有說明一個危險的方法,disable signature verification.
Disabling signature checking

Warning: Use with caution. Disabling package signing will allow pacman to install untrusted packages automatically.
If you are not concerned about package signing, you can disable PGP signature checking completely. 
Edit /etc/pacman.conf and uncomment the following line under [options]:

SigLevel = Never

You need to comment out any repository-specific SigLevel settings too because they override the global settings. 
This will result in no signature checking, which was the behavior before pacman 4. 
If you decide to do this, you do not need to set up a keyring with pacman-key. 
You can change this option later if you decide to enable package verification.

text-generation-webui run microsoft_Phi-3-mini-128k-instruct error : trust_remote_code=True

load 玩model出現錯誤,console 顯示
ValueError: Loading models/microsoft_Phi-3-mini-128k-instruct requires you to execute the configuration file in that repo on your local machine. 
Make sure you have read the code there to avoid malicious use, then set the option `trust_remote_code=True` to remove this error.
在model tab 有一個checkbox 剛好就是 trust_remote_code,上面的說明:
Set trust_remote_code=True while loading the tokenizer/model. To enable this option, start the web UI with the --trust-remote-code flag.
所以是在啟動的時候...
./start_linux.sh --listen --trust-remote-code
哪個checckout 就check 了,model load and run OK

2024/4/25

bin_decode support 的compress method:
typedef enum {
    LV_IMAGE_COMPRESS_NONE = 0,
    LV_IMAGE_COMPRESS_RLE,  /*LVGL custom RLE compression*/
    LV_IMAGE_COMPRESS_LZ4,
} lv_image_compress_t;
在 decompress_image( ) 中,參考這個欄位。
lv_bin_decoder_open( ),

2024/4/5

Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, you need to source
the corresponding env file under $HOME/.cargo.

This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env"            # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish"  # For fish

2024/3/26

lvgl label, font

找 font 的 code:
/home/charles-chang/lv_sim_vscode_sdl/lvgl/src/font/lv_font_fmt_txt.c

static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
好像是..
/home/charles-chang/lv_sim_vscode_sdl/lvgl/src/font/lv_font_fmt_txt.c

const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unicode_letter)
設定歸設定,之後的,可以在 draw_ 設定斷點,看到 call 的時機 (後來的 timer callback, update_layout(cb))

2024/3/25

android studio for platform

就是能 support AOSP source code 的 Android Studio。
好像是 Android Studio + plugin,有這個 plugin 後,在 Android Studio 的 Welcom Page,除了一般的New Project 和 Open 之外,
還會多一個 "Import Asfp Project"

選 Import Asfp Project 就是 Import Aosp 裡面的 project (code)
所以要設定 AOSP source code 位置。還有build 時,lunch 的 target 是 ? (例如 pixel4 就是 aosp_flame-userdebug)
後面才是挑選aosp 中,要 import 的 module (folder)

2024/3/12

wayland. weston hello-world

wayland 是新的 X protocol (?)。
wayland 也是一樣,一個 server 負責顯示,一堆 client 藉由 wayland protocol 要求 server 畫圖。
wayland server 的實做就是 weston。

weston 也可以 run 在 X上(變成 interpreter ?),所以在 ubuntu 上,使用 X 的系統,也可以 run wayland client.
開啟console 啟動 weston 就可以。
~$ weston
Date: 2024-03-12 CST
[15:11:15.003] weston 9.0.0
               https://wayland.freedesktop.org
               Bug reports to: https://gitlab.freedesktop.org/wayland/weston/issues/
               Build: 9.0.0
[15:11:15.003] Command line: weston
[15:11:15.003] OS: Linux, 6.5.0-25-generic, #25~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Feb 20 16:09:15 UTC 2, x86_64
[15:11:15.003] Starting with no config file.
[15:11:15.003] Output repaint window is 7 ms maximum.
[15:11:15.003] Loading module '/usr/lib/x86_64-linux-gnu/libweston-9/x11-backend.so'
[15:11:15.009] Loading module '/usr/lib/x86_64-linux-gnu/libweston-9/gl-renderer.so'
[15:11:15.019] EGL client extensions: EGL_EXT_platform_base EGL_EXT_device_base
               EGL_EXT_device_enumeration EGL_EXT_device_query
               EGL_KHR_client_get_all_proc_addresses EGL_EXT_client_extensions
               EGL_KHR_debug EGL_KHR_platform_x11 EGL_EXT_platform_x11
               EGL_EXT_platform_device EGL_KHR_platform_wayland
               EGL_EXT_platform_wayland EGL_EXT_platform_xcb
               EGL_MESA_platform_gbm EGL_KHR_platform_gbm
               EGL_MESA_platform_surfaceless
[15:11:15.026] EGL version: 1.5
[15:11:15.026] EGL vendor: NVIDIA
[15:11:15.026] EGL client APIs: OpenGL_ES OpenGL
...
然後看到一個小window 跑起來,裡面有小游標。

然後clone 這個 client example: hello-wayland make 就可以。
然後 run ./hello-wayland
就可以看到一個圖片show 在剛剛的 weston windows 上。



另外一個簡單測試 wayland server connection 的 client code:
#include <stdio.h>
#include <wayland-client.h>

int
main(int argc, char *argv[])
{
    struct wl_display *display = wl_display_connect(NULL);
    if (!display) {
        fprintf(stderr, "Failed to connect to Wayland display.\n");
        return 1;
    }
    fprintf(stderr, "Connection established!\n");

    wl_display_disconnect(display);
    return 0;
}
compile 的時候要 link wayland-client.so
gcc -o waylandclient waylandclient.c -lwayland-client
另外一個簡單的,紙提供 wayland sock connect 的 server (chatgpt 寫的):
#include <stdio.h>
#include <wayland-server.h>

int
main(int argc, char *argv[])
{
    struct wl_display *display = wl_display_create();
    if (!display) {
        fprintf(stderr, "Unable to create Wayland display.\n");
        return 1;
    }

    const char *socket = wl_display_add_socket_auto(display);
    if (!socket) {
        fprintf(stderr, "Unable to add socket to Wayland display.\n");
        return 1;
    }

    fprintf(stderr, "Running Wayland display on %s\n", socket);
    wl_display_run(display);

    wl_display_destroy(display);
    return 0;
}
一樣,compile 的時候要link wayland-server (-lwayland-server)

2024/3/4

build aosp android 12 for pixel4

repo version 顯示 repo launcher version 要是 2.15 以上。
"codenanme-tages-and-buildnumber" 去看,pixel4最後一個版本tag name 是 android-12.1.0_r11

所以
repo init -u https://android.googlesource.com/platform/manifest -b android-12.1.0_r11
repo sync -c -j8
官方說 "-c" 就可以只fetch current version (所以 repo init 不用加 --depth=1 ?)

download 玩aosp 後,要 download hardware 相關的 none-open binary.
要依照build id 來download,剛剛的android-12.1.0_r11 的 build id 是 SQ3A.220705.003.A1
有 google 跟 qualcomm 兩個 tgz 檔。

說明解開後是自解壓縮script,說在 aosp 的 root folder 執行,accept license後,就會放在正確位置 (vendor)。

開始build:
source build/envsetup.sh
接下來的lunch 要選pixel4,依照說明去 flash device 查,是 flame,所以:
lunch aosp_flame-userdebug
然後就可以用 "m" 來build,不用加任何option,他會看cpu核心數開啟對應process。
-- 用 i9 13 代,限制溫度70,64G ram, 普通hd, 需要90分鐘。



build kernel
現在AOSP 的kernel是 prebuilt kernel,所以要build 的話,要另外clone 下來。
kernel build法以 Android 12 為分界。
12 (含)以前,用build.sh
另外,pixel6以上,android 13(含)以上,支援 GKI (generalize kernel image),所以可以只update kernel vender part,所以只build 出 kernel 就可以。
古老的還是要build 好 kernel 後,到 aosp 再build 一次,把 kernel 包進去。

現在做 pixel4, android12 的作法:build.sh

用 repo clone source,先到kernel branch 去看android12 for pixel 4 的 branch name 是什嗎。
猜大概是 common-android12-5.10 吧?
repo init -u https://android.googlesource.com/kernel/manifest -b common-android12-5.10
repo sync -j8

燒錄

要先 unlock bootloader
pixel 4 要先到 Setting 中的 developement option 去開啟 allow unlock bootloader,
然後關機,按著volume down + power 開機進入bootloader mode.
用 fastboot flashing unlock 來unlock
其實在pixel 4 的 bootloader 畫面也有 unlock 選項,選後按下 power,他會自己 reboot,之後就是 unlock mode 了。

開始燒錄。
一樣在 bootloader mode,所以先進入 bootlaoder:
adb reboot bootloader
fastboot 要看環境變數 ANDROID_PRODUCT_OUT 來找 img 檔。
所以要先設定這個變數到剛剛 build 好的 aosp src /out/target/product/flame
之後就可以下
$ fastboot flashall -w
--------------------------------------------
Bootloader Version...: c2f2-0.4-7617419
Baseband Version.....: g8150-00111-210817-B-7650554
Serial Number........: 99211FFAXXXXXX
--------------------------------------------
Checking 'product'                                 OKAY [  0.070s]
Setting current slot to 'b'                        OKAY [  0.157s]
Sending 'boot_b' (65536 KB)                        OKAY [  1.850s]
Writing 'boot_b'                                   OKAY [  0.299s]
Sending 'dtbo_b' (8192 KB)                         OKAY [  0.340s]
Writing 'dtbo_b'                                   OKAY [  0.094s]
Sending 'vbmeta_b' (4 KB)                          OKAY [  0.140s]
Writing 'vbmeta_b'                                 OKAY [  0.078s]
Sending 'vbmeta_system_b' (4 KB)                   OKAY [  0.140s]
Writing 'vbmeta_system_b'                          OKAY [  0.078s]
Rebooting into fastboot                            OKAY [  0.070s]
< waiting for any device >
Sending 'super' (4 KB)                             OKAY [  0.018s]
Updating super partition                           OKAY [  0.025s]
Resizing 'product_b'                               OKAY [  0.003s]
Resizing 'system_b'                                OKAY [  0.003s]
Resizing 'system_ext_b'                            OKAY [  0.003s]
Resizing 'system_a'                                OKAY [  0.005s]
Resizing 'vendor_b'                                OKAY [  0.005s]
Resizing 'vendor_a'                                OKAY [  0.003s]
Resizing 'product_b'                               OKAY [  0.003s]
Sending sparse 'product_b' 1/2 (262140 KB)         OKAY [  6.835s]
Writing 'product_b'                                OKAY [  1.816s]
Sending sparse 'product_b' 2/2 (10064 KB)          OKAY [  0.274s]
Writing 'product_b'                                OKAY [  0.089s]
Resizing 'system_b'                                OKAY [  0.004s]
Sending sparse 'system_b' 1/4 (262140 KB)          OKAY [  7.071s]
Writing 'system_b'                                 OKAY [  1.884s]
Sending sparse 'system_b' 2/4 (262140 KB)          OKAY [  7.484s]
Writing 'system_b'                                 OKAY [  0.896s]
Sending sparse 'system_b' 3/4 (262140 KB)          OKAY [  6.993s]
Writing 'system_b'                                 OKAY [  0.873s]
Sending sparse 'system_b' 4/4 (34396 KB)           OKAY [  0.924s]
Writing 'system_b'                                 OKAY [  0.176s]
Resizing 'system_ext_b'                            OKAY [  0.004s]
Sending 'system_ext_b' (136184 KB)                 OKAY [  3.665s]
Writing 'system_ext_b'                             OKAY [  1.531s]
Resizing 'system_a'                                OKAY [  0.003s]
Sending 'system_a' (23492 KB)                      OKAY [  0.728s]
Writing 'system_a'                                 OKAY [  0.151s]
Resizing 'vendor_b'                                OKAY [  0.004s]
Sending sparse 'vendor_b' 1/4 (262140 KB)          OKAY [  7.022s]
Writing 'vendor_b'                                 OKAY [  1.893s]
Sending sparse 'vendor_b' 2/4 (262140 KB)          OKAY [  6.996s]
Writing 'vendor_b'                                 OKAY [  0.898s]
Sending sparse 'vendor_b' 3/4 (262140 KB)          OKAY [  7.075s]
Writing 'vendor_b'                                 OKAY [  0.902s]
Sending sparse 'vendor_b' 4/4 (42360 KB)           OKAY [  1.120s]
Writing 'vendor_b'                                 OKAY [  0.212s]
Erasing 'userdata'                                 OKAY [ 12.301s]
Erase successful, but not automatically formatting.
File system type raw not supported.
Erasing 'metadata'                                 OKAY [  0.008s]
Erase successful, but not automatically formatting.
File system type raw not supported.
Rebooting                                          OKAY [  0.000s]
Finished. Total time: 105.627s
可以看到燒錄過程中,燒完 dtb 和 system 後會自己 reboot,不要動他。
reboot 完會自己繼續download,最後 reboot,進入android.


memo 一下 pixel4 的最後版本 android-13.0.0_r31
一樣,下載 propriety binary 後 build OK, 但是燒錄後無法開機,停在 google logo 畫面。

另外,build 好的 aosp folder copy 到另一台機器上 會 build fail。
因為 out/host/linux-x86/b8in 下,有一些 python script 是絕對路徑的 link。



結果要燒回 factory ota image 時,用 adb sideload 出現 signiture verified error。
最後用 android flash tool 網頁版,才燒錄成功。

2024/2/26

msys2 pacman -S failed, key not verified

原來用得好好的,某一次後要安裝 package 就 fail,而且一直發生 db lock,
猜想可能是做過 upgrade : pacman -Syuu 的關係。
所以去找 release 的各個版本來試。
發現在 20231026 之後(包含),用 -S 安裝package 就發生 key 的問題了。
所以所有的版本要是做過 -Syuu 更新到最新版本,當然就會出問題。
-- 是過最新 daily build 版本也依樣。

所以只能拿 20230718 的版本來用,並且記得絕對不能 升級。

2024/2/22

repo: no module named 'formatter'

ref: 因為repo 使用的 python 在 python 3.10 之後,已經把 formatter 這個 module 移除了。
所以 google 建議修改成:
diff --git a/subcmds/help.py b/subcmds/help.py
index 1e16019..9c4756b 100644
--- a/subcmds/help.py
+++ b/subcmds/help.py
@@ -17,7 +17,7 @@
 from __future__ import print_function
 import re
 import sys
-from formatter import AbstractFormatter, DumbWriter
+import textwrap

 from subcmds import all_commands
 from color import Coloring
@@ -88,7 +88,7 @@ Displays detailed usage information about a command.
         Coloring.__init__(self, gc, 'help')
         self.heading = self.printer('heading', attr='bold')

-        self.wrap = AbstractFormatter(DumbWriter())
+        self._first = True

       def _PrintSection(self, heading, bodyAttr):
         try:
@@ -123,9 +123,12 @@ Displays detailed usage information about a command.
             self.nl()
             continue

-          self.wrap.add_flowing_data(para)
-          self.wrap.end_paragraph(1)
-        self.wrap.end_paragraph(0)
+        lines = textwrap.warp(para.replace(' ',' '), width=80, break_long_word=False, break_on_hyphens=False)
+
+        for line in lines:
+            self.write('%s',line)
+            self.nl()
+        self.nl()

     out = _Out(self.manifest.globalConfig)
     out._PrintSection('Summary', 'helpSummary')



其實可以去 .repo/repo 下面,加入 git-repo 做remote source,然後 checkout 一個新版也可以
git remote add gitrepo https://github.com/GerritCodeReview/git-repo
git fetch gitrepo
git checkout v2.29
.. 因為這個 repo mirror 最小的 tag 好像只有 v2.29,沒有更早的。

2024/2/21

Windows Terminal

ref: Windows 提供一個新的 terminal 程式,或者說是 front-end,背後可以是 PowerShell, Cmd, 或是自己install 的 msys。
以 msys2 的 shell 為例,自己增加一個 profile。

選 Setting,最下面的 "開啟 json 檔"
json 檔中的 "profiles" 就是一堆 shell 的command.

2024/2/16

Android Platform API, packages in api level

有關 Android 各版本提供的 api,可以查詢: 網頁左邊的panel,有一個 API level 的下拉選單,可以選 Api level
依照你選的 level 變更,不支援的 package 會變成灰色。
另外在每一個 package 的說明頁都會有 "Added in API level " 的標示。

api level 對應 Android OS version,android 10 之後:
Platform Version    API level
     14             34
     13             33
     12             32
                    31
     11             30
     10             29

另外,這個: Android OS core topics,左邊panel 的每個 item 都有列出每個feature 在 哪個 Android 版本開始實作。
太多了,每個都有細項可以看。


大概列一下每個版本新增的package api.

Android 14(level 34):
  • adservice : 不清楚,好想是open advertising id 供 ap 使用
  • documentid :
  • sdk sandbox : application sandbox 的 user api


有關 application 的 security, isolation,goole 有一篇說明從 android 5 到 android 10 的改進 -- app-sandbox:
  • In Android 5.0, SELinux provided mandatory access control (MAC) separation between the system and apps. However, all third-party apps ran within the same SELinux context so inter-app isolation was primarily enforced by UID DAC.
  • In Android 6.0, the SELinux sandbox was extended to isolate apps across the per-physical-user boundary. In addition, Android also set safer defaults for application data: For apps with targetSdkVersion >= 24, default DAC permissions on an app's home dir changed from 751 to 700. This provided safer default for private app data (although apps may override these defaults).
  • In Android 8.0, all apps were set to run with a seccomp-bpf filter that limited the syscalls that apps were allowed to use, thus strengthening the app/kernel boundary.
  • In Android 9 all non-privileged apps with targetSdkVersion >= 28 must run in individual SELinux sandboxes, providing MAC on a per-app basis. This protection improves app separation, prevents overriding safe defaults, and (most significantly) prevents apps from making their data world accessible.
  • In Android 10 apps have a limited raw view of the filesystem, with no direct access to paths like /sdcard/DCIM. However, apps retain full raw access to their package-specific paths, as returned by any applicable methods, such as Context.getExternalFilesDir().

其他的新功能還有 apk cached (freezer): cached-apps-freezer,加速 app 啟動時間。

大的功能是硬體的檢查: Android Health,一樣在每個android 版本有不同的實作。
一開始的brief:

Android 9 includes android.hardware.health HAL 2.0, a major version upgrade from health@1.0 HAL. This new HAL has the following advantages:
  • Cleaner separation between framework and vendor code.
  • Deprecates the unnecessary healthd daemon.
  • Greater degrees of freedom for vendor customization in health information reports.
  • More device health information than just battery.
Android 11 includes android.hardware.health HAL 2.1, a minor version upgrade from health@2.0 HAL. This new HAL has the following advantages:
  • Easier to implement
  • Better conformance with existing 2.0 HAL APIs
  • Better Treble separation in off-mode charging code
  • Better support for the framework to indicate the battery health of the device
Android 13 includes android.hardware.health AIDL HAL, a conversion from health@2.1 HAL. This new HAL has the following advantages:
  • Remove unused charger-related APIs
  • Remove unused StorageAttribute and related fields
  • Support dock charging.


Android 12 後:
新增 App Hibernation 功能。一段時間沒用的 app,會自動 release 他用的 memory 和 cache,把她放回 storage。
新增一個 memory monitor 的機制: MM Event -Historical Memory Statics

Android 14 新增一個 Power Mode : GAME.

test build android 14 for raspberry pi 4

因為要試試看 Android 12, 13, 14 的差異,所以用 raspberry pi 來測試。
順便紀錄一下很久沒做android (上次到 android 9) 之後,覺得是新的東西。
先照: 果然 prequreirement package 有新的:
sudo apt-get install bc coreutils dosfstools e2fsprogs fdisk kpartx mtools ninja-build pkg-config python3-pip
sudo pip3 install meson mako jinja2 ply pyyaml dataclasses
以 ubunutu 22.04,已經 build 過 android12 的系統。
結果缺 mtools (mcopy command). 和 pip install 的 meson, mako, ply.
結果用 pip3 install 還是 build fail,最後是用 apt (deb) 的 package 才 build OK

bionic/apex

結果是一種file format.從Android 10 就有了。
這種file 是用來更新用(?)
以往的 apk 都是用在 application 更新,所以都是由 package manager 負責。
但是如果是系統 component (例如native service),不是由 vm run 的程式,就沒版辦法了。
這個 apex 系統就是為了這個目的。
apex 檔案裡面主要是一個 ext4 的 img file,裡面包含需要的 program. so 和一些config file。
android 另外新增一個 apexd 服務,boot 時會檢查 /apex/ 目錄下有沒有 *.apex 檔案。
有的話就 把img loop mount,然後叫起裡面的服務。

另外,他也支援更新。因為 /apex 目錄是 ro,所以安裝都放在其他位置(/data ?)。
apexd 會去見查 /data 下有沒有 /apex/ 內檔案的對應新版本,有就用,沒有就用 /apex/ 下的。

結果在 android 14 上,幾乎所有東西都 apex 化了。
framework 裡的 service,甚至一些 apk 也都包裝成 apex.
out 目錄中,有一個 apex 目錄。裡面很多 componments folder.


raspberry-vanilla 開機失敗。
試試看: android-rpi

update: 開機成功。
失敗是因為使用 pi4, 2GB 版本,logcat 一直出現 oom, 最後 watchdog 出現 wait too long,然後 goodbye 重新啟動 dalvik ? activitymanager.
改用 4GB 版本直接開啟 OK


lunch aosp_rpi4_tv 的話,build fail:
ERROR: files are incompatible: android.hardware.camera.provider@2.5::ICameraProvider/legacy/0 is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.gatekeeper@1.0::IGatekeeper/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.allocator@4.0::IAllocator/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.composer@2.4::IComposer/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.keymaster@4.1::IKeymasterDevice/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.tv.cec@1.0::IHdmiCec/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.usb.gadget@1.2::IUsbGadget/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.camera.provider@2.5::ICameraProvider/legacy/0 is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.gatekeeper@1.0::IGatekeeper/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.allocator@4.0::IAllocator/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.composer@2.4::IComposer/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.keymaster@4.1::IKeymasterDevice/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.tv.cec@1.0::IHdmiCec/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.usb.gadget@1.2::IUsbGadget/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.camera.provider@2.5::ICameraProvider/legacy/0 is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.gatekeeper@1.0::IGatekeeper/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.composer@2.4::IComposer/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.keymaster@4.1::IKeymasterDevice/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.tv.cec@1.0::IHdmiCec/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.usb.gadget@1.2::IUsbGadget/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.camera.provider@2.5::ICameraProvider/legacy/0 is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.gatekeeper@1.0::IGatekeeper/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.allocator@4.0::IAllocator/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.graphics.composer@2.4::IComposer/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.keymaster@4.1::IKeymasterDevice/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.tv.cec@1.0::IHdmiCec/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
android.hardware.usb.gadget@1.2::IUsbGadget/default is deprecated in compatibility matrix at FCM Version 8; it should not be served.
The following instances are in the device manifest but not specified in framework compatibility matrix:
    android.hardware.camera.provider@2.5::ICameraProvider/legacy/0
    android.hardware.gatekeeper@1.0::IGatekeeper/default
    android.hardware.graphics.allocator@4.0::IAllocator/default
    android.hardware.graphics.composer@2.4::IComposer/default
    android.hardware.keymaster@4.1::IKeymasterDevice/default
    android.hardware.tv.cec@1.0::IHdmiCec/default
    android.hardware.usb.gadget@1.2::IUsbGadget/default
    android.hardware.wifi.supplicant.ISupplicant/default (@1)
Suggested fix:
1. Update deprecated HALs to the latest version.
2. Check for any typos in device manifest or framework compatibility matrices with FCM version >= 8.
3. For new platform HALs, add them to any framework compatibility matrix with FCM version >= 8 where applicable.
4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE.: Success
INCOMPATIBLE
16:15:08 ninja failed with: exit status 1                                                                                                                                                 
#### failed to build some targets (43:52 (mm:ss)) ####   
update: 錯了,上面的error 是因為用 "m" 來build 導致的。
如果 follow 原 po 的說明,用
make bootimage systemimage vendorimage -j$(nproc)
就沒有 build fail 了。


android14 的話,還需要 texlive-full ,領外 meson 也要 0.6以上,所以 ubuntu 20.04 的話,apt 的 meson 版本不夠 (0.52),要用 pip 的版本才夠。
另外,要用 python3,所以乾脆整個系統都用 python3 了: python-is-python3

2024/2/7

LVGL set font and filesystem

ref: 會遭遇兩個問題:
  • 如何讀入字型檔
  • 如何設定字型
讀入就跟 filesystem 有關。
filesystem 就跟 platform 有關,是用 windows, linux 還是 mcu,filesystem 的 api 不一樣。
lvgl 用 lv_conf.h 來設定用哪個 api:
/*File system interfaces for common APIs */

/*API for fopen, fread, etc*/
#define LV_USE_FS_STDIO 1
#if LV_USE_FS_STDIO
    #define LV_FS_STDIO_LETTER 'A'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
    #define LV_FS_STDIO_PATH ""         /*Set the working directory. File/directory paths will be appended to it.*/
    #define LV_FS_STDIO_CACHE_SIZE 0    /*>0 to cache this number of bytes in lv_fs_read()*/
#endif

/*API for open, read, etc*/
#define LV_USE_FS_POSIX 0
#if LV_USE_FS_POSIX
    #define LV_FS_POSIX_LETTER 'A'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
    #define LV_FS_POSIX_PATH ""         /*Set the working directory. File/directory paths will be appended to it.*/
    #define LV_FS_POSIX_CACHE_SIZE 0    /*>0 to cache this number of bytes in lv_fs_read()*/
#endif

/*API for CreateFile, ReadFile, etc*/
#define LV_USE_FS_WIN32 0
#if LV_USE_FS_WIN32
    #define LV_FS_WIN32_LETTER '\0'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
    #define LV_FS_WIN32_PATH ""         /*Set the working directory. File/directory paths will be appended to it.*/
    #define LV_FS_WIN32_CACHE_SIZE 0    /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
那個 LETTER 不是代表 windows 的 A 槽,B槽。而是用來代表 device.
像我用 ubuntu,試過用 "A:~/font.bin" 不行,一定要寫full path: "A:\home\charles\font.bin",然後用的是 FS_STDIO (會用 fopen())

load font 之後放進style,再把 style 設定到 object。
設定 font 跟 style 的 code:
     lv_font_t *myfont = lv_font_load("A:/home/charles/font.bin");
     static lv_style_t style;
     lv_style_init(&style);
     lv_style_set_text_font(&style,myfont);
要注意 stype 要是 static,因為之後系統會 periodically render 畫面,那時候會 access style 變數。如果是 local 變數,已經 free 調的話,就會出現 segment fault

下面用 example 的 label 為例子,設定 style:
    lv_obj_t * label1 = lv_label_create(lv_scr_act());
    lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP);     /*Break the long lines*/
    lv_label_set_recolor(label1, true);                      /*Enable re-coloring by commands in the text*/
    lv_label_set_text(label1, "TEST MY FONT");
    lv_obj_set_width(label1, 150);  /*Set smaller width to make the lines wrap*/
    lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40);
    
    lv_obj_add_style(label1,&style,0);

2024/1/31

HUB8735 - Ameba Pro2 - AMB82 MINI

不曉得是不是一樣的東西。

不過說除了用 Arduino IDE 之外,也可以用 Standard SDK.
然後就是說參考: 就 follow Project README: clone , untar tools, export PATH.
然後就可以開始 build example 了。
因為 build 最後的 tool 有分 linux 版的 *.linux 和 windows 版的 *.exe。
這個 repo 的 linux file attibute 沒有設定對,build 的時候會出現 Error。
所以先去把所有的 *.linux 加上 execution.
開始 build..
cd ambpro2_sdk/project/realtek_amebapro2_v0_example/GCC-RELEASE/build/
cmake .. -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DVIDEO_EXAMPLE=ON
cmake --build . --target flash_nn -j4
build 完,會是剛剛 --target 寫的 flash_nn.bin

燒錄是 tools/Pro2_PG_tool,把 zip 解開。把剛剛build 好的 flash_nn.bin copy 過來。
和用 Arduino IDE 一樣, HUB 8735 進入 download mode:
  • 短路 A5, 3V3 pin
  • 按一下 reset buuton
dmesg 看一下是 ttyUSB?

README 的說明 -b 2000000,會出現 ucf fail,看 ./uartfwburn.linux --help, -b 是 baudrate 的意思。
所以改成 9612000 後成功:
~/ambpro2_sdk/tools/Pro2_PG_tool _v1.3.0$ ./uartfwburn.linux -p /dev/ttyUSB0 -f flash_ntz.nn.bin -b 921600 -U
/dev/ttyUSB0 opened
ping ok
ucfg ok
Uart boot 
programing	[========================================] 100%        77824/       77824 bytes
programing done.
uboot ok
reset device
/dev/ttyUSB0 opened
ping ok
ucfg ok
download to offset 0x0
masked area [0x0, 0x0]
dowload 0, [0x0, 0xd9e000]
fw_len = 0xd9e000
programing	[========================================] 100%     14286848/    14286848 bytes
programing done.
done for download 0
download success
然後把 A5. 3V3 短路 pin 解開。reset
用 uart 115200 看到開機 log:
== Rtl8735b IoT Platform ==

[Normal mode]
BootFromNORFlash
[Start Boot ROM...]
=== Load PARTBL ===
=== Load Done ===
=== Load ISP_IQ ===
[fcs chk pass]
ISP_IQ @ 0x8401080, 0x2cf80, 0x0
mfcs_data version 0x00010001
fcs_data version 0x00010101
=== Process ISP_IQ ===
=== Load Done ===
=== Load BL ===
[Image Start Table @ 0x18200]
=== Load Done ===

== Boot Loader ==
Jul 12 2023:11:11:05
=== Load FCS Para ===
=== Load Done ===
[crc pass]
=== Load ISP_IQ Sensor ===
ISP_IQ @ 0x8401080, 0x2cf80
=== Process ISP_IQ ===
=== Load Done ===
=== Load FW1 ===
FW_ISP_IQ @ 0x8081080, 0x2ef80
=== Process FW_ISP_IQ ===
DRAM_TYPE is DDR2 128MB.
ddr_freq = 533
VOE flash @ 0x80b0080, 0x7ef80
FCS KM_status 0x00002081 err 0x0000200a
Wait KM fcs done 0 us
FCS TM_status 0x003f0000 
store fcs data for application 
RAM TM_STATUS 0x00bf0000 status 0x00000080
RAM TM_STATUS 0x00bf1208 err 0x00001208
read fcs_status 0x000000bf
                                                                                                                                               read fcs_status 0x000000bf
== Process VOE IMG ===
[Image Start Table @ 0x20106200]
RAM Load @ 0x812f100->0x20106200, 0x6a58
DDR Load @ 0x8136080->0x70100000, 0x19f574
=== FW Load Done ===

Boot Loader <==

== RAM Start ==
Build @ 15:20:47, Sep 13 2023

$8735b>interface 0 is initialized
interface 1 is initialized
cfg_size_lib = 29, cfg_size_user = 29

Initializing WIFI ...[Driver]: [HALMAC]
 11692M HALMAC_MAJOR_VER = 1
 HALMAC_PROTOTYPE_VER = 4
 HALMAC_MINOR_VER = 20
 HALMAC_PATCH_VER = 
[Driver]: The driver include MP
[Driver]: Ver = libwlan:2023.07.21.14.18_b9.5_a20c848742482c5f0ee2b39dd14c0c200435e46b
- download_firmware_88xx HALMAC_RET_SUCCESS
RFE type = 0
start_addr=(0x4000), end_addr=(0x8000), buffer_size=(0x4000), smp_number_max=(2048)

WIFI initialized
[FAST_CONNECT] Fast connect profile is empty, abort fast connection

init_thread(49), Available heap 0x6b847e0

use ATW0, ATW1, ATWC to make wifi connection
wait for wifi connection...

#
最後的 # 是按下 Enter 後出現的 prompt,因為 README 說要下命令 config wifi..
ATW0=<WiFi_SSID> : Set the WiFi AP to be connected
ATW1=<WiFi_Password> : Set the WiFi AP password
ATWC : Initiate the connection
下完之後,開始 scan , connect...
Interface 0 IP address : 172.24.1.117

init_thread(49), Available heap 0x6b82200
[video_voe_presetting] fps:30  w:1920  h:1080   

 voe heap size = 13455104
fwin(1),enc_en(0),IQ_OFFSET = 0x16520
 fwin(1),enc_en(0),SENSOR_OFFSET = 0x2e560
sensor id 1 iq_data 16520 sensor_data 2e560
hal_voe_ready 0x0 0xbf1208 
 read fcs_status 0x000000bf
[video_init] uvcd iq is null, use default.
[video_init] uvcd SNR is null, use default.
IQ:FW size (98342)
sensor:date 2023/7/18 version:RTL8735B_VOE_1.4.4.0
sensor:FW size (1812)
sensor timestamp: 2023/07/18
iq timestamp: 2023/05/15 14:48:54
ISP:1 ENC:1 H265:1 NN:1
hal_voe_ready 0x0 0xbf1208 
voe   :RTL8735B_VOE_1.4.4.0 
sensor:RTL8735B_VOE_1.4.4.0 
hal   :RTL8735B_VOE_1.4.4.0 
load time sensor:52us iq:2722us itcm:0us dtcm:0us ddr:0us ddr2:0us

RTSP[0] port: 554
fwin(1),enc_en(0),IQ_OFFSET = 0x16520
connect successful sta mode

 fwin(1),enc_en(0),SENSOR_OFFSET = 0x2e560
sensor id 1 iq_data 16520 sensor_data 2e560
hal_voe_ready 0x0 0x1718 
npu[7045d6e0] gck vip_drv_init, video memory heap base: 0x77000000, size: 0x01000000
NN IRQ default priority : 0, set to 9
npu[7045d6e0] HASHMAP 0x0x703fa994(process ID) INIT SUCCESS
npu[7045d6e0] HASHMAP 0x0x703fb6a0(memory wrap) INIT SUCCESS
npu[7045d6e0] HASHMAP 0x0x703fc2ec(network information) INIT SUCCESS
npu[7045d6e0] HASHMAP 0x0x703fcf10(segment information) INIT SUCCESS
VIPLite Drv version 10c00
set yolo confidence thresh to 0.500000
set yolo NMS thresh to 0.300000
Deploy YOLOv4t
...
開啟 vlc 連到 rtsp://172.24.1.117:554,就可以看到 yolov4 objection detection 的輸出。

2024/1/20

HUB 8735

ref: 下載 IDE (linux 用 zip。解開)

安裝 HUB 8735 的 board support package (?):
在 IDE 的 perference -- Settings -- Additional board manager URL 中,填入:
https://github.com/ideashatch/HUB-8735/raw/main/amebapro2_arduino/Arduino_package/ideasHatch.json
然後到 Tools -- Board -- Board Manager ,找 HUB 8735,會出現 ideaHatch Ameba Board,選一版 install (4.0.8-R).

完成後,Tools -- Board 的內容就會多一個 ideaHatch Ameba Boad 可以選。
選 HUB-8735


File -- Example -- AmebaMultimedia -- StreamRTSP -- VideoOnly
開啟 example : streaming server

修改 source code 中的 ssid[],pass[]到家裡的 wifi,
Sketch -- Verify/Compile
開始 make,
出現 Error:
misc/elf2bin.linux: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./misc/elf2bin.linux)
看一下自己系統的 libc 版本:
strings /lib/x86_64-linux-gnu/libc.so.6  | grep GLIBC
..
只有列到 GLIBC_2.30
所以是 ubuntu 版本不夠新(20.04)
ref: Error /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found
sources.list 加入
deb http://security.ubuntu.com/ubuntu jammy-security main 
然後 apt update, apt install lib
結果 lib 是很重要的 libary,所以一堆 service 要重開。

之後IDE重 Verify/Compile就 OK 了。

--- 這樣好像會 break distribution,update,upgrade之後,一堆function failed,

硬體接線。

hub 8735 使用 usb-uart 的 5V 就可以驅動了。
所以就順便用 usb-uart 的 5V, GND, TX, RD 接到 板子上。
usb-uart 插入nb,出現 ttyUSB0,
IDE 選 board, port : HUB 8735, ttyUSB0

讓 hub 8735 進入 download mode:

跟接 usb-uart 的四根 pin 的最旁邊的兩 pin : 3.3V, A5 ,短路後,按下正面的 led 旁邊的 button,就會 reboot into download mode.
在 IDE -- script -- upload,開始 build and upload.
IDE log 會出現:
Sketch uses 5054464 bytes (30%) of program storage space. Maximum is 16777216 bytes.
  Enter Flash Mode!
  Start Upload Flash
    Uploading...................upload success
  End Upload Flash
upload 完成,把剛剛的 A5, 3.3V 斷開。
開啟 uart terminal (picocom , 115200),按下正面 reset .. 可以看到開機 log..
    - RTSP -
rtsp://192.168.213.200:
[INFO] 554
開啟 VLC --- Media -- Open Network Stream
填入 rtsp://192.168.213.200:554
play 就可以看到畫面,開啟 VLC 的 codec information :
resolution : 1920x 1080, 30fps



另一種,不用 arduino,用一般mcu programming, gcc build 的方法是 sdk.
這個是 run yolov4 的 example:
20240130 update:

在 linux 的 arduino 安裝hub8735 的 board package 時,版本更新到 4.0.9 了,結果出現 Error,說 ameba_pro2_tools_linux-1.2.13 的 file size 錯,
去 release download gz 後看,果然 json 寫錯了。
後來發現 sha256sum 也錯,只好 fork 自己改,所以那個 json url 要改:
https://raw.githubusercontent.com/checko/HUB-8735/main/amebapro2_arduino/Arduino_package/ideasHatch.json
這樣安裝就 OK 了,所以也做了 pull request,之後應該就會改了吧。
-- size 和 checksum 都錯,有可能是 gz 放錯了,所以還是要等主站確定,ˋ這個只是暫時的方法。


Reatek AMB82 Mini

這個跟 HUB8735 很像,都是用 realtek RTL8735B,但是 GPIO pin 腳好像不一樣。
realtek 也有給他一個 arduino 的 sdk: 用法依樣,把 json 檔的 raw path 寫到 preference...

2024/1/19

Arduino Uno R3

Uno R3 有兩顆 MCU:
  • ATMEGA328P : 主 MCU
  • ATMEGA16U2 : 做 usb - uart 轉換

然後 有 R3 SMD 版,差異是 ATMEGA238P 這一棵由 DIP 改 SMD

另外有一種 CH340 版,就是用 CH340 這棵 usb-uart IC 換掉 ATMEGA16U2,可能有比較便宜吧,還有 CH340 的 baudrate 好像可以比較高。
相容性的話,因尾 Arduino IDE 只把 ATMEGA16U2 視為 usb-uart。並沒有 program 他,所以用起來應該一樣。

實際上也有project 把 ATMEGA16U2 改成 HID : keyboard,但是燒錄就要用 另一塊 arduno,hardware socket 和 dfu program.
如果沒有要動到 ATMEGA16U2,那麼選 便宜的 CH340 版本也行。

2024/1/8

gitlab 16.7 docker run

在名叫 i9rtx3090 的機器上啟動 gitlab-ce (現在的latest 應該是 16.7)
docker run -d --hostname i9rtx3090 --name gitlab -p 8080:80 gitlab/gitlab-ce
因為 gitlab 啟動很慢,所以看一下docker log:
docker logs gitlab
[execute] Running db:schema:load rake task 的時候會久一點。

16.7 版在 create issue 後,browse issue 會出現 hostname 沒有加上 port 的狀況。
如果Docker container 用 80,也就是 -p 80:80 的話就 OK
-- 另外,在 12.10 版沒有這個問題。

16.7 版docker 啟動後,root password 在 /etc/gitlab/initial_root_password 裡面。
所以用
docker exec -it gitlab /bin/bash
進去container 裡面看。
就可以用這個 password 登入 root 了。