diff --git a/en/device-dev/driver/driver-peripherals-lcd-des.md b/en/device-dev/driver/driver-peripherals-lcd-des.md index 0a4e12179b5e6328a1f051440ca35fc16877b706..f4eafc5e8f90f38928293f0205c2be5b1e5b7635 100644 --- a/en/device-dev/driver/driver-peripherals-lcd-des.md +++ b/en/device-dev/driver/driver-peripherals-lcd-des.md @@ -6,7 +6,7 @@ The Liquid Crystal Display (LCD) driver performs operations such as powering on the LCD and initializing the internal registers of the driver integrated circuits (ICs). -The display driver model based on the [Hardware Driver Foundation (HDF)](../driver/driver-hdf-overview.md) provides the following functions: +The display driver model based on the [Hardware Driver Foundation (HDF)](driver-overview-foundation.md) provides the following functions: - Provides a basic framework for LCD driver development to improve development efficiency. @@ -46,7 +46,7 @@ The LCD interfaces include the Mobile Industry Processor Interface (MIPI) Displa ![](figures/ttl-interface.png "ttl-interface") - TTL level signals are generated by TTL devices, which are a major type of digital integrated circuits. TTL devices are manufactured using the bipolar process and feature high speed, low power consumption, and diversified types. + TTL level signals are generated by TTL devices, which are a major type of digital integrated circuits. TTL devices are manufactured using the bipolar process and feature high speed, low power consumption, and diversified types. The TTL interface is used to transmit data in parallel mode under control signals. It transmits data signals, clock signals, and control signals (such as line synchronization signals, frame synchronization signals, and data validity signals). For the LCD with the TTL, additional peripheral interfaces, such as the Serial Peripheral Interface (SPI) and Inter-Integrated Circuit (I2C), are required for the read and write of the internal registers. @@ -62,11 +62,13 @@ Before applying your device with OpenHarmony system, you need to perform LCD dri ### Available APIs +To adjust the parameters of the LCD, establish a display channel with the display, and implement the display effect, use **display::host** to register the **PanelInfo** struct and interface information and add device description. + Table 1 APIs required for LCD driver adaptation | API | Description | | :------------------------------------------------------ | ------------------- | -| display :: host | Sets device information. | +| static int32_t MipiDsiInit(struct PanelInfo *info) | Initializes the corresponding chip platform driver.| | static int32_t LcdResetOn(void) | Sets the status of the reset pin.| | int32_t SampleEntryInit(struct HdfDeviceObject *object) | Initializes the entry function of the device driver. | @@ -77,7 +79,7 @@ Table 1 APIs required for LCD driver adaptation 2. Adapt the driver to the chip at the SoC adapter layer. -3. Add the LCD panel driver and register the panel driver functions in the driver entry function **Init**. The functions provide capabilities for: +3. Add the LCD panel driver and register the panel driver data in the driver entry function **Init**. The driver data interface implements the following features: - Powering on/off the LCD device Based on the LCD hardware connection, use the GPIO APIs provided by the platform to perform operations on the LCD pins, such as the reset pin and IOVCC pin. For details about the power-on sequence, see the SPEC provided by the LCD supplier. @@ -86,7 +88,7 @@ Table 1 APIs required for LCD driver adaptation Based on the LCD hardware interfaces, use the I2C, SPI, and MIPI interfaces provided by the platform to download the LCD initialization sequence. For details, see the SPEC provided by the LCD supplier. -4. (Optional) Implement other HDF APIs, such as **Release()**, as required. +4. (Optional) Implement other HDF interfaces as required. 5. (Optional) Create other device nodes for implementing service logic or debugging based on the HDF as required. @@ -136,7 +138,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf } ``` -2. Configure the chip platform driver information in the **drivers/hdf_core/framework/model/display/driver/adapter_soc/hi35xx_disp.c file**. +2. Configure the chip platform driver information in **drivers/hdf_core/framework/model/display/driver/adapter_soc/hi35xx_disp.c**. ```c++ /* Configuration of the display driver to adapt to the MIPI and chip platform */ @@ -179,9 +181,9 @@ The following uses the Hi35xx series chips as an example to describe how to perf } ``` -3. Add a device in **drivers/hdf_core/framework/model/display/driver/panel/mipi_icn9700.c**. +3. Add a device. - - Define driver-related interface information. + - Define driver-related interfaces (**drivers/hdf_core/framework/model/display/driver/panel/mipi_icn9700.c**). ```c++ #define RESET_GPIO 5 @@ -203,7 +205,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf #define FRAME_RATE 60 ``` - - Define the **PanelInfo** structure. + - Define the **PanelInfo** struct (**drivers/hdf_core/framework/model/display/driver/hdf_disp.h**). ```c++ struct PanelInfo { @@ -214,7 +216,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf uint32_t hsw; // Horizontal synchronization width uint32_t vbp; // Vertical back porch uint32_t vfp; // Vertical front porch - uint32_t vsw; // Vertial synchronization width + uint32_t vsw; // Vertical synchronization width uint32_t frameRate; // Frame rate enum LcdIntfType intfType; // LCD interface type enum IntfSync intfSync; // User timing parameter @@ -224,7 +226,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf }; ``` - - Initialize the LCD. + - Initialize the LCD (**drivers/hdf_core/framework/model/display/driver/panel/mipi_icn9700.c**). ```c++ static uint8_t g_payLoad0[] = { 0xF0, 0x5A, 0x5A }; @@ -256,7 +258,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf static DevHandle g_pwmHandle = NULL; ``` - - Set the status of the reset pin. + - Set the Reset pin status (**/drivers_hdf_core/framework/model/display/driver/panel/mipi_icn9700.c**). ```c++ static int32_t LcdResetOn(void) @@ -280,7 +282,7 @@ The following uses the Hi35xx series chips as an example to describe how to perf } ``` - - Initialize the entry function of the device driver. + - Define the device driver entry function (**/drivers_hdf_core/framework/model/display/driver/panel/mipi_icn9700.c**). ```c++ /* Initialize the entry function. */ diff --git a/en/device-dev/driver/driver-peripherals-light-des.md b/en/device-dev/driver/driver-peripherals-light-des.md index 9b680a1bced3964d7197ad7c99004105988a40e1..0127fc711c1518d26cd8e673ea09e2d210f1390d 100644 --- a/en/device-dev/driver/driver-peripherals-light-des.md +++ b/en/device-dev/driver/driver-peripherals-light-des.md @@ -3,7 +3,7 @@ ## Overview -### Light +### Introduction The light driver model provides APIs for the upper-layer light hardware service layer to control lights, including obtaining the light type, setting the lighting mode and blinking effect, and turning on or off a light. This model implements cross-OS porting and differentiated configurations based on the Hardware Driver Foundation (HDF) to achieve the goal of "one-time development for cross-system deployment" of the light driver. @@ -21,7 +21,7 @@ The figure below shows how the light driver works. ![How light driver works](figures/light_working.png) -The following describes how the light module driver loads and starts on a Hi3516D V300 board that runs the standard system. +The following describes how to start and run the light module driver on an RK3568 board that runs the standard system. 1. The Device Manager reads the Light device management configuration from the **device_info.hcs** file. 2. The Device Manager reads the light data configuration from the **light_config.hcs** file. @@ -42,17 +42,74 @@ The light driver model provides APIs for obtaining information about all the lig **Table 1** APIs of the light driver model +**NOTE**
The following APIs are C interfaces. For details about the interface declaration, see [/drivers/peripheral/light/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/light/interfaces/include). + | API | Description | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| int32_t (*GetLightInfo)([out] struct LightInfo **lightInfo, [out] uint32_t *count) | Obtains information about all types of lights in the system.
**lightInfo** indicates the double pointer to the light information obtained.
**count** indicates the pointer to the number of lights.| -| int32_t (*TurnOnLight)([in] uint32_t lightId, [in] struct LightEffect *effect) | Turns on available lights in the list based on the specified light type.
**lightId** indicates the light type, and **effect** indicates the pointer to the light effect.| -| int32_t (*TurnOffLight)([in] uint32_t lightId) | Turns off available lights in the list based on the specified light type. | +| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | Obtains information about all types of lights in the system.
**lightInfo** indicates the double pointer to the light information obtained.
**count** indicates the pointer to the number of lights.| +| int32_t (*TurnOnLight)(uint32_t lightId, struct LightEffect *effect) | Turns on available lights in the list based on the specified light type.
**lightId** indicates the light type, and **effect** indicates the pointer to the light effect.| +| int32_t (*TurnOffLight)(uint32_t lightId) | Turns off available lights in the list based on the specified light type. | +| int32_t (*TurnOnMultiLights)(uint32_t lightId, const struct LightColor *colors, const uint32_t count); | Turns on multiple sub-lights of a light based on the specified light type ID. | + +### How to Develop +Develop the light driver based on the HDF and driver entry, configure resources, and parse the HCS configuration file. + +1. Configure the light driver in the host. + + - Light HCS file path: **vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs**. + + - The code is as follows: + + ```c + /* HCS of the light device. */ + light :: host { + hostName = "light_host"; + device_light :: device { + device0 :: deviceNode { + policy = 2; // Policy for the driver to publish services. If the value is 0, the driver does not publish services. If the value is 1, the driver publishes services to the kernel space. If the value is 2, the driver publishes services to both the kernel space and user space. + priority = 100; // Priority (0–200) for starting the light driver. A larger value indicates a lower priority. The recommended value is 100. If the priorities are the same, the device loading sequence is not ensured. + preload = 0; // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite. + permission = 0664; // Permission for the device node created. + moduleName = "HDF_LIGHT"; // Light driver name. The value must be the same as the value of moduleName in the driver entry structure. + serviceName = "hdf_light"; // Service published by the light driver. The service name must be unique. + deviceMatchAttr = "hdf_light_driver"; // Keyword matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver. + } + } + } + ``` + +2. Configure the private HCS of the light driver. + + - Code path: **vendor\hihope\rk3568\hdf_config\khdf\light\light_config.hcs**. + + - The code is as follows: + + ```c + root { + lightConfig { + boardConfig { + match_attr = "hdf_light_driver"; + lightAttr { + light01 { + lightId = [1]; // Lightid can contain multiple logical light IDs. For example, 1 indicates the power indicator. + lightName = "battery"; + lightNumber = 1; + busRNum = 147; // GPIO value corresponding to red (light effect color). + busGNum = 146; // GPIO value corresponding to green (light effect color). + busBNum = 149; // GPIO value corresponding to blue (light effect color). + defaultBrightness = 0X00FFFFFF; // Default luminance value of the system. B: bits 0 to 7; R: bits 8 to 15; G: bits 16 to 23; extended bits 24 to 31. + onTime = 50; // Minimum duration (in milliseconds) supported by the system when the flash is on. + offTime = 50; // Minimum duration (in milliseconds) supported by the system when the flash is off. + } + } + } + } + } + ``` -### Development Procedure -1. Based on the HDF and the driver entry, complete the light abstract driver development (using the **Bind**, **Init**, **Release**, and **Dispatch** functions), resource configuration, and HCS parsing. +3. Implement the light driver in **drivers\hdf_core\framework\model\misc\light\driver\src\light_driver.c**. - - Call **HDF_INIT** to register the driver entry with the HDF. Generally, the HDF calls the **Bind** function and then the **Init** function to load the driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit. - - The light driver model uses HDF configuration source (HCS). For details about HCS fields, see [Configuration Management](driver-hdf-manage.md). The light driver entry is defined as follows: + - Define the **HdfDriverEntry** object of the light driver. The driver entry function is defined as follows: ```c /* Register the light entry data structure object. */ @@ -63,94 +120,82 @@ The light driver model provides APIs for obtaining information about all the lig .Init = InitLightDriver, // Init() of the light driver. .Release = ReleaseLightDriver, // Release() of the light driver. }; - /* Call HDF_INIT to register the driver entry with the HDF. */ + /* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init() to load the driver. If Init() fails to be called, the HDF calls Release() to release resources and exit. */ HDF_INIT(g_lightDriverEntry); ``` - - Develop the light abstract driver. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions. + - Implement **Bind()** of the light driver. ```c - /* Dispatch the light driver. */ - static int32_t DispatchLight(struct HdfDeviceIoClient *client, - int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) { - CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); - return GetAllLightInfo(data, reply); - } - - CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); - (void)OsalMutexLock(&drvData->mutex); - if (!HdfSbufReadInt32(data, &lightId)) { - HDF_LOGE("%s: sbuf read lightId fail", __func__); - (void)OsalMutexUnlock(&drvData->mutex); - return HDF_ERR_INVALID_PARAM; - } - ..... - ret = DispatchCmdHandle(lightId, data, reply); - (void)OsalMutexUnlock(&drvData->mutex); - return ret; - } - /* Bind the external service provided by the light driver to the HDF. */ int32_t BindLightDriver(struct HdfDeviceObject *device) { struct LightDriverData *drvData = NULL; CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); - /* Allocate resources for private interfaces. */ + /* Allocate resources for private interfaces. */ drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData)); CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); - /* Functions to be dispatched. */ + /* Functions to be dispatched. */ drvData->ioService.Dispatch = DispatchLight; drvData->device = device; device->service = &drvData->ioService; g_lightDrvData = drvData; + return HDF_SUCCESS; } - + ``` + + - Implement **Init()** of the light driver. + + ```c /* Initialize the light driver. */ int32_t InitLightDriver(struct HdfDeviceObject *device) - { - ..... - /* Initialize the workqueue. */ + { + struct LightDriverData *drvData = NULL; + + drvData = (struct LightDriverData *)device->service; + + if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) { + return HDF_FAILURE; + } + /* Initialize the workqueue. */ if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) { - HDF_LOGE("%s: init workQueue fail!", __func__); return HDF_FAILURE; } - /* Initialize work items. */ + /* Initialize work items. */ if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: init work fail!", __func__); return HDF_FAILURE; } - /* Parse the HCS. */ + /* Parse the HCS. */ if (GetLightConfigData(device->property) != HDF_SUCCESS) { - HDF_LOGE("%s: get light config fail!", __func__); return HDF_FAILURE; } - /* Set the GPIO pin direction. */ + /* Set the GPIO pin direction. */ if (SetLightGpioDir(drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: set light gpio dir fail!", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } - + ``` + + - Implement **Release()** of the light driver. When the driver is unloaded or **Init** fails to be executed, **Release()** can be used to release resources. The implementation is as follows: + + ```c /* Release the resources allocated for driver initialization. */ void ReleaseLightDriver(struct HdfDeviceObject *device) - { - ..... + { + int32_t i; + struct LightDriverData *drvData = NULL; /* Release the allocated resources. */ - for (i = LIGHT_TYPE_NONE; i < LIGHT_TYPE_BUTT; ++i) { - + for (i = LIGHT_ID_NONE; i < LIGHT_ID_BUTT; ++i) { if (drvData->info[i] != NULL) { OsalMemFree(drvData->info[i]); drvData->info[i] = NULL; } } - /* Destroy workqueue resources. */ + /* Destroy the work queue resource if the sensor is in position. */ HdfWorkDestroy(&drvData->work); HdfWorkQueueDestroy(&drvData->workQueue); (void)OsalMutexDestroy(&drvData->mutex); @@ -159,277 +204,699 @@ The light driver model provides APIs for obtaining information about all the lig } ``` - - The light device management module is responsible for publishing light device APIs in the system. During the system startup process, the HDF loads the device management driver based on **Light Host** in the HCS. + - The light driver parses the light device management configuration information from the HCS file. ```c - /* HCS of the light device. */ - light :: host { - hostName = "light_host"; - device_light :: device { - device0 :: deviceNode { - policy = 2; // Policy for the driver to publish services. If the value is 0, the driver does not publish services. If the value is 1, the driver publishes services to the kernel space. If the value is 2, the driver publishes services to both the kernel space and user space. - priority = 100; // Priority (0–200) for starting the light driver. A larger value indicates a lower priority. The recommended value is 100. If the priorities are the same, the device loading sequence is not ensured. - preload = 0; // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite. - permission = 0664; // Permission for the device node created. - moduleName = "HDF_LIGHT"; // Light driver name. The value must be the same as the value of moduleName in the driver entry structure. - serviceName = "hdf_light"; // Service published by the light driver. The service name must be unique. - deviceMatchAttr = "hdf_light_driver"; // Keyword for matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver. + /* Obtain the Light basic configuration from the HCS file. */ + static int32_t GetLightBaseConfigData(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser, + uint32_t lightId) + { + int32_t ret; + uint32_t *defaultBrightness = NULL; + struct LightDriverData *drvData = NULL; + const char *name = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + /* Types are used as subscripts to create space. */ + drvData->info[lightId] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: malloc fail", __func__); + return HDF_FAILURE; + } + /* Fill in the light device information. */ + ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[lightId]->busRNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busRNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[lightId]->busGNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busGNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[lightId]->busBNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busBNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetString(node, "lightName", &name, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s:get lightName failed!", __func__); + return HDF_FAILURE; + } + + if (strcpy_s(drvData->info[lightId]->lightInfo.lightName, NAME_MAX_LEN, name) != EOK) { + HDF_LOGE("%s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + ret = parser->GetUint32(node, "lightNumber", (uint32_t *)&drvData->info[lightId]->lightInfo.lightNumber, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s:get lightNumber failed!", __func__); + return HDF_FAILURE; + } + + defaultBrightness = (uint32_t *)&drvData->info[lightId]->defaultBrightness; + ret = parser->GetUint32(node, "defaultBrightness", defaultBrightness, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "defaultBrightness"); + ret = parser->GetUint32(node, "onTime", &drvData->info[lightId]->onTime, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "onTime"); + ret = parser->GetUint32(node, "offTime", &drvData->info[lightId]->offTime, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "offTime"); + + drvData->info[lightId]->lightBrightness = 0; + drvData->info[lightId]->lightState = LIGHT_STATE_STOP; + + return HDF_SUCCESS; + } + ``` + + - Allocate resources and parse the HCS configuration information as follows: + + ```c + /* Allocate resources and parse the HCS. */ + static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser) + { + int32_t ret; + uint32_t i; + uint32_t temp; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + /* Obtain the number of supported light types from the HCS. */ + drvData->lightNum = (uint32_t)parser->GetElemNum(node, "lightId"); + if (drvData->lightNum > LIGHT_ID_NUM) { + HDF_LOGE("%s: lightNum cross the border", __func__); + return HDF_FAILURE; + } + + ret = memset_s(drvData->info, sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT, 0, + sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "memset_s"); + + for (i = 0; i < drvData->lightNum; ++i) { + /* Obtain the light type. */ + ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId"); + + if (temp >= LIGHT_ID_BUTT) { + HDF_LOGE("%s: light id invalid para", __func__); + return HDF_FAILURE; + } + + ret = GetLightBaseConfigData(node, parser, temp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: get light base config fail", __func__); + return HDF_FAILURE; } } + + return HDF_SUCCESS; } ``` -2. Parse the device attribute information and registers, and register them with the light device management module. - - ```c - /* Allocate resources and parse the HCS. */ - static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser) - { - ..... - /* Obtain the number of supported light types from the HCS. */ - drvData->lightNum = parser->GetElemNum(light, "lightId"); - .... - for (i = 0; i < drvData->lightNum; ++i) { - /* Obtain the light type. */ - ret = parser->GetUint32ArrayElem(light, "lightId", i, &temp, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId"); - } - - for (i = 0; i < drvData->lightNum; ++i) { - ..... - /* Types are used as subscripts to create space. */ - drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); - ..... - /* Fill in the light device information. */ - ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[temp]->busRNum, 0); - if (ret != HDF_SUCCESS) { - /* If busNum fails to be obtained, the color of the light corresponding to busNum cannot be set. */ - drvData->info[temp]->busRNum = LIGHT_INVALID_GPIO; - } - ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[temp]->busGNum, 0); - if (ret != HDF_SUCCESS) { - drvData->info[temp]->busGNum = LIGHT_INVALID_GPIO; + - Use the internal APIs of the light driver to obtain the light type information, set the blinking mode, turn on and trun off lights, and create and destroy timers based on the blinking mode. + + - The **GetAllLightInfo** interface is implemented as follows: + + ```c + /* The light driver service calls GetAllLightInfo() to obtain the light type information. */ + static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)data; + uint32_t i; + struct LightInfo lightInfo; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); + + if (!HdfSbufWriteUint32(reply, drvData->lightNum)) { + HDF_LOGE("%s: write sbuf failed", __func__); + return HDF_FAILURE; } - ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[temp]->busBNum, 0); - if (ret != HDF_SUCCESS) { - drvData->info[temp]->busBNum = LIGHT_INVALID_GPIO; + + for (i = 0; i < LIGHT_ID_BUTT; ++i) { + if (drvData->info[i] == NULL) { + continue; + } + lightInfo.lightId = i; + + if (!HdfSbufWriteUint32(reply, lightInfo.lightId)) { + HDF_LOGE("%s: write lightId failed", __func__); + return HDF_FAILURE; + } + + if (strcpy_s(lightInfo.lightName, NAME_MAX_LEN, drvData->info[i]->lightInfo.lightName) != EOK) { + HDF_LOGE("%s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufWriteString(reply, (const char *)lightInfo.lightName)) { + HDF_LOGE("%s: write lightName failed", __func__); + return HDF_FAILURE; + } + + lightInfo.lightNumber = drvData->info[i]->lightInfo.lightNumber; + if (!HdfSbufWriteUint32(reply, lightInfo.lightNumber)) { + HDF_LOGE("%s: write lightNumber failed", __func__); + return HDF_FAILURE; + } + + lightInfo.lightType = HDF_LIGHT_TYPE_RGB_COLOR; + if (!HdfSbufWriteUint32(reply, lightInfo.lightType)) { + HDF_LOGE("%s: write lightType failed", __func__); + return HDF_FAILURE; + } } + + return HDF_SUCCESS; } - ..... - return HDF_SUCCESS; - } - ``` - -3. Implement the APIs for obtaining the light type, setting the blinking mode, turning on and off lights, and creating and destroying a timer based on the blinking mode. - - ```c - /* Call GetAllLightInfo() to obtain the light types, call TurnOnLight() to turn on lights, - and call TurnOffLight() to turn off lights. */ - static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - /* Obtain the number of light types. */ - if (!HdfSbufWriteUint32(reply, drvData->lightNum)) { - HDF_LOGE("%s: write sbuf fail", __func__); - return HDF_FAILURE; - } - for (i = 0; i < LIGHT_TYPE_BUTT; ++i) { - if (drvData->info[i] == NULL) { - continue; - } - lightInfo.lightId = i; - lightInfo.reserved = NULL; - /* Fill the light device information into the reply. */ - if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) { - HDF_LOGE("%s: write sbuf fail", __func__); + ``` + + - The **TurnOnLight** interface is implemented as follows: + + ```c + /* Enable lights based on the specified light type and input parameters. */ + static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)reply; + uint32_t len; + struct LightEffect *buf = NULL; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: light id info is null", __func__); return HDF_FAILURE; } - } - - return HDF_SUCCESS; - } - - /* Update the status of the lights of the specified type. */ - static int32_t UpdateLight(uint32_t lightId, uint32_t lightOn) - { - ..... - /* If the lightBrightness value passed in is invalid, use the default value. */ - if (drvData->info[lightId]->lightBrightness == 0) { - lightBrightness = drvData->info[lightId]->defaultBrightness; - } else { - lightBrightness = drvData->info[lightId]->lightBrightness; - } - /* If bits 0 to 7 are not 0, output the GPIO pins corresponding to blue based on the status of lightOn. */ - if ((lightBrightness & LIGHT_MAKE_B_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busBNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write blue gpio fail", __func__); + + if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) { + HDF_LOGE("%s: light read data failed", __func__); return HDF_FAILURE; } - } - /* If bits 8 to 15 are not 0, output the GPIO pins corresponding to green based on the status of lightOn. */ - if ((lightBrightness & LIGHT_MAKE_G_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busGNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write green gpio fail", __func__); - return HDF_FAILURE; + /* Receive the lightBrightness value passed in. Bits 24 to 31 indicate extension bits, bits 16 to 23 indicate red, bits 8 to 15 indicate green, and bits 0 to 7 indicate blue. If lightBrightness is not 0, enable the light in the specified color. + Set the light brightness to a value ranging from 0 to 255 if supported. */ + if (buf->lightColor.colorValue.rgbColor.r != 0) { + drvData->info[lightId]->lightBrightness |= 0X00FF0000; } - } - /* If bits 16 to 23 are not 0, output the GPIO pins corresponding to red based on the status of lightOn. */ - if ((lightBrightness & LIGHT_MAKE_R_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busRNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write red gpio fail", __func__); - return HDF_FAILURE; + + if (buf->lightColor.colorValue.rgbColor.g != 0) { + drvData->info[lightId]->lightBrightness |= 0X0000FF00; } + + if (buf->lightColor.colorValue.rgbColor.b != 0) { + drvData->info[lightId]->lightBrightness |= 0X000000FF; + } + /* The light is steady on. */ + if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { + return UpdateLight(lightId, LIGHT_STATE_START); + } + /* The light is blinking. */ + if (buf->flashEffect.flashMode == LIGHT_FLASH_BLINK) { + drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ? + drvData->info[lightId]->onTime : buf->flashEffect.onTime; + drvData->info[lightId]->offTime = (buf->flashEffect.offTime < drvData->info[lightId]->offTime) ? + drvData->info[lightId]->offTime : buf->flashEffect.offTime; + /* Create a timer. */ + if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) { + HDF_LOGE("%s: create light timer fail!", __func__); + return HDF_FAILURE; + } + /* Start the timer. */ + if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { + HDF_LOGE("%s: start light timer fail!", __func__); + return HDF_FAILURE; + } + } + + return HDF_SUCCESS; } - ..... - } - - /* Enable lights based on the specified light type and input parameters. */ - static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - /* Receive the lightBrightness value passed in. Bits 24 to 31 are extension bits, bits 16 to 23 indicate red, bits 8 to 15 indicate green, and bits 0 to 7 indicate blue. If lightBrightness is not 0, turn on the light in the specified color. - Set the light brightness to a value ranging from 0 to 255 if supported. */ - drvData->info[lightId]->lightBrightness = buf->lightBrightness; - /* The light is steady on. */ - if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { - return UpdateLight(lightId, LIGHT_STATE_START); - } - /* The light is blinking. */ - if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) { - drvData->info[lightId]->lightState = LIGHT_STATE_START; - /* If the specified blinking duration is less than the minimum time period supported by the system, the time configured by the system (in HCS) is used. */ - drvData->info[lightId]->onTime = buf->flashEffect.onTime < drvData->info[lightId]->onTime ? - drvData->info[lightId]->onTime : buf->flashEffect.onTime; - drvData->info[lightId]->offTime = buf->flashEffect.offTime < drvData->info[lightId]->offTime ? - drvData->info[lightId]->offTime : buf->flashEffect.offTime; - /* Create a timer. */ - if (OsalTimerCreate(&drvData->timer, drvData->info[lightId]->onTime, - LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) { - HDF_LOGE("%s: create light timer fail!", __func__); + ``` + + - The **TurnOffLight** interface is implemented as follows: + + ```c + /* Turn off lights based on the specified light type. */ + static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)data; + (void)reply; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: light id info is null", __func__); return HDF_FAILURE; } - /* Start the periodic timer. */ - if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { - HDF_LOGE("%s: start light timer fail!", __func__); + + if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) { + HDF_LOGE("%s: gpio write failed", __func__); return HDF_FAILURE; } - } - return HDF_SUCCESS; - } - - /* Turn off lights based on the specified light type. */ - static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) - { - /* Delete the timer. */ - if (drvData->timer.realTimer != NULL) { - - if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { - HDF_LOGE("%s: delete haptic timer fail!", __func__); + + drvData->info[lightId]->lightState = LIGHT_STATE_STOP; + drvData->info[lightId]->lightBrightness = 0; + /* Destroy the timer. */ + if (drvData->timer.realTimer != NULL) { + if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { + HDF_LOGE("%s: delete light timer fail!", __func__); + return HDF_FAILURE; + } } + + return HDF_SUCCESS; } - if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) { - HDF_LOGE("%s: gpio write fail", __func__); - return HDF_FAILURE; - } - - return HDF_SUCCESS; - } - ``` + ``` + +5. Implement the HDIs of the light controller. + + - Code path: **drivers\peripheral\light\hal\src\light_controller.c**. + + - The **GetLightInfo** interface is implemented as follows: + + ```c + /* Read the light type information from HdfSBuf in the light abstract driver to LightInfo. */ + static int32_t ReadLightInfo(struct HdfSBuf *reply, struct LightDevice *priv) + { + struct LightInfo *pos = NULL; + const char *name = NULL; + + if (!HdfSbufReadUint32(reply, &priv->lightNum)) { + HDF_LOGE("%s: sbuf read lightNum failed", __func__); + return HDF_FAILURE; + } + + if (priv->lightInfoEntry != NULL) { + OsalMemFree(priv->lightInfoEntry); + priv->lightInfoEntry = NULL; + } + + priv->lightInfoEntry = (struct LightInfo *)OsalMemCalloc(sizeof(*priv->lightInfoEntry) * priv->lightNum); + if (priv->lightInfoEntry == NULL) { + HDF_LOGE("%s: malloc fail", __func__); + return HDF_FAILURE; + } + + pos = priv->lightInfoEntry; + + for (uint32_t i = 0; i < priv->lightNum; ++i) { + if (!HdfSbufReadUint32(reply, &pos->lightId)) { + HDF_LOGE("%{public}s:read lightId failed!", __func__); + return HDF_FAILURE; + } + + name = HdfSbufReadString(reply); + if (strcpy_s(pos->lightName, NAME_MAX_LEN, name) != EOK) { + HDF_LOGE("%{public}s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadUint32(reply, &pos->lightNumber)) { + HDF_LOGE("%{public}s:read lightNumber failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadInt32(reply, &pos->lightType)) { + HDF_LOGE("%{public}s:read lightType failed!", __func__); + return HDF_FAILURE; + } + pos++; + } + + return HDF_SUCCESS; + } + /* GetLightInfo interface implementation. */ + static int32_t GetLightInfo(struct LightInfo **lightInfo, uint32_t *count) + { + if ((lightInfo == NULL) || (count == NULL)) { + HDF_LOGE("%s:line:%{public}d pointer is null and return ret", __func__, __LINE__); + return HDF_FAILURE; + } + + struct LightDevice *priv = GetLightDevicePriv(); + + if (priv->lightNum > 0) { + *count = priv->lightNum; + *lightInfo = priv->lightInfoEntry; + return HDF_SUCCESS; + } + + (void)OsalMutexLock(&priv->mutex); + struct HdfSBuf *reply = HdfSbufObtainDefaultSize(); + if (reply == NULL) { + HDF_LOGE("%s: get sbuf failed", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + int32_t ret = SendLightMsg(LIGHT_IO_CMD_GET_INFO_LIST, NULL, reply); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light send cmd failed, ret[%{public}d]", __func__, ret); + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + return ret; + } + + if (ReadLightInfo(reply, priv) != HDF_SUCCESS) { + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + + *count = priv->lightNum; + *lightInfo = priv->lightInfoEntry; + + return HDF_SUCCESS; + } + ``` + + - The **OnLight** interface is implemented as follows: + + ```c + static int32_t OnLight(uint32_t lightId, struct LightEffect *effect) + { + int32_t ret; + + if (effect == NULL) { + HDF_LOGE("%{public}s: effect is NULL", __func__); + return HDF_FAILURE; + } + + ret = OnLightValidityJudgment(lightId, effect); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: effect is false", __func__); + return ret; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + + struct HdfSBuf *msg = HdfSbufObtainDefaultSize(); + if (msg == NULL) { + HDF_LOGE("%{public}s: Failed to obtain sBuf size", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, lightId)) { + HDF_LOGE("%{public}s: Light write id failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_ENABLE)) { + HDF_LOGE("%{public}s: Light write enable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteBuffer(msg, effect, sizeof(*effect))) { + HDF_LOGE("%{public}s: Light write enable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light enable failed, ret[%{public}d]", __func__, ret); + } + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + + if (memcpy_s(&g_lightEffect, sizeof(g_lightEffect), effect, sizeof(*effect)) != EOK) { + HDF_LOGE("%{public}s: Light effect cpy faild", __func__); + return HDF_FAILURE; + } + + g_lightState[lightId] = LIGHT_ON; + + return ret; + } + ``` + + - The **OffLight** interface is implemented as follows: + + ```c + static int32_t OffLight(uint32_t lightId) + { + if (lightId >= LIGHT_ID_BUTT) { + HDF_LOGE("%{public}s: id not supported", __func__); + return HDF_FAILURE; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + + struct HdfSBuf *msg = HdfSbufObtainDefaultSize(); + if (msg == NULL) { + HDF_LOGE("%{public}s: Failed to obtain sBuf", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, lightId)) { + HDF_LOGE("%{public}s: Light write id failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_DISABLE)) { + HDF_LOGE("%{public}s: Light write disable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + int32_t ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light disable failed, ret[%{public}d]", __func__, ret); + } + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + + g_lightState[lightId] = LIGHT_OFF; + + return ret; + } + ``` + + - The **OnMultiLights** interface is implemented as follows: + + ```c + static int32_t OnMultiLights(uint32_t lightId, const struct LightColor *colors, const uint32_t count) + { + int32_t ret; + struct HdfSBuf *sbuf = NULL; + + ret = OnMultiLightsValidityJudgment(lightId, colors, count); + if (ret != HDF_SUCCESS) { + return ret; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + sbuf = HdfSbufObtain(sizeof(struct LightColor) * count); + if (sbuf == NULL) { + return HDF_DEV_ERR_NO_MEMORY; + } + + if (!HdfSbufWriteInt32(sbuf, lightId)) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteInt32(sbuf, LIGHT_OPS_IO_CMD_ENABLE_MULTI_LIGHTS)) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteBuffer(sbuf, colors, sizeof(*colors))) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteInt32(sbuf, count)) { + ret = HDF_FAILURE; + goto EXIT; + } + + ret = SendLightMsg(LIGHT_IO_CMD_OPS, sbuf, NULL); + if (ret != HDF_SUCCESS) { + } + return ret; + + EXIT: + HdfSbufRecycle(sbuf); + (void)OsalMutexUnlock(&priv->mutex); + } + ``` ### Verification After the driver is developed, develop auto-test cases in the light unit test to verify the basic functionalities of the driver. Use the developer self-test platform as the test environment. -```c++ -/* Initialize the LightInterfaceInstance before executing the test case. */ -void HdfLightTest::SetUpTestCase() -{ - g_lightDev = NewLightInterfaceInstance(); - if (g_lightDev == nullptr) { - printf("test light get Module instance fail\n\r"); - } - int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count); - if (ret == -1) { - printf("get light informations fail\n\r"); - } -} - -/* After the test case is executed, release the resources used by the test case. */ -void HdfLightTest::TearDownTestCase() -{ - if(g_lightDev != nullptr){ - FreeLightInterfaceInstance(); - g_lightDev = nullptr; - } -} - -/* Obtain the test light type. */ -HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) -{ - struct LightInfo *info = nullptr; - - if (g_lightInfo == nullptr) { - EXPECT_NE(nullptr, g_lightInfo); - return; - } - - printf("get light list num[%d]\n\r", g_count); - info = g_lightInfo; - - for (int i = 0; i < g_count; ++i) { - printf("get lightId[%d]\n\r", info->lightId); - EXPECT_GE(info->lightId, g_minLightId); - EXPECT_LE(info->lightId, g_maxLightId); - info++; - } -} - -/* Verify the steady on state of the light. */ -HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) -{ - int32_t i; - int32_t ret; - struct LightEffect effect; - effect->lightBrightness = 0x00800000; - effect->flashEffect.flashMode = LIGHT_FLASH_NONE; - effect->flashEffect.onTime = 0; - effect->flashEffect.offTime = 0; - - for (i = 0; i < g_count; ++i) { - - ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); - EXPECT_EQ(0, ret); - - OsalSleep(LIGHT_WAIT_TIME); - - ret = g_lightDev->TurnOffLight(type); - EXPECT_EQ(0, ret); - } -} - -/* Verify the blinking mode of the light. */ -HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1) -{ - int32_t i; - int32_t ret; - struct LightEffect effect; - effect->lightBrightness = 0x00800000; - effect->flashEffect.flashMode = LIGHT_FLASH_TIMED; - effect->flashEffect.onTime = g_onTime; - effect->flashEffect.offTime = g_offTime; - - for (i = 0; i < g_count; ++i) { - - ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); - EXPECT_EQ(0, ret); - - OsalSleep(LIGHT_WAIT_TIME); - - ret = g_lightDev->TurnOffLight(type); - EXPECT_EQ(0, ret); - } -} -``` +- The reference test code is as follows: + + ```c + #include + #include + #include + #include + #include "hdf_base.h" + #include "osal_time.h" + #include "osal_mem.h" + #include "light_if.h" + #include "light_type.h" + + using namespace testing::ext; + const struct LightInterface *g_lightDev = nullptr; + static struct LightInfo *g_lightInfo = nullptr; + static uint32_t g_count = 0; + /* Initialize the LightInterfaceInstance before executing the test case. */ + class HdfLightTest : public testing::Test { + public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + }; + + void HdfLightTest::SetUpTestCase() + { + g_lightDev = NewLightInterfaceInstance(); + if (g_lightDev == nullptr) { + printf("test light get Module instance fail\n\r"); + } + int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count); + if (ret == -1) { + printf("get light informations fail\n\r"); + } + } + + /* After the test case is executed, release the resources used by the test case. */ + void HdfLightTest::TearDownTestCase() + { + if(g_lightDev != nullptr){ + FreeLightInterfaceInstance(); + g_lightDev = nullptr; + } + } + + void HdfLightTest::SetUp() + { + } + + void HdfLightTest::TearDown() + { + } + + /* Obtain the test light type. */ + HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) + { + struct LightInfo *info = nullptr; + + if (g_lightInfo == nullptr) { + EXPECT_NE(nullptr, g_lightInfo); + return; + } + + printf("get light list num[%u]\n\r", g_count); + info = g_lightInfo; + + for (uint32_t i = 0; i < g_count; ++i) { + printf("get lightId[%u]\n\r", info->lightId); + EXPECT_GE(info->lightId, 0); + EXPECT_LE(info->lightId, 4); + info++; + } + } + + /* Verify the steady on state of the light. */ + HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) + { + uint32_t i; + struct LightEffect effect; + effect.flashEffect.flashMode = 0; + effect.flashEffect.onTime = 0; + effect.flashEffect.offTime = 0; + + for (i = 0; i < g_count; ++i) { + effect.lightColor.colorValue.rgbColor.r = 255; + effect.lightColor.colorValue.rgbColor.g = 0; + effect.lightColor.colorValue.rgbColor.b = 0; + int32_t ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect); + EXPECT_EQ(0, ret); + + OsalSleep(2); + + ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId); + EXPECT_EQ(0, ret); + + effect.lightColor.colorValue.rgbColor.r = 0; + effect.lightColor.colorValue.rgbColor.g = 255; + effect.lightColor.colorValue.rgbColor.b = 0; + ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect); + EXPECT_EQ(0, ret); + + OsalSleep(2); + + ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId); + EXPECT_EQ(0, ret); + } + } + ``` + +- The reference code of the **BUILD.gn** file is as follows: + + ```c + import("//build/test.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + module_output_path = "drivers_peripheral_light/light" + ohos_unittest("light_test") { + module_out_path = module_output_path + sources = [ "light_test.cpp" ] + include_dirs = [ + "//drivers/peripheral/light/interfaces/include", + ] + deps = [ "//drivers/peripheral/light/hal:hdi_light" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-format", + "-Wno-format-extra-args", + ] + + install_enable = true + install_images = [ "vendor" ] + module_install_dir = "bin" + part_name = "unionman_products" + } + ``` diff --git a/en/device-dev/driver/driver-peripherals-motion-des.md b/en/device-dev/driver/driver-peripherals-motion-des.md index eb147972aff5358f8e503e7375a094ea56323840..343b2935e47b0c898d724086a6c2e223b366d0bb 100644 --- a/en/device-dev/driver/driver-peripherals-motion-des.md +++ b/en/device-dev/driver/driver-peripherals-motion-des.md @@ -23,7 +23,7 @@ The figure below illustrates how a motion driver works. ![](figures/motion_driver_work.png) 1. MSDP: The MSDP service obtains a Motion HDI service instance from the Motion Proxy and calls the Motion HDI API. -2. IDL: The IService Manager allocates a Motion HDI instance requested by the MSDP service, and the Motion Proxy forwards the instance to the MSDP service. After the MSDP service calls the HDI API provided by the Motion Proxy, Motion Stub is called through Inter-Process Communication (IPC) to invoke the Motion Service API. The code is automatically generated by a tool and does not need to be developed by the component vendor. +2. IDL: The MSDP service obtains a Motion HDI service instance from the Motion Proxy and calls the Motion HDI API. The interface instance is allocated by IService Manager. After the MSDP service calls the HDI API provided by the Motion Proxy, Motion Stub is called through Inter-Process Communication (IPC) to invoke the Motion Service API. The code is automatically generated by a tool and does not need to be developed by the component vendor. 3. HDI Service: The HDI service consists of Motion Interface Driver, Motion Service, and Motion Impl. Motion Interface Driver provides the motion driver code. A **HdfDriverEntry** structure is defined to implement the **Init**, **Bind**, and **Release** functions. The **HDF_INIT** macro is used to load the driver in the functions. Motion Service provides the motion recognition service interface class. The specific implementation is described in Motion Impl. The code of HDI Service must be developed by the component vendor. ## Development Guidelines @@ -36,6 +36,8 @@ The motion driver provides capabilities for the MSDP service to enable or disabl **Table 1** Available APIs +**NOTE**
The following table lists the C++ function interfaces generated by the IDL interface description. For details about the interface declaration, see the IDL file [/drivers/interface/motion/v1_0/](https://gitee.com/openharmony/drivers_interface/tree/master/motion). + | API | Description | | ------------------------------------------------------------ | ---------------------------- | | int32_t EnableMotion(int32_t motionType) | Enables motion recognition of the specified type. The motion recognition data can be obtained only after the motion recognition is enabled.| @@ -48,29 +50,30 @@ The motion driver provides capabilities for the MSDP service to enable or disabl The development procedure is as follows: 1. Develop the user-mode driver for motion recognition based on the HDF. + 2. Implement the **EnableMotion**, **DisableMotion**, **Register**, and **Unregister** APIs. The motion recognition directory structure is as follows: -```undefined -/drivers/peripheral/motion # Developed by the vendor. -├── hdi_service # Driver capabilities provided by the motion recognition module for the MSDP service layer. -├── test # Test code for the motion recognition module. -│ └── unittest\hdi # HDI unit test code for the motion recognition module. +``` +/drivers/peripheral/motion // Developed by the vendor. +├── hdi_service // Driver capability provided by the motion module for upper-layer services. +├── test // Test codes for the motion module. + │ └── unittest\hdi // HDI unit test code of the motion driver module. ``` -The following describes how to develop a user-mode motion driver based on the HDF. For details, see [motion_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_interface_driver.cpp). +The following describes how to develop a user-mode motion driver based on the HDF. For details, see [motion_if_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_if_driver.cpp). You need to implement the **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions. The **Bind()** function binds the service capability with the driver; **Init()** implements the initialization required before the driver is loaded; **Release()** reclaims resources when **Init()** fails; **Dispatch()** implements the service, which is bound in **Bind()**. -```c++ -// Custom HdfMotionInterfaceHost object +```c +/* Custom HdfMotionInterfaceHost object. */ struct HdfMotionInterfaceHost { struct IDeviceIoService ioService; OHOS::sptr stub; }; -// Enable the IPC service to call the response API. +/* Enable the IPC service to call the response API. */ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) { @@ -92,14 +95,14 @@ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, i return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); } -// Initialize the HdfMotionInterface driver. +/* Initialize the HdfMotionInterface driver. */ int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverInit enter"); return HDF_SUCCESS; } -// Bind the services provided by the motion driver to the HDF. +/* Bind the services provided by the motion driver to the HDF. */ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverBind enter"); @@ -131,7 +134,7 @@ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) return HDF_SUCCESS; } -// Release the resources used by the motion driver. +/* Release the resources used by the motion driver. */ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverRelease enter"); @@ -140,7 +143,7 @@ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) hdfMotionInterfaceHost = nullptr; } -// Register the HDF driver entry g_motioninterfaceDriverEntry. +/* Register the HDF driver entry g_motioninterfaceDriverEntry. */ struct HdfDriverEntry g_motioninterfaceDriverEntry = { .moduleVersion = 1, .moduleName = "motion_service", @@ -149,7 +152,7 @@ struct HdfDriverEntry g_motioninterfaceDriverEntry = { .Release = HdfMotionInterfaceDriverRelease, }; -// Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind function and then the Init function. If the Init function fails to be called, the HDF will call Release to release driver resources and exit the driver model. +/* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind function and then the Init function. If the Init function fails to be called, the HDF will call Release to release driver resources and exit the driver model. */ HDF_INIT(g_userAuthInterfaceDriverEntry); ``` diff --git a/en/device-dev/driver/driver-peripherals-sensor-des.md b/en/device-dev/driver/driver-peripherals-sensor-des.md index 2f04c658f03f217fe292dc885cbf06c3a6b50597..da1ec4787dfb5db0a94d09384e27581aecff3aeb 100644 --- a/en/device-dev/driver/driver-peripherals-sensor-des.md +++ b/en/device-dev/driver/driver-peripherals-sensor-des.md @@ -13,7 +13,7 @@ The sensor driver model shields the hardware difference and provides interfaces ### Basic Concepts -Sensors are classified into the following types by sensor ID: +Currently, sensors are classified into the following types by sensor ID: - Medical sensors: The sensor IDs range from 128 to 160. @@ -27,7 +27,7 @@ The following figure shows how a sensor driver works. ![How sensor driver works](figures/sensor_working.png) -The following uses the acceleration sensor driver on the Hi3516D V300 development board of the standard system as an example to describe the driver loading and running process. +The following uses the acceleration sensor driver on the RK3568 development board of the standard system as an example to describe the driver loading and running process. 1. The sensor host reads the sensor device management configuration from **Sensor Host** in the **device_info.hcs** file. 2. The sensor host parses the sensor management configuration from the HCB database and associates the configuration with the sensor driver. @@ -44,7 +44,7 @@ The following uses the acceleration sensor driver on the Hi3516D V300 developmen ### When to Use -- Data provided by the gravity and gyroscope sensors denotes the tilt and rotation of the device, which helps your application improve user experience in games. +- Data provided by the gravity and gyroscope sensors denotes the tilt and rotation of the device, which helps improve user experience in games. - Data provided by the proximity sensor denotes the distance between the device and a visible object, which enables the device to automatically turn on or off its screen accordingly to prevent accidental touch on the screen. For example, when the proximity sensor detects the user face approaches the earpiece during a call, it triggers backlight of the screen to be turned off. This prevents the screen from being accidentally touched and further reduces power consumption. - Data provided by the barometric pressure sensor helps your application accurately determine the altitude of the device. - Data provided by the ambient light sensor helps your device automatically adjust its backlight. @@ -55,19 +55,17 @@ The following uses the acceleration sensor driver on the Hi3516D V300 developmen The sensor driver model offers the following APIs: - Sensor HDI APIs, for easier sensor service development - - APIs for implementing sensor driver model capabilities - - APIs for loading, registering, and deregitering sensor drivers, and detecting sensors based on the HDF + - APIs for loading, registering, and deregistering sensor drivers, and detecting sensors based on the HDF. - Unified driver API, register configuration parsing API, bus access abstract API, and platform abstract API for the same type of sensors - -- APIs to be implemented by developers - - Based on the HDF Configuration Source (HCS) and differentiated configuration for sensors of the same type, you need to implement serialized configuration of sensor device parameters and some sensor device operation interfaces to simplify sensor driver development. +- APIs to be implemented by developers: Based on the HDF Configuration Source (HCS) and differentiated configuration for sensors of the same type, developers need to implement serialized configuration of sensor device parameters and some sensor device operation interfaces to simplify sensor driver development. The sensor driver model provides APIs for the hardware service to make sensor service development easier. See the table below. **Table 1** APIs of the sensor driver model +**NOTE**
The following APIs are C interfaces. For details about the interface declaration, see [/drivers/peripheral/sensor/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/sensor/interfaces/include). + | API| Description| | ----- | -------- | | int32_t GetAllSensors(struct SensorInformation **sensorInfo, int32_t *count) | Obtains information about all registered sensors in the system. The sensor information includes the sensor name, sensor vendor, firmware version, hardware version, sensor type ID, sensor ID, maximum range, accuracy, and power consumption.| @@ -79,8 +77,6 @@ The sensor driver model provides APIs for the hardware service to make sensor se | int32_t Register(int32_t groupId, RecordDataCallback cb) | Registers a sensor data callback based on the group ID.| | int32_t Unregister(int32_t groupId, RecordDataCallback cb) | Deregisters a sensor data callback based on the group ID.| - - The sensor driver model provides driver development APIs that do not require further implementation. See the table below. **Table 2** Sensor driver development APIs @@ -99,8 +95,6 @@ The sensor driver model provides driver development APIs that do not require fur | int32_t GetSensorBusHandle(struct SensorBusCfg *busCfg) | Obtains the sensor bus handle information.| | int32_t ReleaseSensorBusHandle(struct SensorBusCfg *busCfg) | Releases the sensor bus handle information.| - - The sensor driver model also provides certain driver development APIs that need to be implemented by driver developers. See the table below. **Table 3** APIs to be implemented by driver developers @@ -113,483 +107,777 @@ The sensor driver model also provides certain driver development APIs that need | int32_t SetBatch(int64_t samplingInterval, int64_t reportInterval) | Sets the processing time of the data reporting thread for the current sensor based on the sampling interval and data reporting interval.| | int32_t SetMode(int32_t mode) | Sets the data reporting mode of the current sensor device.| | int32_t SetOption(uint32_t option) | Sets the register configuration such as the range and accuracy based on sensor options.| -| void ReadSensorData(void) | Reads sensor data.| +| void ReadSensorData(void) | Reads sensor data. | + +For details about the interface implementation, see [How to Develop](#how-to-develop). ### How to Develop -1. Develop the acceleration sensor abstract driver. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions. +The following describes how to develop an acceleration sensor driver based on the HDF and the driver entry. Sensor driver development includes abstracted driver development and differentiated driver development. The abstracted driver development implements the common interfaces for different devices with the same sensor ID. The differentiated driver development implements device-specific interfaces. - - Implement the entry function for the acceleration sensor. +1. Develop the abstracted driver of the acceleration sensor. - ```c - /* Register the entry structure object of the acceleration sensor. */ - struct HdfDriverEntry g_sensorAccelDevEntry = { - .moduleVersion = 1, // Version of the acceleration sensor module. - .moduleName = "HDF_SENSOR_ACCEL", // Name of the acceleration sensor module. The value must be the same as that of moduleName in the device_info.hcs file. - .Bind = BindAccelDriver, // Function for binding an acceleration sensor. - .Init = InitAccelDriver, // Function for initializing an acceleration sensor. - .Release = ReleaseAccelDriver // Function for releasing acceleration sensor resources. - }; - - /* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init() to load the driver. If Init() fails to be called, the HDF calls Release() to release resources and exit. */ - HDF_INIT(g_sensorAccelDevEntry); - ``` + - Configure the host information for the abstracted driver of the acceleration sensor in **vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs**. - - Implement interfaces for acceleration sensor driver operations. + The code is as follows: ```c - /* Bind the service provided by the acceleration sensor driver to the HDF. */ - int32_t AccelBindDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - - struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData)); - if (drvData == NULL) { - HDF_LOGE("%s: Malloc accel drv data fail!", __func__); - return HDF_ERR_MALLOC_FAIL; - } - - drvData->ioService.Dispatch = DispatchAccel; - drvData->device = device; - device->service = &drvData->ioService; - g_accelDrvData = drvData; - return HDF_SUCCESS; - } - - /* Register the normalization functions of the acceleration sensor driver. */ - static int32_t InitAccelOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo) - { - CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); - - deviceInfo->ops.Enable = SetAccelEnable; - deviceInfo->ops.Disable = SetAccelDisable; - deviceInfo->ops.SetBatch = SetAccelBatch; - deviceInfo->ops.SetMode = SetAccelMode; - deviceInfo->ops.SetOption = SetAccelOption; - - if (memcpy_s(&deviceInfo->sensorInfo, sizeof(deviceInfo->sensorInfo), - &config->sensorInfo, sizeof(config->sensorInfo)) != EOK) { - HDF_LOGE("%s: Copy sensor info failed", __func__); - return HDF_FAILURE; + /* Device information HCS configuration of the acceleration sensor. */ + device_sensor_accel :: device { + device0 :: deviceNode { + policy = 1; // Policy for the driver to publish services. + priority = 100; // Priority (0–200) for starting the driver. A larger value indicates a lower priority. The recommended value is 100. If the priorities are the same, the device loading sequence is not ensured. + preload = 0; // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite. + permission = 0664; // Permission for the device node created. + moduleName = "HDF_SENSOR_ACCEL"; // Driver name. It must be the same as moduleName in the driver entry structure. + serviceName = "sensor_accel"; // Name of the service published by the driver. The name must be unique. + deviceMatchAttr = "hdf_sensor_accel_driver"; // Keyword matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver. } - - return HDF_SUCCESS; - } - /* Provide the initialization interface for the chipset driver to parse the basic acceleration sensor configuration (acceleration information, bus configuration, and sensor detection register configuration), detect sensors, and parse sensor registers. */ - static int32_t InitAccelAfterDetected(struct SensorCfgData *config) - { - struct SensorDeviceInfo deviceInfo; - CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); - /* Initialize the acceleration sensor function. */ - if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) { - HDF_LOGE("%s: Init accel ops failed", __func__); - return HDF_FAILURE; - } - /* Register the acceleration sensor with the sensor management module. */ - if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { - HDF_LOGE("%s: Add accel device failed", __func__); - return HDF_FAILURE; - } - /* Parse the sensor register. */ - if (ParseSensorRegConfig(config) != HDF_SUCCESS) { - HDF_LOGE("%s: Parse sensor register failed", __func__); - (void)DeleteSensorDevice(&config->sensorInfo); - ReleaseSensorAllRegConfig(config); - return HDF_FAILURE; + } + ``` + + - Implement the abstracted driver of the acceleration sensor in **drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c**. + + - Define the **HdfDriverEntry** object of the abstracted driver. The driver entry function is defined as follows: + + ```c + struct HdfDriverEntry g_sensorAccelDevEntry = { + .moduleVersion = 1, // Version of the accelerometer sensor module. + .moduleName = "HDF_SENSOR_ACCEL", // Name of the acceleration sensor module. The value must be the same as that of moduleName in the device_info.hcs file. + .Bind = BindAccelDriver, // Function for binding an acceleration sensor. + .Init = InitAccelDriver, // Function for initializing an acceleration sensor. + .Release = ReleaseAccelDriver // Function for releasing acceleration sensor resources. + }; + + /* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init() to load the driver. If Init() fails to be called, the HDF calls Release() to release resources and exit. */ + HDF_INIT(g_sensorAccelDevEntry); + ``` + + - Implement **Bind()** for the abstracted driver of the acceleration sensor. + + ```c + int32_t AccelBindDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + + struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData)); + if (drvData == NULL) { + HDF_LOGE("%s: Malloc accel drv data fail!", __func__); + return HDF_ERR_MALLOC_FAIL; + } + + drvData->ioService.Dispatch = DispatchAccel; + drvData->device = device; + device->service = &drvData->ioService; + g_accelDrvData = drvData; + return HDF_SUCCESS; + } + ``` + + - Implement **Init()** for the abstracted driver of the acceleration sensor. + + ```c + int32_t AccelInitDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + /* Initialize work queue resources. */ + if (InitAccelData(drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: Init accel config failed", __func__); + return HDF_FAILURE; + } + /* Allocate acceleration configuration resources. */ + drvData->accelCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->accelCfg)); + if (drvData->accelCfg == NULL) { + HDF_LOGE("%s: Malloc accel config data failed", __func__); + return HDF_FAILURE; + } + /* Register the register group information. */ + drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0]; + drvData->cb = NULL; + + HDF_LOGI("%s: Init accel driver success", __func__); + return HDF_SUCCESS; + } + ``` + + - Implement **Release()** for the abstracted driver of the acceleration sensor. When the driver is unloaded or **Init()** fails, **Release()** can be used to release resources. + + ```c + void AccelReleaseDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN(device); + + struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; + CHECK_NULL_PTR_RETURN(drvData); + /* Release the resources if the sensor is in position. */ + if (drvData->detectFlag && drvData->accelCfg != NULL) { + AccelReleaseCfgData(drvData->accelCfg); + } + + OsalMemFree(drvData->accelCfg); + drvData->accelCfg = NULL; + /* Destroy the work queue resource if the sensor is in position. */ + HdfWorkDestroy(&drvData->accelWork); + HdfWorkQueueDestroy(&drvData->accelWorkQueue); + OsalMemFree(drvData); + } + ``` + + - Implement the internal interfaces for the abstracted driver of the acceleration sensor. + + - Implement the initialization interface provided for the differentiated driver. This interface parses the basic configuration information (acceleration sensor information, acceleration sensor bus configuration, and acceleration sensor detection register configuration) of the acceleration sensor, detects devices, and parses the device register. The initialization interface is implementation is as follows: + + ```c + static int32_t InitAccelAfterDetected(struct SensorCfgData *config) + { + struct SensorDeviceInfo deviceInfo; + CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); + /* Initialize the acceleration sensor. */ + if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) { + HDF_LOGE("%s: Init accel ops failed", __func__); + return HDF_FAILURE; + } + /* Register the accelerometer device with the sensor device management module. */ + if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { + HDF_LOGE("%s: Add accel device failed", __func__); + return HDF_FAILURE; + } + /* Parse the sensor register. */ + if (ParseSensorDirection(config) != HDF_SUCCESS) { + HDF_LOGE("%s: Parse accel direction failed", __func__); + (void)DeleteSensorDevice(&config->sensorInfo); + return HDF_FAILURE; + } + + if (ParseSensorRegConfig(config) != HDF_SUCCESS) { + HDF_LOGE("%s: Parse sensor register failed", __func__); + (void)DeleteSensorDevice(&config->sensorInfo); + ReleaseSensorAllRegConfig(config); + ReleaseSensorDirectionConfig(config); + return HDF_FAILURE; + } + return HDF_SUCCESS; } - return HDF_SUCCESS; - } - struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node) - { - ... - /* Continue the next detection if the sensor is not detected. */ - if (drvData->detectFlag) { - HDF_LOGE("%s: Accel sensor have detected", __func__); - return NULL; + + struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node) + { + struct AccelDrvData *drvData = AccelGetDrvData(); + /* If the device is not in position, return to detect the next device. */ + if (drvData == NULL || node == NULL) { + HDF_LOGE("%s: Accel node pointer NULL", __func__); + return NULL; + } + + if (drvData->detectFlag) { + HDF_LOGE("%s: Accel sensor have detected", __func__); + return NULL; + } + + if (drvData->accelCfg == NULL) { + HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__); + return NULL; + } + /* Parse the basic sensor configuration. */ + if (GetSensorBaseConfigData(node, drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGE("%s: Get sensor base config failed", __func__); + goto BASE_CONFIG_EXIT; + } + /* If the device is not in position (the device ID exists), return to detect the next device. */ + if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGI("%s: Accel sensor detect device no exist", __func__); + drvData->detectFlag = false; + goto BASE_CONFIG_EXIT; + } + /* Parse the sensor register. */ + drvData->detectFlag = true; + if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor detect device no exist", __func__); + goto INIT_EXIT; + } + return drvData->accelCfg; + + INIT_EXIT: + (void)ReleaseSensorBusHandle(&drvData->accelCfg->busCfg); + BASE_CONFIG_EXIT: + drvData->accelCfg->root = NULL; + (void)memset_s(&drvData->accelCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo)); + (void)memset_s(&drvData->accelCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg)); + (void)memset_s(&drvData->accelCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr)); + return drvData->accelCfg; } - if (drvData->accelCfg == NULL) { - HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__); - return NULL; + ``` + + - Implement **Enable()** as follows. + + ```c + static int32_t SetAccelEnable(void) + { + int32_t ret; + struct AccelDrvData *drvData = AccelGetDrvData(); + + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); + + if (drvData->enable) { + HDF_LOGE("%s: Accel sensor is enabled", __func__); + return HDF_SUCCESS; + } + /* Set the register. */ + ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor enable config failed", __func__); + return ret; + } + /* Create a timer. */ + ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret); + return ret; + } + /* Start the timer to report data. */ + ret = OsalTimerStartLoop(&drvData->accelTimer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret); + return ret; + } + drvData->enable = true; + + return HDF_SUCCESS; } - /* Parse the basic sensor configuration. */ - if (GetSensorBaseConfigData(node, drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGE("%s: Get sensor base config failed", __func__); - goto BASE_CONFIG_EXIT; + ``` + + - Implement **Disable()** as follows. + + ```c + static int32_t SetAccelDisable(void) + { + int32_t ret; + struct AccelDrvData *drvData = AccelGetDrvData(); + + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); + + if (!drvData->enable) { + HDF_LOGE("%s: Accel sensor had disable", __func__); + return HDF_SUCCESS; + } + /* Set the register. */ + ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor disable config failed", __func__); + return ret; + } + /* Delete the timer. */ + ret = OsalTimerDelete(&drvData->accelTimer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel delete timer failed", __func__); + return ret; + } + drvData->enable = false; + + return HDF_SUCCESS; } - /* Continue the next detection if the sensor is not detected. */ - if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGI("%s: Accel sensor detect device no exist", __func__); - drvData->detectFlag = false; - goto BASE_CONFIG_EXIT; + ``` + + - Implement **SetBatch()** as follows. + + ```c + static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval) + { + (void)interval; + + struct AccelDrvData *drvData = NULL; + + drvData = AccelGetDrvData(); + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + /* Set the sampling rate for the timer. */ + drvData->interval = samplingInterval; + + return HDF_SUCCESS; } - drvData->detectFlag = true; - /* Parse the sensor register. */ - if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor detect device no exist", __func__); - goto INIT_EXIT; + ``` + + - Implement **SetMode()** as follows. + + ```c + static int32_t SetAccelMode(int32_t mode) + { + if (mode <= SENSOR_WORK_MODE_DEFAULT || mode >= SENSOR_WORK_MODE_MAX) { + HDF_LOGE("%s: The current mode is not supported", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; } - return drvData->accelCfg; - ... - } - /* The entry function of the acceleration sensor driver is used to initialize the sensor private data structure object, allocate space for the sensor HCS data configuration object, call the entry function for initializing the sensor HCS data configuration, detect whether the sensor device is in position, create a timer for sensor data reporting, register the sensor normalization APIs, and register the sensor device. */ - int32_t AccelInitDriver(struct HdfDeviceObject *device) - { - ... - /* Initialize work queue resources. */ - if (InitAccelData(drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: Init accel config failed", __func__); - return HDF_FAILURE; - } - /* Allocate acceleration configuration resources. */ - drvData->accelCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->accelCfg)); - if (drvData->accelCfg == NULL) { - HDF_LOGE("%s: Malloc accel config data failed", __func__); - return HDF_FAILURE; + ``` + + - Implement **SetOption()** as follows. + + ```c + static int32_t SetAccelOption(uint32_t option) + { + (void)option; + return HDF_SUCCESS; } - /* Register the register group information. */ - drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0]; - ... - return HDF_SUCCESS; - } - /* Release the resources allocated during driver initialization. */ - void AccelReleaseDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN(device); - struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; - CHECK_NULL_PTR_RETURN(drvData); - /* Release the resources if the sensor is in position. */ - if (drvData->detectFlag) { - AccelReleaseCfgData(drvData->accelCfg); + ``` + +2. Develop the differentiated drivers for acceleration sensors. + + - Configure the host information for the differentiated driver of the acceleration sensor in **vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs**. + + The code is as follows: + + ```c + device_sensor_mxc6655xa :: device { + device0 :: deviceNode { + policy = 1; // Policy for publishing drive services. + priority = 120; // Driver startup priority (0–200). A larger value indicates a lower priority. The default value 100 is recommended. The sequence for loading devices with the same priority is random. + preload = 0; // Whether to load the driver on demand. The value 0 means to load the driver on demand, and 2 means the opposite. + permission = 0664; // Permission for the driver to create a device node. + moduleName = "HDF_SENSOR_ACCEL_MXC6655XA"; // Driver name, which must be the same as moduleName in the driver entry structure. + serviceName = "hdf_accel_mxc6655xa"; // Name of the service published by acceleration mxc6655xa. It must be unique. + deviceMatchAttr = "hdf_sensor_accel_mxc6655xa_driver"; // Keyword for matching the private data of the driver. The value must be the same as the match_attr value in the private data configuration table of the driver. } - OsalMemFree(drvData->accelCfg); - drvData->accelCfg = NULL; - /* Destroy the work queue resource if the sensor is in position. */ - HdfWorkDestroy(&drvData->accelWork); - HdfWorkQueueDestroy(&drvData->accelWorkQueue); - OsalMemFree(drvData); } ``` -2. Configure the device information about the acceleration sensor driver. - - The acceleration sensor model uses the HCS as the configuration source code. For details about the HCS configuration fields, see [Driver Configuration Management](driver-hdf-manage.md). - - ```hcs - /* Device information HCS configuration of the acceleration sensor. */ - device_sensor_accel :: device { - device0 :: deviceNode { - policy = 1; // Policy for the driver to publish services. - priority = 100; // Priority (0–200) for starting the driver. A larger value indicates a lower priority. The recommended value is 100. If the priorities are the same, the device loading sequence is not ensured. - preload = 0; // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite. - permission = 0664; // Permission for the device node created. - moduleName = "HDF_SENSOR_ACCEL"; // Driver name. It must be the same as moduleName in the driver entry structure. - serviceName = "sensor_accel"; // Name of the service published by the driver. The name must be unique. - deviceMatchAttr = "hdf_sensor_accel_driver"; // Keyword matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver. + - Configure the private HCS for the differentiated driver of the acceleration sensor. + + - Code path: **vendor\hihope\rk3568\hdf_config\khdf\sensor\accel\mxc6655xa_config.hcs**. + + - The code is as follows: + + ```c + #include "../sensor_common.hcs" + root { + accel_mxc6655xa_chip_config : sensorConfig { + match_attr = "hdf_sensor_accel_mxc6655xa_driver"; + sensorInfo :: sensorDeviceInfo { + sensorName = "accelerometer"; + vendorName = "memsi_mxc6655xa"; // Max string length is 16 bytes + sensorTypeId = 1; // enum SensorTypeTag + sensorId = 1; // User-defined sensor ID + power = 230; + minDelay = 5000000; // Nanosecond + maxDelay = 200000000; // Nanosecond + } + sensorBusConfig :: sensorBusInfo { + busType = 0; // 0:i2c 1:spi + busNum = 5; + busAddr = 0x15; + regWidth = 1; // 1 byte + } + sensorIdAttr :: sensorIdInfo { + chipName = "mxc6655xa"; + chipIdRegister = 0x0f; + chipIdValue = 0x05; // Read the value based on the device ID register or check the value in the related chip datasheet. + } + sensorDirection { + direction = 1; // chip direction range of value:0-7 + /* 1:negative 0:positive + 0:AXIS_X 1:AXIS_Y 2:AXIS_Z + */ + /* sign[AXIS_X], sign[AXIS_Y], sign[AXIS_Z], map[AXIS_X], map[AXIS_Y], map[AXIS_Z] */ + convert = [ + 0, 0, 0, 0, 1, 2, + 1, 0, 0, 1, 0, 2, + 0, 0, 1, 0, 1, 2, + 0, 1, 0, 1, 0, 2, + 1, 0, 1, 0, 1, 2, + 0, 0, 1, 1, 0, 2, + 0, 1, 1, 0, 1, 2, + 1, 1, 1, 1, 0, 2 + ]; + } + sensorRegConfig { + /* regAddr: register address + value: config register value + len: size of value + mask: mask of value + delay: config register delay time (ms) + opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bit + calType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shift + shiftNum: shift bits + debug: 0-no debug 1-debug + save: 0-no save 1-save + */ + /* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */ + initSeqConfig = [ + 0x7e, 0xb6, 0xff, 1, 5, 2, 0, 0, 0, 0, + 0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0 + ]; + enableSeqConfig = [ + 0x7e, 0x11, 0xff, 1, 5, 2, 0, 0, 0, 0, + 0x41, 0x03, 0xff, 1, 0, 2, 0, 0, 0, 0, + 0x40, 0x08, 0xff, 1, 0, 2, 0, 0, 0, 0 + ]; + disableSeqConfig = [ + 0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0 + ]; + } + } } - } - ``` - -3. Develop the internal interfaces of the acceleration sensor abstract driver. Specifically, implement the **Enable**, **Disable**, **SetBatch**, **SetMode**, **SetOption**, **AccelCreateCfgData**, **AccelReleaseCfgData**, and **AccelRegisterChipOps** functions. - - ```c - /* Leave a function empty if it is not used. */ - static int32_t SetAccelInfo(struct SensorBasicInfo *info) - { - (void)info; - - return HDF_ERR_NOT_SUPPORT; - } - /* Deliver the configuration of enabling the register groups. */ - static int32_t SetAccelEnable(void) - { - int32_t ret; - struct AccelDrvData *drvData = AccelGetDrvData(); - - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); - - if (drvData->enable) { - HDF_LOGE("%s: Accel sensor is enabled", __func__); + ``` + + - Implement the code for the differentiated driver in **drivers\peripheral\sensor\chipset\accel\accel_mxc6655xa.c**. + + - Define the **HdfDriverEntry** object corresponding to the acceleration sensor chipset driver. The driver entry function is defined as follows: + + ```c + /* Register the entry struct object of the mxc6655xa acceleration sensor. */ + struct HdfDriverEntry g_accelMxc6655xaDevEntry = { + .moduleVersion = 1, // Module version of the mxc6655xa acceleration sensor. + .moduleName = "HDF_SENSOR_ACCEL_MXC6655XA", // Module name of the mxc6655xa acceleration sensor. The value must be the same as the value of moduleName of the acceleration sensor in the device_info.hcs file. + .Bind = Mxc6655xaBindDriver, // Bind function of the mxc6655xa acceleration sensor. + .Init = Mxc6655xaInitDriver, // Init function of the mxc6655xa acceleration sensor. + .Release = Mxc6655xaReleaseDriver, // Release function of the mxc6655xa acceleration sensor. + }; + /* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init() to load the driver. If Init() fails to be called, the HDF calls Release() to release resources and exit. */ + HDF_INIT(g_accelMxc6655xaDevEntry); + ``` + + - Implement **Bind()** for the differentiated driver as follows. + + ```c + int32_t Mxc6655xaBindDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)OsalMemCalloc(sizeof(*drvData)); + if (drvData == NULL) { + HDF_LOGE("%s: Malloc MXC6655XA drv data fail", __func__); + return HDF_ERR_MALLOC_FAIL; + } + + drvData->ioService.Dispatch = DispatchMXC6655xa; + drvData->device = device; + device->service = &drvData->ioService; + g_mxc6655xaDrvData = drvData; + return HDF_SUCCESS; } - - ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor enable config failed", __func__); - return ret; - } - - ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret); - return ret; + ``` + + - Implement **Init()** for the differentiated driver as follows. + + ```c + int32_t Mxc6655xaInitDriver(struct HdfDeviceObject *device) + { + int32_t ret; + struct AccelOpsCall ops; + + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service; + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + drvData->sensorCfg = AccelCreateCfgData(device->property); + if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) { + HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__); + return HDF_ERR_NOT_SUPPORT; + } + + ops.Init = NULL; + ops.ReadData = ReadMxc6655xaData; + ret = AccelRegisterChipOps(&ops); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Register MXC6655XA accel failed", __func__); + return HDF_FAILURE; + } + + ret = InitMxc6655xa(drvData->sensorCfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Init MXC6655XA accel failed", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; } - - ret = OsalTimerStartLoop(&drvData->accelTimer); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret); - return ret; + ``` + + - Implement **Release()** for the differentiated driver as follows. + + ```c + void Mxc6655xaReleaseDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN(device); + + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service; + CHECK_NULL_PTR_RETURN(drvData); + + if (drvData->sensorCfg != NULL) { + AccelReleaseCfgData(drvData->sensorCfg); + drvData->sensorCfg = NULL; + } + OsalMemFree(drvData); } - drvData->enable = true; - - return HDF_SUCCESS; - } - /* Deliver the configuration of disabling the register groups. */ - static int32_t SetAccelDisable(void) - { - int32_t ret; - struct AccelDrvData *drvData = AccelGetDrvData(); - - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); - - if (!drvData->enable) { - HDF_LOGE("%s: Accel sensor had disable", __func__); + ``` + + - Implement the internal interfaces of the differentiated driver of the acceleration sensor. + + You need to implement **ReadMxc6655xaData** and register it in **Mxc6655xaInitDriver**. The implementation is as follows: + + ```c + static int32_t ReadMxc6655xaRawData(struct SensorCfgData *data, struct AccelData *rawData, uint64_t *timestamp) + { + uint8_t status = 0; + uint8_t reg[ACCEL_AXIS_BUTT]; + OsalTimespec time; + int32_t x; + int32_t y; + int32_t z; + + (void)memset_s(&time, sizeof(time), 0, sizeof(time)); + (void)memset_s(reg, sizeof(reg), 0, sizeof(reg)); + + CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); + + if (OsalGetTime(&time) != HDF_SUCCESS) { + HDF_LOGE("%s: Get time failed", __func__); + return HDF_FAILURE; + } + *timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT; /* unit nanosecond */ + + int32_t ret = ReadSensor(&data->busCfg, MXC6655XA_STATUS_ADDR, &status, sizeof(uint8_t)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: data status [%u] ret [%d]", __func__, status, ret); + return HDF_FAILURE; + } + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_LSB_ADDR, ®[ACCEL_X_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_MSB_ADDR, ®[ACCEL_X_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_LSB_ADDR, ®[ACCEL_Y_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_MSB_ADDR, ®[ACCEL_Y_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_LSB_ADDR, ®[ACCEL_Z_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_MSB_ADDR, ®[ACCEL_Z_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + x = SensorConvertData(reg[ACCEL_X_AXIS_MSB], reg[ACCEL_X_AXIS_LSB]); + y = SensorConvertData(reg[ACCEL_Y_AXIS_MSB], reg[ACCEL_Y_AXIS_LSB]); + z = SensorConvertData(reg[ACCEL_Z_AXIS_MSB], reg[ACCEL_Z_AXIS_LSB]); + rawData->x = x; + rawData->y = y; + rawData->z = z; + return HDF_SUCCESS; } - - ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor disable config failed", __func__); - return ret; - } - - ret = OsalTimerDelete(&drvData->accelTimer); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel delete timer failed", __func__); + /* Read the event data of the accelerator. Register this function in Mxc6655xaInitDriver() to pass in the data to the abstracted driver of the acceleration sensor. */ + int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event) + { + int32_t ret; + struct AccelData rawData = { 0, 0, 0 }; + static int32_t tmp[ACCEL_AXIS_NUM]; + + CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM); + + ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: MXC6655XA read raw data failed", __func__); + return HDF_FAILURE; + } + + event->sensorId = SENSOR_TAG_ACCELEROMETER; + event->option = 0; + event->mode = SENSOR_WORK_MODE_REALTIME; + + rawData.x = rawData.x * MXC6655XA_ACC_SENSITIVITY_2G; + rawData.y = rawData.y * MXC6655XA_ACC_SENSITIVITY_2G; + rawData.z = rawData.z * MXC6655XA_ACC_SENSITIVITY_2G; + + tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + + ret = SensorRawDataToRemapData(cfg->direction, tmp, sizeof(tmp) / sizeof(tmp[0])); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__); + return HDF_FAILURE; + } + + event->dataLen = sizeof(tmp); + event->data = (uint8_t *)&tmp; + return ret; } - drvData->enable = false; - - return HDF_SUCCESS; - } - /* Set the sampling interval and data reporting interval of the sensor. */ - static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval) - { - (void)interval; - - struct AccelDrvData *drvData = NULL; - - drvData = AccelGetDrvData(); - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - - drvData->interval = samplingInterval; - - return HDF_SUCCESS; - } - /* Set the data reporting mode of the sensor. Currently, the real-time mode is supported. */ - static int32_t SetAccelMode(int32_t mode) - { - return (mode == SENSOR_WORK_MODE_REALTIME) ? HDF_SUCCESS : HDF_FAILURE; - } - - static int32_t SetAccelOption(uint32_t option) - { - (void)option; - return HDF_SUCCESS; - } - /* Set the sensor options. */ - static int32_t SetAccelOption(uint32_t option) - { - (void)option; - return HDF_ERR_NOT_SUPPORT; - } - ``` - -4. Develop the acceleration sensor chipset driver. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions. - - ```c - /* Message interaction of the acceleration sensor chipset driver */ - static int32_t DispatchBMI160(struct HdfDeviceIoClient *client, - int cmd, struct HdfSBuf *data, struct HdfSBuf *reply) - { - (void)client; - (void)cmd; - (void)data; - (void)reply; - - return HDF_SUCCESS; - } - /* Bind the service provided by the acceleration sensor chipset driver to the HDF. */ - int32_t Bmi160BindDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - - struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)OsalMemCalloc(sizeof(*drvData)); - if (drvData == NULL) { - HDF_LOGE("%s: Malloc Bmi160 drv data fail", __func__); - return HDF_ERR_MALLOC_FAIL; - } - - drvData->ioService.Dispatch = DispatchBMI160; - drvData->device = device; - device->service = &drvData->ioService; - g_bmi160DrvData = drvData; - - return HDF_SUCCESS; - } - /* Initialize the acceleration sensor chipset driver. */ - int32_t Bmi160InitDriver(struct HdfDeviceObject *device) - { - int32_t ret; - struct AccelOpsCall ops; - - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)device->service; - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - - ret = InitAccelPreConfig(); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Init BMI160 bus mux config", __func__); - return HDF_FAILURE; - } - - drvData->sensorCfg = AccelCreateCfgData(device->property); - if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) { - HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__); - return HDF_ERR_NOT_SUPPORT; - } - - ops.Init = NULL; - ops.ReadData = ReadBmi160Data; - ret = AccelRegisterChipOps(&ops); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Register BMI160 accel failed", __func__); - return HDF_FAILURE; - } - - ret = InitBmi160(drvData->sensorCfg); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Init BMI160 accel failed", __func__); - return HDF_FAILURE; - } - - return HDF_SUCCESS; - } - /* Release the resources allocated during driver initialization. */ - void Bmi160ReleaseDriver(struct HdfDeviceObject *device) - { - ... - if (drvData->sensorCfg != NULL) { - AccelReleaseCfgData(drvData->sensorCfg); - drvData->sensorCfg = NULL; - } - OsalMemFree(drvData); - } - /*HdfDriverEntry object corresponding to the acceleration sensor chipset driver */ - struct HdfDriverEntry g_accelBmi160DevEntry = { - .moduleVersion = 1, - .moduleName = "HDF_SENSOR_ACCEL_BMI160", - .Bind = Bmi160BindDriver, - .Init = Bmi160InitDriver, - .Release = Bmi160ReleaseDriver, - }; - HDF_INIT(g_accelBmi160DevEntry); - ``` - -5. Implement the **ReadData** function of the acceleration sensor chipset driver. - - ```c - int32_t ReadBmi160Data(struct SensorCfgData *data) - { - int32_t ret; - struct AccelData rawData = { 0, 0, 0 }; - int32_t tmp[ACCEL_AXIS_NUM]; - struct SensorReportEvent event; - (void)memset_s(&event, sizeof(event), 0, sizeof(event)); - ret = ReadBmi160RawData(data, &rawData, &event.timestamp); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: BMI160 read raw data failed", __func__); - return HDF_FAILURE; - } - event.sensorId = SENSOR_TAG_ACCELEROMETER; - event.option = 0; - event.mode = SENSOR_WORK_MODE_REALTIME; - ... - ret = ReportSensorEvent(&event); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: BMI160 report data failed", __func__); - } - return ret; - } - ``` + ``` ### Verification -After the driver is developed, develop test cases in the sensor unit test to verify the basic functions of the driver. Use your test platform to set up the test environment. - -```c++ -static int32_t g_sensorDataFlag = 0; // Whether to report sensor data. -static const struct SensorInterface *g_sensorDev = nullptr; // Retain the obtained sensor interface instance address. - -/* Register the data reporting function. */ -static int SensorTestDataCallback(struct SensorEvents *event) -{ - if (event == nullptr) { - return -1; - } - float *data = (float*)event->data; - printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp, - event->sensorId, (*data), *(data + 1), *(data + g_axisZ)); - if (*data > 1e-5) { - g_sensorDataFlag = 1; - } - return 0; -} -/* Initialize the sensor interface instance before executing the test cases. */ -void HdfSensorTest::SetUpTestCase() -{ - g_sensorDev = NewSensorInterfaceInstance(); - if (g_sensorDev == nullptr) { - printf("test sensor get module instance failed\n\r"); - } -} -/* Release case resources. */ -void HdfSensorTest::TearDownTestCase() -{ - if (g_sensorDev != nullptr) { - FreeSensorInterfaceInstance(); - g_sensorDev = nullptr; - } -} -/* Verify the sensor driver. */ -HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0) -{ - int32_t sensorInterval = 1000000000; // Data sampling interval, in nanoseconds. - int32_t pollTime = 5; // Data sampling time, in seconds. - int32_t accelSensorId = 1; // Acceleration sensor ID, which specifies the sensor type. - int32_t count = 0; - int ret; - struct SensorInformation *sensorInfo = nullptr; - - ret = g_sensorDev->Register(0, TraditionSensorTestDataCallback) - EXPECT_EQ(SENSOR_NULL_PTR, ret); - - ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); - EXPECT_EQ(0, ret); - if (sensorInfo == nullptr) { - EXPECT_NE(nullptr, sensorInfo); - return; - } - /* Print the obtained sensor list. */ - for (int i = 0; i < count; i++) { - printf("get sensorId[%d], info name[%s]\n\r", sensorInfo[i]->sensorId, sensorInfo[i]->sensorName); - } - ret = g_sensorDev->Enable(accelSensorId); - EXPECT_EQ(0, ret); - g_sensorDataFlag = 0; - - ret = g_sensorDev->SetBatch(accelSensorId, sensorInterval, pollTime); - EXPECT_EQ(0, ret); - /* Observe the printed data within the period specified by pollTime. */ - OsalSleep(pollTime); - EXPECT_EQ(1, g_sensorDataFlag); - - ret = g_sensorDev->Disable(accelSensorId); - g_sensorDataFlag = 0; - EXPECT_EQ(0, ret); - - ret = g_sensorDev->Unregister(0, TraditionSensorTestDataCallback); - EXPECT_EQ(0, ret); -} -``` +After the driver is developed, develop test cases in the sensor unit test to verify the basic functions of the driver. Use the developer self-test platform as the test environment. + +- The reference test code is as follows: + + ```c + #include + #include + #include + #include + #include + #include "hdf_base.h" + #include "osal_mem.h" + #include "osal_time.h" + #include "sensor_if.h" + #include "sensor_type.h" + + using namespace testing::ext; + const struct SensorInterface *g_sensorDev = nullptr; + /* Create a callback. */ + static int32_t SensorDataCallback(const struct SensorEvents *event) + { + if (event == NULL) { + return HDF_FAILURE; + } + + float *data = (float*)event->data; + printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp, + event->sensorId, (*data), *(data + 1), *(data + 2)); + + return HDF_SUCCESS; + } + + class HdfSensorTest : public testing::Test { + public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + }; + + /* Initialize the sensor interface instance before executing the test cases. */ + void HdfSensorTest::SetUpTestCase() + { + g_sensorDev = NewSensorInterfaceInstance(); + if (g_sensorDev == nullptr) { + printf("test sensor get module instance failed\n\r"); + } + } + /* Release case resources. */ + void HdfSensorTest::TearDownTestCase() + { + if (g_sensorDev != nullptr) { + FreeSensorInterfaceInstance(); + g_sensorDev = nullptr; + } + } + + void HdfSensorTest::SetUp() + { + } + + void HdfSensorTest::TearDown() + { + } + + HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0) + { + int ret; + struct SensorInformation *sensorInfo = NULL; + int32_t count = 0; + int32_t sensorInterval = 200000000; /* Set the data sampling rate to 200000000, in the unit of nanoseconds (200 ms). */ + int32_t reportInterval = 400000000; + + /* 2. Register a sensor data callback. */ + ret = g_sensorDev->Register(TRADITIONAL_SENSOR_TYPE, SensorDataCallback); + if (ret != 0) { + return; + } + printf("Register success\n"); + + /* 3. Obtain the list of sensors supported by the device. */ + ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); + if (ret != 0) { + return; + } + + printf("GetAllSensors count: %d\n", count); + + for (int i = 0; i < count; i++) + { + printf("sensor [%d]: sensorName: %s, vendorName: %s, sensorTypeId: %d, sensorId: %d\n", i, + sensorInfo[i].sensorName, sensorInfo[i].vendorName, sensorInfo[i].sensorTypeId, sensorInfo[i].sensorId); + } + + for (int i = 0; i < count; i++) + { + /* 4. Set the sensor sampling rate. */ + ret = g_sensorDev->SetBatch(sensorInfo[i].sensorId, sensorInterval, reportInterval); + if (ret != 0) { + printf("SetBatch failed\n ,ret: %d",ret); + continue; + } + printf("SetBatch success\n"); + + /* 5. Enable the sensor. */ + ret = g_sensorDev->Enable(sensorInfo[i].sensorId); + if (ret != 0) { + continue; + } + printf("Enable success\n"); + + usleep(1000 * 1000); + + /* 6. Disable the sensor. */ + ret = g_sensorDev->Disable(sensorInfo[i].sensorId); + if (ret != 0) { + continue; + } + printf("Disable success\n"); + } + + /* 7. Unregister the sensor data callback. */ + ret = g_sensorDev->Unregister(TRADITIONAL_SENSOR_TYPE, SensorDataCallback); + if (ret != 0) { + return; + } + printf("Unregister success\n"); + } + ``` + +- The reference code of the .gn file is as follows: + + ``` + import("//build/ohos.gni") + import("//build/test.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + module_output_path = "drivers_peripheral_sensor/sensor" + ohos_unittest("sensor_test") { + module_out_path = module_output_path + sources = [ "sensor_test.cpp" ] + include_dirs = [ + "//drivers/peripheral/sensor/interfaces/include", + ] + deps = [ "//drivers/peripheral/sensor/hal:hdi_sensor" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-format", + "-Wno-format-extra-args", + ] + + install_enable = true + install_images = [ "vendor" ] + module_install_dir = "bin" + part_name = "unionman_products" + } + ```