<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一文讀懂RIL - OpenHarmony 3GPP 協議開發解讀

汽車電子技術 ? 來源:軟通夏德旺 ? 作者:軟通夏德旺 ? 2023-01-16 16:58 ? 次閱讀

作者 軟通夏德旺 在此特別鳴謝!

市面上關于終端(手機操作系統在 3GPP 協議開發的內容太少了,即使 Android 相關的資料都很少,Android 協議開發書籍我是沒有見過的??赡苁鞘袌鲂枨蟮木壒拾?,現在市場上還是前后端軟件開發從業人員最多,包括我自己。

基于我曾經也在某手機協議開發團隊干過一段時間,協議的 AP 側和 CP 側開發都整過,于是想嘗試下基于 OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)源碼寫點內容,幫助大家了解下協議開發領域,盡可能將 3gpp 協議內容與 OpenHarmony 電話子系統模塊進行結合講解。據我所知,現在終端協議開發非常缺人。首先聲明我不是協議專家,我也離開該領域有五六年了,如有錯誤,歡迎指正。

等我覺得自己整明白了,就會考慮出本《OpenHarmony 3GPP 協議開發深度剖析》書籍。

提到終端協議開發,我首先想到的就是 RIL 了。

專有名詞

CP:Communication Processor通信處理器),我一般就簡單理解為 modem 側,也可以理解為底層協議,這部分由各個 modem 芯片廠商完成(比如海思、高通)。

AP:Application Processor(應用處理器),通常就是指的手機終端,我一般就簡單理解為上層協議,主要由操作系統 Telephony 服務來進行處理。

RIL: Radio Interface Layer(無線電接口層),我一般就簡單理解為硬件抽象層,即 AP 側將通信請求傳給 CP 側的中間層。

AT指令: AT 指令是應用于終端設備與 PC 應用之間的連接與通信的指令。

設計思想

常規的 Modem 開發與調試可以使用 AT 指令來進行操作,而各家的 Modem 芯片的 AT 指令都會有各自的差異。因此手機終端廠商為了能在各種不同型號的產品中集成不同 modem 芯片,需要進行解耦設計來屏蔽各家 AT 指令的差異。于是 OpenHarmony 采用 RIL 對 Modem 進行 HAL(硬件抽象),作為系統與 Modem 之間的通信橋梁,為 AP 側提供控制 Modem 的接口,各 Modem 廠商則負責提供對應于 AT 命令的 Vender RIL(這些一般為封裝好的 so 庫),從而實現操作系統與 Modem 間的解耦。

OpenHarmony RIL架構

pYYBAGPFEeGAA4OkAADo4jb5pI8387.jpg

框架層:Telephony Service,電話子系統核心服務模塊,主要功能是初始化 RIL 管理、SIM 卡和搜網模塊。對應 OpenHarmony 的源碼倉庫 OpenHarmony / telephony_core_service。這個模塊也是非常重要的一個模塊,后期單獨再做詳細解讀。

硬件抽象層:即我們要講的 RIL,對應 OpenHarmony 的源碼倉庫 OpenHarmony / telephony_ril_adapter。RIL Adapter 模塊主要包括廠商庫加載,業務接口實現以及事件調度管理。主要用于屏蔽不同 modem 廠商硬件差異,為上層提供統一的接口,通過注冊 HDF 服務與上層接口通訊。

芯片層:Modem 芯片相關代碼,即 CP 側,這些代碼各個 Modem 廠商是不開放的,不出現在 OpenHarmony 中。

硬件抽象層

硬件抽象層又被劃分為了 hril_hdf 層、hril 層和 venderlib 層。

hril_hdf層:HDF 服務,基于 OpenHarmony HDF 框架,提供 hril 層與 Telephony Service 層進行通訊。

hril 層:hril 層的各個業務模塊接口實現,比如通話、短彩信、數據業務等。

vendorlib層:各 Modem 廠商提供的對應于 AT 命令庫,各個廠商可以出于代碼閉源政策,在這里以 so 庫形式提供。目前源碼倉中已經提供了一套提供代碼的 AT 命令操作,至于這個是針對哪個型號 modem 芯片的,我后續了解清楚再補充。

下面是 ril_adapter 倉的源碼結構:


base/telephony/ril_adapter
├── figures # readme資源文件
├── frameworks
│ ├── BUILD.gn
│ └── src # 序列化文件
├── interfaces # 對應提供上層各業務內部接口
│ └── innerkits
├── services # 服務
│ ├── hril # hril層的各個業務模塊接口實現
│ ├── hril_hdf # HDF服務
│ └── vendor # 廠商庫文件
└── test # 測試代碼
├── BUILD.gn
├── mock
└── unittest # 單元測試代碼

核心業務邏輯梳理

本文解讀 RIL 層很小一部分代碼,RIL 是如何通過 HDF 與 Telephony 連接上的,以后更加完整的邏輯梳理會配上時序圖講解,會更加清晰。首先我們要對 OpenHarmony 的 HDF(Hardware Driver Foundation)驅動框架做一定了解,最好是動手寫一個 Demo 案例,具體的可以單獨去官網查閱 HDF 資料。

首先,找到 hril_hdf.c 文件的代碼,它承擔的是驅動業務部分,源碼中是不帶中文注釋的,為了梳理清楚流程,我給源碼關鍵部分加上了中文注釋。

/*

* Copyright (C) 2021 Huawei Device Co., Ltd.

* Licensed under the Apache License, Version 2.0 (the “License”);

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an “AS IS” BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

#include “hril_hdf.h”

#include

#include

#include

#include “dfx_signal_handler.h”

#include “parameter.h”

#include “modem_adapter.h”

#include “telephony_log_c.h”

#define RIL_VENDOR_LIB_PATH “persist.sys.radio.vendorlib.path”

#define BASE_HEX 16

static struct HRilReport g_reportOps = {

OnCallReport,

OnDataReport,

OnModemReport,

OnNetworkReport,

OnSimReport,

OnSmsReport,

OnTimerCallback

};

static int32_t GetVendorLibPath(char *path)

{

int32_t code = GetParameter(RIL_VENDOR_LIB_PATH, “”, path, PARAMETER_SIZE);

if (code 《= 0) {

TELEPHONY_LOGE(“Failed to get vendor library path through system properties. err:%{public}d”, code);

return HDF_FAILURE;

}

return HDF_SUCCESS;

}

static UsbDeviceInfo *GetPresetInformation(const char *vId, const char *pId)

{

char *out = NULL;

UsbDeviceInfo *uDevInfo = NULL;

int32_t idVendor = (int32_t)strtol(vId, &out, BASE_HEX);

int32_t idProduct = (int32_t)strtol(pId, &out, BASE_HEX);

for (uint32_t i = 0; i 《 sizeof(g_usbModemVendorInfo) / sizeof(UsbDeviceInfo); i++) {

if (g_usbModemVendorInfo[i].idVendor == idVendor && g_usbModemVendorInfo[i].idProduct == idProduct) {

TELEPHONY_LOGI(“list index:%{public}d”, i);

uDevInfo = &g_usbModemVendorInfo[i];

break;

}

}

return uDevInfo;

}

static UsbDeviceInfo *GetUsbDeviceInfo(void)

{

struct udev *udev;

struct udev_enumerate *enumerate;

struct udev_list_entry *devices, *dev_list_entry;

struct udev_device *dev;

UsbDeviceInfo *uDevInfo = NULL;

udev = udev_new();

if (udev == NULL) {

TELEPHONY_LOGE(“Can‘t create udev”);

return uDevInfo;

}

enumerate = udev_enumerate_new(udev);

if (enumerate == NULL) {

TELEPHONY_LOGE(“Can’t create enumerate”);

return uDevInfo;

}

udev_enumerate_add_match_subsystem(enumerate, “tty”);

udev_enumerate_scan_devices(enumerate);

devices = udev_enumerate_get_list_entry(enumerate);

udev_list_entry_foreach(dev_list_entry, devices) {

const char *path = udev_list_entry_get_name(dev_list_entry);

if (path == NULL) {

continue;

}

dev = udev_device_new_from_syspath(udev, path);

if (dev == NULL) {

continue;

}

dev = udev_device_get_parent_with_subsystem_devtype(dev, “usb”, “usb_device”);

if (!dev) {

TELEPHONY_LOGE(“Unable to find parent usb device.”);

return uDevInfo;

}

const char *cIdVendor = udev_device_get_sysattr_value(dev, “idVendor”);

const char *cIdProduct = udev_device_get_sysattr_value(dev, “idProduct”);

uDevInfo = GetPresetInformation(cIdVendor, cIdProduct);

udev_device_unref(dev);

if (uDevInfo != NULL) {

break;

}

}

udev_enumerate_unref(enumerate);

udev_unref(udev);

return uDevInfo;

}

static void LoadVendor(void)

{

const char *rilLibPath = NULL;

char vendorLibPath[PARAMETER_SIZE] = {0};

// Pointer to ril init function in vendor ril

const HRilOps *(*rilInitOps)(const struct HRilReport *) = NULL;

// functions returned by ril init function in vendor ril

const HRilOps *ops = NULL;

UsbDeviceInfo *uDevInfo = GetUsbDeviceInfo();

if (GetVendorLibPath(vendorLibPath) == HDF_SUCCESS) {

rilLibPath = vendorLibPath;

} else if (uDevInfo != NULL) {

rilLibPath = uDevInfo-》libPath;

} else {

TELEPHONY_LOGI(“use default vendor lib.”);

rilLibPath = g_usbModemVendorInfo[DEFAULT_MODE_INDEX].libPath;

}

if (rilLibPath == NULL) {

TELEPHONY_LOGE(“dynamic library path is empty”);

return;

}

TELEPHONY_LOGI(“RilInit LoadVendor start with rilLibPath:%{public}s”, rilLibPath);

g_dlHandle = dlopen(rilLibPath, RTLD_NOW);

if (g_dlHandle == NULL) {

TELEPHONY_LOGE(“dlopen %{public}s is fail. %{public}s”, rilLibPath, dlerror());

return;

}

rilInitOps = (const HRilOps *(*)(const struct HRilReport *))dlsym(g_dlHandle, “RilInitOps”);

if (rilInitOps == NULL) {

dlclose(g_dlHandle);

TELEPHONY_LOGE(“RilInit not defined or exported”);

return;

}

ops = rilInitOps(&g_reportOps);

HRilRegOps(ops);

TELEPHONY_LOGI(“HRilRegOps completed”);

}

// 用來處理用戶態發下來的消息

static int32_t RilAdapterDispatch(

struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)

{

int32_t ret;

static pthread_mutex_t dispatchMutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_lock(&dispatchMutex);

TELEPHONY_LOGI(“RilAdapterDispatch cmd:%{public}d”, cmd);

ret = DispatchRequest(cmd, data);

pthread_mutex_unlock(&dispatchMutex);

return ret;

}

static struct IDeviceIoService g_rilAdapterService = {

.Dispatch = RilAdapterDispatch,

.Open = NULL,

.Release = NULL,

};

//驅動對外提供的服務能力,將相關的服務接口綁定到HDF框架

static int32_t RilAdapterBind(struct HdfDeviceObject *device)

{

if (device == NULL) {

return HDF_ERR_INVALID_OBJECT;

}

device-》service = &g_rilAdapterService;

return HDF_SUCCESS;

}

// 驅動自身業務初始的接口

static int32_t RilAdapterInit(struct HdfDeviceObject *device)

{

if (device == NULL) {

return HDF_ERR_INVALID_OBJECT;

}

DFX_InstallSignalHandler();

struct HdfSBuf *sbuf = HdfSbufTypedObtain(SBUF_IPC);

if (sbuf == NULL) {

TELEPHONY_LOGE(“HdfSampleDriverBind, failed to obtain ipc sbuf”);

return HDF_ERR_INVALID_OBJECT;

}

if (!HdfSbufWriteString(sbuf, “string”)) {

TELEPHONY_LOGE(“HdfSampleDriverBind, failed to write string to ipc sbuf”);

HdfSbufRecycle(sbuf);

return HDF_FAILURE;

}

if (sbuf != NULL) {

HdfSbufRecycle(sbuf);

}

TELEPHONY_LOGI(“sbuf IPC obtain success!”);

LoadVendor();

return HDF_SUCCESS;

}

// 驅動資源釋放的接口

static void RilAdapterRelease(struct HdfDeviceObject *device)

{

if (device == NULL) {

return;

}

dlclose(g_dlHandle);

}

//驅動入口注冊到HDF框架,這里配置的moduleName是找到Telephony模塊與RIL進行通信的一個關鍵配置

struct HdfDriverEntry g_rilAdapterDevEntry = {

.moduleVersion = 1,

.moduleName = “hril_hdf”,

.Bind = RilAdapterBind,

.Init = RilAdapterInit,

.Release = RilAdapterRelease,

};

// 調用HDF_INIT將驅動入口注冊到HDF框架中,在加載驅動時HDF框架會先調用Bind函數,再調用Init函數加載該驅動,當Init調用異常時,HDF框架會調用Release釋放驅動資源并退出。

HDF_INIT(g_rilAdapterDevEntry);

上述代碼中配置了對應該驅動的 moduleName 為"hril_hdf",因此我們需要去找到對應驅動的配置文件,以 Hi3516DV300 開發板為例,它的驅動配置在 vendor_hisilicon/ Hi3516DV300 / hdf_config / uhdf / device_info.hcs 代碼中可以找到,如下:

riladapter :: host {
hostName = "riladapter_host";
priority = 50;
riladapter_device :: device {
device0 :: deviceNode {
policy = 2;
priority = 100;
moduleName = "libhril_hdf.z.so";
serviceName = "cellular_radio1";
}
}
}

這里可以發現該驅動對應的服務名稱為 cellular_radio1,那么 telephony_core_service 通過 HDF 與 RIL 進行通信肯定會調用到該服務名稱,因此無查找 telephony_core_service 的相關代碼,可以很快定位到 telephony_core_service/ services / tel_ril / src / tel_ril_manager.cpp 該代碼,改代碼中有一個關鍵類 TelRilManager,它用來負責管理 tel_ril。

看 tel_ril_manager.cpp 中的一個關鍵函數 ConnectRilAdapterService,它就是用來通過 HDF 框架獲取RIL_ADAPTER 的服務,之前定義過 RIL_ADAPTER_SERVICE_NAME 常量為 "cellular_radio1",它就是在 vendor_hisilicon/ XXXX / hdf_config / uhdf / device_info.hcs 中配置的 hril_hdf 驅動對應的服務名稱。

bool TelRilManager::ConnectRilAdapterService()

{

std::lock_guard《std::mutex》 lock_l(mutex_);

rilAdapterRemoteObj_ = nullptr;

auto servMgr_ = OHOS::HDI::ServiceManager::V1_0::IServiceManager::Get();

if (servMgr_ == nullptr) {

TELEPHONY_LOGI(“Get service manager error!”);

return false;

}

//通過HDF框架獲取RIL_ADAPTER的服務,之前定義過RIL_ADAPTER_SERVICE_NAME常量為“cellular_radio1”,它就是在 vendor_hisilicon/ XXXX / hdf_config / uhdf / device_info.hcs中配置的hril_hdf驅動對應的服務名稱

rilAdapterRemoteObj_ = servMgr_-》GetService(RIL_ADAPTER_SERVICE_NAME.c_str());

if (rilAdapterRemoteObj_ == nullptr) {

TELEPHONY_LOGE(“bind hdf error!”);

return false;

}

if (death_ == nullptr) {

TELEPHONY_LOGE(“create HdfDeathRecipient object failed!”);

rilAdapterRemoteObj_ = nullptr;

return false;

}

if (!rilAdapterRemoteObj_-》AddDeathRecipient(death_)) {

TELEPHONY_LOGE(“AddDeathRecipient hdf failed!”);

rilAdapterRemoteObj_ = nullptr;

return false;

}

int32_t ret = SetCellularRadioIndication();

if (ret != CORE_SERVICE_SUCCESS) {

TELEPHONY_LOGE(“SetCellularRadioIndication error, ret:%{public}d”, ret);

return false;

}

ret = SetCellularRadioResponse();

if (ret != CORE_SERVICE_SUCCESS) {

TELEPHONY_LOGE(“SetCellularRadioResponse error, ret:%{public}d”, ret);

return false;

}

return true;

}

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 協議
    +關注

    關注

    2

    文章

    572

    瀏覽量

    38954
  • 3GPP
    +關注

    關注

    4

    文章

    413

    瀏覽量

    44910
  • HDF框架
    +關注

    關注

    0

    文章

    9

    瀏覽量

    2735
  • OpenHarmony
    +關注

    關注

    24

    文章

    3442

    瀏覽量

    15294
收藏 人收藏

    評論

    相關推薦

    3GPP協議中哪些是手機的測試文檔

    現在在了解些有關3GPP測試的文檔,但是3GPP的內容很多,下子抓不住重點來看.我想看些有關手機測試的
    發表于 11-21 14:41

    3GPP協議中文版

    3GPP協議中文版.
    發表于 08-01 23:45

    3GPP的概念是什么?

    3GPP的目標是實現由2G網絡到3G網絡的平滑過渡,保證未來技術的后向兼容性,支持輕松建網及系統間的漫游和兼容性。
    發表于 09-20 09:10

    如何實現3GPP毫微微蜂窩測試?

    如何評估3GPP家庭節點B的性能?3GPP毫微微蜂窩技術是什么?毫微微蜂窩基站部署的重要組件有哪些?如何實現3GPP毫微微蜂窩測試?
    發表于 04-15 06:30

    3GPP R5中IMS的基本結構是怎樣構成的?

    SIP協議是什么?3GPP R5中IMS的基本結構是怎樣構成的?漫游用戶的會話過程是如何建立起來的?
    發表于 05-27 06:02

    讀懂什么是NEC協議

    讀懂什么是NEC協議?
    發表于 10-15 09:22

    OpenHarmony 3GPP協議開發資料分享

    1、OpenHarmony 3GPP協議開發RIL詳解專有名詞CP: Communication Processor(通信處理器),我
    發表于 03-18 10:37

    OpenHarmony 3GPP協議開發深度剖析——讀懂RIL

    考慮出本《OpenHarmony 3GPP 協議開發深度剖析》書籍。提到終端協議開發,我首先想到
    發表于 05-06 11:06

    OpenHarmony 3GPP協議開發深度剖析》之--搜網流程之PLMN選擇

    協議開發最大的法寶就是反復閱讀3GPP協議標準,然后結合標準梳理信令流程,同時比對modem日志或者ap側日志,閱讀modem側源碼或者ap側源碼。本系列主題在操作系統
    發表于 09-14 10:31

    3GPP協議版本的發展路線

    3GPP協議版本的發展路線3GPP協議版本分為R99/R4/R5/R6等多個階段,其中R99協議于2000年3月凍結功能,R4
    發表于 06-13 22:23 ?2560次閱讀

    3GPP協議說明

    3GPP 的目標是實現由2G網絡到3G網絡的平滑過渡,保證未來技術的后向兼容性,支持輕松建網及系統間的漫游和兼容性。 其職能: 3GPP主要是制訂以GSM核心網為基礎,UTRA(FDD為W-CDMA技術,
    發表于 06-16 10:35 ?48次下載

    3GPP最基礎的協議_英文版

    3GPP最基礎的協議,通讀后,即可對移動通信有大致的了解。
    發表于 03-01 09:39 ?0次下載

    3GPP協議中文版

    3GPP協議中文版,入網測試專用,各種測試指標
    發表于 05-09 09:41 ?0次下載

    一文讀懂3GPP到底是什么

    業界了解3GPP如何開發4G和5G的標準越來越重要,因為移動生態系統的擴展遠遠超過了智能手機的范疇,從汽車到公共安全,再到物聯網的興起,越來越多的行業逐漸與3GPP生態系統發生關系。隨著5G的到來,將生態系統推向新的發展務必重要
    發表于 09-29 08:59 ?2w次閱讀

    3GPP協議 36.508版本pdf下載

    3GPP協議 36.508
    發表于 03-07 14:43 ?0次下載
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>