2023年9月22日 星期五

[C++ ]Poco資料寫入資料庫SQLite解析

  Poco::Data::SQLite::Connector::registerConnector();

    // 建立会话

    Session session("SQLite", "sample.db");

    // 如果有名為abc的表存在,删除

    session << "DROP TABLE IF EXISTS abc", now;

    // 創建Table

    session << "CREATE TABLE abc (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;

     Statement insert(session);

  //塞一筆資料 #略#

for(int i=0; i<=65535; i++)

{

    insert << "INSERT INTO abc VALUES(?, ?, ?)",use(abc.name),use(abc.address),use(abc.age);

   //在這裡每插入一筆資料 必須使用insert.exexute(); 並執行execute方法

    insert.execute();

}
當使用for loop 時 insert必須都在括弧內宣告及處理,execute使用for loop會造成效能低下

65536筆跑完必須耗時10分鐘

有關于SQLite批量寫入資料耗時的問題有很多帖子可以找

我找到這篇Reference : https://blog.darkthread.net/blog/sqlite-insert-slow/


在UnitTest時 為了達到65536筆資料來滿足line coverage必須花不少時間,因此需要介紹以下的批量寫入

在訪問了Bing大神後(Bing也有推薦此篇文章 : Poco插入大量数据到数据库的优化 | xilixili.net),有找到一種寫法 說是批量寫入需要靠"事務"進行優化

其範例程式碼如下 : 

Poco::Data::Session sess("SQLite", "test.db");
sess << "create table if not exists test ("
        " [col_a] NVARCHAR (256) NOT NULL,"
        " [col_b] NVARCHAR (256) NOT NULL)",
    Poco::Data::Keywords::now;
 
sess.begin();  <=============================重點在這兩筆
for (size_t i = 0; i < 65535; i++) {
    char bufa[64] = {0};
    char bufb[64] = {0};
    sprintf(bufa, "test col a %d %d", i, rand());
    sprintf(bufb, "test col b %d %d", i * 2, rand());
    sess << "insert into test (col_a,col_b) values (?,?)",
        Poco::Data::Keywords::use(bufa),
        Poco::Data::Keywords::use(bufb),
        Poco::Data::Keywords::now;
}
sess.commit();  <=============================重點在這兩筆

中間筆數內的詳細資訊可以略過,因個人專案不同而已 當使用for loop進行插入前後必須宣告

sess.begin(); 以及 sess.commit(); 便可快速且大量塞入資料至Poco資料庫SQLite中


2023年8月31日 星期四

[C++]C++筆記

推薦閱讀書單&網路資源

1.C++ Primer 5th

2.C++ Standard Library headers

3.語言技術:C++ Gossip

字串

reference : https://shengyu7697.github.io/std-string-substr/

using std::string;

std::string::substr  取出子字串

範例 : substr(從第幾個字節之後開始,的多少個字截截取)

std::string abc_str = "hello"

abc_str.substr(1); //扣掉第一個印出後面的 ello

abc_str.substr(1,2); //扣掉第一個印出後面兩個 el 

string m("ssx"); == string m = "ssx";

 

>> //input

<< //Output message

endl = println = \n


abcManager::abcManager(Poco::Logger &L):_logger(L)

初始化


資料型別

using namespace std; //引入標準類別庫   可使用string  => std::string aa = "";

using namespace xxx::yyy

也可寫成

using xxx:yyy

nullptr : 指標字面值

指標宣告

1.shared_ptr宣告方法 

reference :https://cplusplus.com/reference/memory/shared_ptr/operator%20bool/

h檔全宣告方式std::shared_ptr<CppObjName> abc = std::shared_ptr<CppObjName>();

h檔半宣告方式std::shared_ptr<CppObjName> abc;

cpp檔 new : abc = std::shared_ptr<CppObjName>();

abc = NULL;



p_ptr* = NULL;


2.auto_ptr宣告方法

reference :https://openhome.cc/Gossip/CppGossip/autoPtr.html

3.h檔宣告

h檔半宣告 : abc* a;

cpp檔 new : a = new abc();

[VS code]VS code 環境設定 與 好用套件&熱鍵教學

1.Code Runner 
 2.RemoteSSH 
 3.C/C++ 
 4.C/C++ Extension Pack 
 5.C/C++ Themes 
 6.GitLens -- Git supercharged 





 搜尋關鍵字在workspace的使用 雙擊(滑鼠圈選關鍵字) + Ctrl + Shift + F

2022年9月9日 星期五

[MCU開發]解決S32K編譯時發生VMA error

 Description Resource Path Location Type Ld error: section .stack VMA [20002c00,20002fff] overlaps section .heap VMA Meter_AS_MCU C/C++ Problem

"c:/nxp/s32ds_arm_v2.2/s32ds/build_tools/gcc_v6.3/gcc-6.3-arm32-eabi/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/bin/real-ld.exe: section .stack VMA [20002d00,20002fff] overlaps section .heap VMA [20002a58,20002d57]"

這問題描述主要說的是./stack跟heap去重疊到

導致編譯錯誤


解法如下 : 

開啟S32 Design Studio 開啟專案的Project Settings->Linker files

點選S32K1xx_32_ram.ld


HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x00000400;

STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;

並在以下資料夾入前綴 : __attribute__ ((section(".data"))) 如下 : 

 __attribute__ ((section(".data")))m_interrupts          (RX)  : ORIGIN = 0x1FFFC000, LENGTH = 0x00000400

  __attribute__ ((section(".data")))m_text                (RX)  : ORIGIN = 0x1FFFC400, LENGTH = 0x00003C00

  /* SRAM_U */

  __attribute__ ((section(".data")))m_data                (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00003000

接著在S32K1xx_32_flash.ld

動態調整heap size跟stack size 如下 : 

HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x00000300;

STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000300;

即可解決

另一種暴力的方式如下 : 

#define VAR_PUT_IN_DATA_SECTION    __attribute__((section(".data")))

2022年8月24日 星期三

[嵌入式系統]開機的順序與記憶體的跳換

開機的順序為bootloader->u-boot

bootloader 可以想像成是PC開機到windows前的GRUB開機管理程式

ARM 結構的 CPU 會從位址 0x00000000 開始執行

但是bootloader是更底層

Bootloader會針對SoC的clock rate做初始化 以及Ram的初始化

透過memory map執行跳躍到u-boot區段

其中記錄開機後bootloader載入的區段,接著u-boot 是linux提前載入的程式階段在此階段會存在很多小工具讓使用診進行診斷或使用 - busybox。

其主要程式為Start.s,分為boot loading模式及下載模式,下載模式可使用一些指令下載,如xmodem, tftp, usb等 並將其存至Ram或Flash固存中。其中透過調用lowlevel_init.S的lowlevel_init進行u-boot相關的低階初始化。

接著跳轉到kernel 這段就是linux的核心層 也就是linux最基礎的功能包含driver的環境


kernel層完之後會根據參照及傳遞值跳躍到application層。


一但到application層即代表 已經開至Userspace上層

[C語言]Stack堆疊與Heap堆積的差別

https://www.twblogs.net/a/5d1b5c70bd9eee1e5c8311ef


 Stack 與 Heap 皆為C語言中處理底層記憶體的技術


Stack是有順序的疊加


Heap則會找空的疊加


Heap需要考慮到空間釋放的問題 (GC回收機制)

2021年7月15日 星期四

[Windows] 使用ffmpeg對mp4影片進行轉檔合併

Reference : 如何在Windows 10下合併多個MP4檔案的字幕和影片 - 銳力電子實驗室 (reneelab.net)


Step1 : cd D:

Step2 : cd ffmpeg/

Step3 : cd bin/

Step4 : ffmpeg.exe -i D:/1.mp4 –f mpeg D:/1.mpg

Step5 : ffmpeg.exe -i D:/2.mp4 –f mpeg D:/2.mpg

Step6 : cd ../../

Step7 : copy /b “D:/1.mpg”+”D:/2.mpg” “D:/3.mpg”

Step8 : ffmpeg.exe -i D:/3.mpg -f mp4 D:/3.mp4

2021年4月6日 星期二

[C語言韌體]微控制器(MCU)開發雜記








C語言在MCU的開發上使用while迴圈去進行大循環
常見會有while(1){...}的用法
有時候也會出現for( ; ; ) {...}的用法 跟while(1)是一樣的


20210506 更新 do{ ... }while(0)的妙用
do                                                                                             
{                                                                                              
        code statement                                                              
} while (0)

今天在看nRF52-DK 的code時看到官方定義的code出現此環節,一般來說,mcu會以上述while(1) 或for( ; ; ) 來進行無限迴圈的應用,以do{...}while(0)的定義並不是要做無窮迴圈應用為何還是這樣使用呢? 本來以為是coding style習慣問題,在參考完下述連結後,有更多此妙用的介紹。

好處是必執行外,不需要多餘的if else壟餘code 也避免goto的危險性








使用Trace32 debug
 
 





















 












 
 
 















因葦
k
ll
lll
 
 
 

2021年3月18日 星期四

[WINDOWS] FileZilla Server(FTP伺服器)架設

Reference : https://blog.xuite.net/yh96301/blog/62868611-%E5%85%8D%E8%B2%BB%E7%9A%84FTP%E4%BC%BA%E6%9C%8D%E5%99%A8FileZilla+Server 

官網下載網址 : https://filezilla-project.org/

點選 Download File Zilla Server

下載後 一直下一步已完成安裝

(架設 host 輸入localhost 或是 127.0.0.1)

安裝完後 點選 close

接著點選File Zilla Server Interface進入主程式

輸入密碼 或不用輸入 點選Connect 登入


點選單人頭圖標進入User

在右方Users 按下Add 並加入使用者

接著在中間Account Setting 勾選 Enable account 及 Password

接著點選左邊的Shared Folder 後 並點選中間的Add 加入使用者允許存取的本機路徑後 將所有存取權限打勾

按下ok即生效



防火牆

搜尋 允許應用程式通過Windows防火牆

並點選上方的變更設定賦予 管理者權限 接著選到 安裝目錄下的 FileZillaServer.exe ,輸入後按下確定關閉視窗 - '允許應用程式通過Windows防火牆' 即可。


NAT設定 : 網路位址轉換(英語:Network Address Translation,縮寫:NAT;又稱網路掩蔽、IP掩蔽)


2021年3月8日 星期一

[Python]字串切割存入list再透過socket傳送至server端

首先先加強對Python socket的了解

Reference : https://ithelp.ithome.com.tw/articles/10205819 

socket.accept //server等待client端的連線 accept代表socket 採用阻塞式訪問


位類別名稱宣告解釋內容
familysocket.AF_UNIX於本機端進行串接
socket.AF_INET於伺服器與伺服器之間進行串接
socket.AF_INET6使用IPv6於伺服器與伺服器之間進行串接
typesocket.SOCK_STREAM使用TCP(資料流)的方式提供可靠、雙向、串流的通信頻道
socket.SOCK_DGRAM使用UDP()的方式通用的免連線訊息交換通道

Reference : https://www.itread01.com/content/1541825839.html


socket物件方法
函式 型別 描述
s.bind() 服務端用 繫結地址和埠到套接字,引數address為元組形式的(host, port)
s.listen() 服務端用 開始監聽繫結的地址埠程式(程序),引數backlog指定在拒絕連線之前,可以掛起的最大連線數量。
s.accept() 服務端用 等待客戶端的連線(阻塞式)。
s.connect() 客戶端用 主動去連線伺服器,引數address為元組形式的(host, port),如果連接出錯,返回socket.error錯誤。
s.connect_ex() 客戶端用 主動去連線伺服器,引數address為元組形式的(host, port),出錯時返回出錯碼,而不是丟擲異常。
s.recv() 公共使用 接收資料,返回位元組型字串資料,引數bufsize指定接收資料的最大長度。
s.send() 公共使用 傳送資料,返回傳送成功的位元組數,引數data是要傳送的位元組型字串資料。
s.sendall() 公共使用 完整發送資料。內部迴圈呼叫send直至資料傳送完整,引數data是要傳送的位元組型字串資料。
s.recvfrom() 公共使用 接收資料,返回值是(data, address)。data是包含接收資料的字串,address是傳送資料的套接字地址。
s.sendto() 公共使用 傳送資料,將資料傳送到套接字,address形式為(host, port)的元組,指定遠端地址。返回值是傳送位元組數。
s.close() 公共使用 關閉套接字
s.getpeername() 公共使用 返回連線套接字的遠端地址。返回值通常是元組(host, port)。
s.getsockname() 公共使用 返回套接字自己的地址。通常是一個元組(host, port)。
s.setsockopt() 公共使用 設定給定套接字選項的值。
s.getsockopt() 公共使用 返回套接字選項的值。
s.settimeout() 公共使用 設定套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。
s.gettimeout() 公共使用 返回當前超時期的值,單位是秒,如果沒有設定超時期,則返回None。
s.fileno() 公共使用 接收資料,返回位元組型字串資料,引數bufsize指定接收資料的最大長度。
s.setblocking() 公共使用 flag為0非阻塞,否則為阻塞模式(預設)。非阻塞模式調recv()或send()沒有資料,將引起socket.error異常。
s.makefile() 公共使用 建立一個與該套接字相關連的檔案。


Reference : https://www.itread01.com/content/1549100881.html

def convertRaw_and_SplitToSave(split_size):
print("[Func]splitDataAndSave")
with open(r'c:\test.jpg', 'rb') as f:
res = base64.b64encode(f.read())
print("len = " + str(len(str(res))) + " Context : " + str(res))
globals.tmp_array = re.findall('.{' + str(split_size) + '}', str(res))
globals.tmp_array.append(str(res)[(len(globals.tmp_array) * split_size):])
globals.tmp_array[0] = str(globals.tmp_array[0]).strip('b\'')
#找尋最後一筆 把'過濾掉回存 先取得長度 將陣列長度減1 strip(''') 然後回存
print("end print " + str(globals.tmp_array[0]))
另外,在轉塗作字串切割時 會有b'的特殊符號出現,必須去除
在此,參考這篇【python】去除字符串头尾的多余符号
 https://blog.csdn.net/u014636245/article/details/103120201
使用.strip('b\'')去除掉 加鞋線是因為跳脫字元'
此外針對影像串流部分:
Reference : https://www.jianshu.com/p/931cd24450ec
上傳串流部分
result, imgencode = cv2.imencode('.jpg', frame, encode_param)
        data = numpy.array(imgencode)
        stringData = data.tobytes()

        stringDataLen = str(len(stringData)).ljust(16)
        print("stringDataLength = " + stringDataLen)
        client.send(stringDataLen.encode())
        print("stringDataLen = " + stringDataLen + " Context : " + str(stringData))
        print(stringData)
        data_perform = [b'']
        data_perform = re.findall(b"[\s\S]{500}", stringData)  # 就是这里需要做小小的改造,看仔细哦
        data_perform.append(stringData[(len(data_perform) * 500):])
        #globals.tmp_array = re.findall('.{' + str(split_size) + '}', str(stringData))
        #globals.tmp_array.append(str(stringData)[(len(globals.tmp_array) * split_size):])
        print(data_perform)
        print(len(data_perform))

        for i in range(len(data_perform)):
            print(" data_perform array len = " + str(len(data_perform)) + " ,prepare to send [" + str(i) + "]:" + str(data_perform[i]))
            client.send(data_perform[i]);

        ret, frame = capture.read()# 以幀為單位獲取影象
        decimg = cv2.imdecode(data, 1)
        cv2.imshow('CLIENT', decimg)
        key = cv2.waitKey(20)

        if key == 113:  # 按q拍照, 比照ASCII碼
            cv2.imwrite("fangjian2.jpeg", frame)  # 拍照存檔檔名
            continue
        if key == 27:  # 按esc停止, 比照ASCII碼
            break
    client.close()
    cv2.destroyAllWindows()
接收串流部分
def recvall(sock, count):
    buf = b''
    while count:
        newbuf = sock.recv(count)
        if not newbuf: return None
        buf += newbuf
        count -= len(newbuf)
    return buf

length = recvall(conn, 16)
            print(length)
            stringData = recvall(conn, int(length))
            data = numpy.fromstring(stringData, dtype='uint8')
            decimg = cv2.imdecode(data, 1)
            cv2.imshow('SERVER', decimg)
            cv2.waitKey(30)
            time.sleep(1)