Chino 操作系統開發日志 (1) - 為 IoT 而生


引言

很多人都聽說過 IoT (物聯網)這個詞,越來越多的人在裝修時開始選擇智能家居,很多人也購買智能音箱做智能家居控制,想必未來一定是 AI + 物聯網的時代。

一種技術要發展並走向成熟必須要降低門檻,提高迭代速度。傳統的嵌入式開發太碎片化,很多時候還在使用代碼復制、粘貼、修改的開發方法。如果不提供一個開箱即用的開發平台,讓磚瓦能一層層疊上去,是很難開發更高級的應用的。

因此需要一個這樣的平台:

  • 提供足夠的硬件抽象能力
  • 提供友好的編程接口和調試接口

同時結合 IoT 的特點還要:

 

  • 靈活控制非標准的定制硬件
  • 適應有限資源的運行設備

因此 IoT 操作系統應運而生。

目前很多公司已經開始布局 IoT 操作系統,如 RT-Thread,華為的 LiteOS 等。

Chino OS

Chino OS 由包括我在內的開發團隊設計開發的一款開源 IoT 操作系統。GitHub 地址:https://github.com/chino-os/chino-os

Chino 主要使用 C++ 語言編寫,配有專用的 GNU 工具鏈和 C 運行庫,使用 DeviceTree 描述硬件配置。目前系統具有以下特性:

  • 多任務 (6 個優先級, Round robin 調度)
  • 線程同步 (Mutex, Recurisve Mutex, Semaphore, Event)
  • 進程間通信 (Mailslot)
  • 統一的驅動模型
  • 網絡支持 (基於 LwIP 的 Socket API)

Chino 預定義了一組驅動接口,為應用開發者提供了一個統一的 API 層,使得開發者的大部分需求不用關心具體硬件差異。部分設備抽象如下表:

類別 子類 示例驅動
中斷控制器   cortex-m3, nvic
IO / 總線 GPIO stm32f10x, gpio
I²C stm32f10x, i2c
SPI stm32f10x, spi
串行 stm32f10x, uart
SDIO stm32f10x, sdio
存儲 EEPROM AT24C02
Flash GD25Q128
SD 內存卡 SD V2.0 大容量存儲
顯示 TFT LCD ILI9486L
網絡 以太網 ENC28J60
傳感器 加速度計 ADXL345

Chino 目前支持 x86_64、Cortex-M3 架構,可運行在 PC 和 STM32 開發板上。未來計划支持 ESP32、RISCV32/64 等更多架構。

Chino 在 STM32F103 上的運行截圖

Chino 在 STM32F103 開發板上的運行截圖

代碼示例

1. GPIO 亮小燈

亮小燈可以說是嵌入式開發的 Hello World 了。

 1 auto access = OA_Read | OA_Write;
 2 auto gpio = g_ObjectMgr->GetDirectory(WKD_Device).Open("gpio3", access).MoveAs<GpioController>();
 3 auto pin0 = gpio->OpenPin(0, access);
 4 pin0->SetDriveMode(GpioPinDriveMode::Output);
 5 
 6 while (true)
 7 {
 8     pin0->Write(GpioPinValue::Low);
 9     g_ProcessMgr->SleepCurrentThread(1s);
10     pin0->Write(GpioPinValue::High);
11     g_ProcessMgr->SleepCurrentThread(1s);
12 }

程序申請讀寫權限打開名為 “gpio3” 的 GPIO 控制器,然后打開第 0 個 Pin,並設置該 Pin 的驅動模式為輸出。

然后間隔 1s 切換輸出高低電平。

這段代碼隱藏了硬件具體細節,在任意具有 GPIO 的硬件上無需修改代碼便可運行。

2. 讀寫 Flash

 1 auto flash1 = g_ObjectMgr->GetDirectory(WKD_Device).Open("flash1", access).MoveAs<FlashStorage>();
 2 {
 3     gsl::span<const uint8_t> writeBuffers[] = { buffer };
 4     flash1->Write(0, { writeBuffers });
 5 }
 6 {
 7     gsl::span<uint8_t> readBuffers[] = { buffer };
 8     kassert(flash1->Read(0, { readBuffers }) == std::size(buffer));
 9     g_Logger->PutString("GD25Q128 Read:\n");
10     g_Logger->DumpHex(buffer, std::size(buffer));
11 }

這段代碼功能很簡單:打開 flash 之后寫入數據然后讀取數據。唯一需要說明的是 Chino 的 IO 部分均使用 BufferList 來讀寫數據,因此可以支持多個非連續內存段讀寫,且沒有復制開銷。

3. TCP Echo

 1 auto eth0 = g_NetworkMgr->InstallNetworkDevice(g_ObjectMgr->GetDirectory(WKD_Device).Open("eth0", OA_Read | OA_Write).MoveAs<EthernetController>());
 2 eth0->SetAsDefault();
 3 eth0->Setup();
 4 g_NetworkMgr->Run();
 5 
 6 auto bindAddr = std::make_shared<IPEndPoint>(IPAddress::IPv4Any, 80);
 7 auto socket = MakeObject<Socket>(AddressFamily::IPv4, SocketType::Stream, ProtocolType::Tcp);
 8 socket->Bind(bindAddr);
 9 socket->Listen(1);
10 
11 auto client = socket->Accept();
12 while (true)
13 {
14     const uint8_t text[] = "hello\n";
15     gsl::span<const uint8_t> buffers[] = { {text,6} };
16 
17     try
18     {
19         client->Send({ buffers });
20         g_ProcessMgr->SleepCurrentThread(1s);
21     }
22     catch (...)
23     {
24         break;
25     }
26 }

程序打開名為 “eth0” 的以太網控制器,並注冊到網絡子系統。

然后創建一個 Tcp Socket,並監聽 80 端口。

接受一個客戶端連接並循環輸出 hello,直到連接被關閉則退出循環。

系列說明

本文作為 Chino 操作系統開發日志的第一篇,簡單概述了 Chino 目前的開發進度和基本的編程模型。今后的文章會詳細介紹各個子系統的設計和開發的最新進展。

歡迎大家提出批評和建議,幫助 Chino 發展得更好。

 

最后再次附上 Chino 項目地址:https://github.com/chino-os/chino-os,希望大家多 star,多提 issue。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM