From 36eab375f7aeecefb26f2292113ce44cdbfee5ec Mon Sep 17 00:00:00 2001 From: Annie_wang Date: Mon, 4 Jul 2022 14:48:04 +0800 Subject: [PATCH] update docs Signed-off-by: Annie_wang --- .../driver/driver-peripherals-light-des.md | 176 +++++++++++------- .../driver/figures/light_driver_model.png | Bin 9493 -> 13595 bytes 2 files changed, 109 insertions(+), 67 deletions(-) diff --git a/en/device-dev/driver/driver-peripherals-light-des.md b/en/device-dev/driver/driver-peripherals-light-des.md index 3825100fce..2abac6f9b9 100644 --- a/en/device-dev/driver/driver-peripherals-light-des.md +++ b/en/device-dev/driver/driver-peripherals-light-des.md @@ -5,7 +5,9 @@ ### Light -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 functionalities such as cross-OS migration 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. The figure below shows the light driver model. +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 functionalities such as cross-OS migration 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. + +The figure below shows the light driver model. **Figure 1** Light driver model @@ -23,7 +25,7 @@ The following uses the Hi3516D V300 development board powered by the standard sy 1. The light driver reads the light device management configuration from **Light Host** in the **device_info.hcs** file. 2. The light driver reads the light data configuration from the **light_config.hcs** file. -3. The light driver parses information about the light device management configuration and associates with the corresponding device driver. +3. The light driver parses the light device management configuration and associates with the corresponding device driver. 4. The light proxy delivers an instruction to the light stub. 5. The light stub delivers an instruction to the light controller. 6. The light abstract driver interface is started. @@ -40,17 +42,17 @@ The light driver model provides APIs to obtain information about all the lights **Table 1** APIs of the light driver model -| API | Description | +| API | Description | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | Obtains information about all lights in the system. **lightInfo** indicates the double pointer to the basic light information. **count** indicates the pointer to the number of lights.| -| int32_t (*TurnOnLight)(uint32_t type, struct LightEffect *effect) | Turns on available lights in the list based on the specified light type. **type** indicates the light type, and **effect** indicates the pointer to the blinking effect.| -| int32_t (*TurnOffLight)(uint32_t type) | Turns off available lights in the light list based on the specified light type. **type** indicates the light type. | +| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | Obtains information about all lights in the system.
- **lightInfo** indicates the double pointer to the basic light information.
- **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 blinking effect. | +| int32_t (*TurnOffLight)(uint32_t lightId) | Turns off available lights in the light list based on the specified light type.
**lightId** indicates the light type. | ### How to Develop 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. Configure the light driver device information. - 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](https://gitee.com/openharmony/docs/blob/master/en/device-dev/driver/driver-hdf-manage.md). + The light driver model uses HDF configuration source (HCS). For details about HCS fields, see [Configuration Management](../driver/driver-hdf-manage.md). The light driver entry is defined as follows: ```c @@ -62,7 +64,7 @@ The light driver model provides APIs to obtain information about all the lights .Init = InitLightDriver, // Initialize the light driver. .Release = ReleaseLightDriver, // Release the light resources. }; - /* Call HDF_INIT to register the driver entry with the HDF. The HDF calls the Bind function and then the Init function to load a driver. If Init fails to be called, the HDF calls Release to release driver resources and exit. */ + /* 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 will call Release() to release resources and exit. */ HDF_INIT(g_lightDriverEntry); ``` @@ -81,13 +83,13 @@ The light driver model provides APIs to obtain information about all the lights CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); (void)OsalMutexLock(&drvData->mutex); - if (!HdfSbufReadInt32(data, &lightType)) { - HDF_LOGE("%s: sbuf read lightType failed", __func__); + if (!HdfSbufReadInt32(data, &lightId)) { + HDF_LOGE("%s: sbuf read lightId fail", __func__); (void)OsalMutexUnlock(&drvData->mutex); return HDF_ERR_INVALID_PARAM; } ..... - ret = DispatchCmdHandle(lightType, data, reply); + ret = DispatchCmdHandle(lightId, data, reply); (void)OsalMutexUnlock(&drvData->mutex); return ret; } @@ -128,6 +130,11 @@ The light driver model provides APIs to obtain information about all the lights HDF_LOGE("%s: get light config fail!", __func__); return HDF_FAILURE; } + /* 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; } @@ -153,18 +160,18 @@ The light driver model provides APIs to obtain information about all the lights } ``` - - The light device management module dispatches light device APIs in the system. During the system startup process, the HDF loads the device management driver from the HCS of the light host. + - The light device management module publishes 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. ``` /* Light device HCS */ device_light :: device { device0 :: deviceNode { - policy = 2; // Driver service dispatch policy (0: no service is dispatched; 1: services are dispatched to the kernel mode; 2: services are dispatched to both the kernel mode and user mode) + policy = 2; // Policy for the driver to publish services. (0: The driver does not provide services. 1: The driver publishes services for the kernel space. 2: The driver publishes services for both the kernel space and user space.) priority = 100; // Light driver startup priority. The value ranges from 0 to 200. A larger value indicates a lower priority. The value 100 is recommended. If the priorities are the same, the device loading sequence cannot be ensured. - preload = 0; // Field for specifying whether to load the driver. The value 0 means to load the driver, and 2 means the opposite. + preload = 0; // Whether to load the driver on demand. The value 0 means to load the driver on demand; the value 2 means the opposite. permission = 0664; // Permission for the driver to create a device node. moduleName = "HDF_LIGHT"; // Light driver name. The value of this field must be the same as that of moduleName in the HdfDriverEntry structure. - serviceName = "hdf_light"; // Service name of the driver, which must be unique. + serviceName = "hdf_light"; // Unique name of the service published by the driver. 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. } ``` @@ -173,16 +180,16 @@ The light driver model provides APIs to obtain information about all the lights ```c /* Allocate resources and parse the HCS. */ - static int32_t ParseLightInfo(const struct DeviceResourceNode *node) + 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, "lightType"); + drvData->lightNum = parser->GetElemNum(light, "lightId"); .... for (i = 0; i < drvData->lightNum; ++i) { - /* Obtains the light type information. */ - ret = parser->GetUint32ArrayElem(light, "lightType", i, &temp, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightType"); + /* 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) { @@ -191,12 +198,19 @@ The light driver model provides APIs to obtain information about all the lights drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); ..... /* Fill in the light device information. */ - ret = parser->GetUint32(light, "busRNum", &drvData->info[temp]->busRNum, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busRNum"); - ret = parser->GetUint32(light, "busGNum", &drvData->info[temp]->busGNum, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busGNum"); - ret = parser->GetUint32(light, "busBNum", &drvData->info[temp]->busBNum, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busBNum"); + 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; + } + ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[temp]->busBNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[temp]->busBNum = LIGHT_INVALID_GPIO; + } ..... return HDF_SUCCESS; } @@ -205,25 +219,25 @@ The light driver model provides APIs to obtain information about all the lights 3. Call related APIs to obtain the light type, turn on and off lights, and create and delete the timer based on the blinking mode. ```c - /* Call GetAllLightInfo to obtain the light type. Call Enable to enable the blinking mode. - Call Disable to stop blinking. */ + /* Call GetAllLightInfo() to obtain the light type. Call TurnOnLight() to enable the blinking mode. + Call TurnOffLight() to stop blinking. */ 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 failed", __func__); + 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.lightType = i; + 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 failed", __func__); + HDF_LOGE("%s: write sbuf fail", __func__); return HDF_FAILURE; } } @@ -231,38 +245,67 @@ The light driver model provides APIs to obtain information about all the lights return HDF_SUCCESS; } - /* Enable lights based on the specified light type and input parameters. */ - static int32_t Enable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply) + /* Update the status of the lights of the specified type. */ + static int32_t UpdateLight(uint32_t lightId, uint32_t lightOn) { ..... - /* Set the light color based on the brightness value passed in. Red: bits 16–31; Green: bits 8–15; Blue: bits 0–7 */ - if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_R_BIT) != 0) { - drvData->info[lightType]->busNum = drvData->info[lightType]->busRNum; - } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_G_BIT) != 0) { - drvData->info[lightType]->busNum = drvData->info[lightType]->busGNum; - } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_B_BIT) != 0) { - drvData->info[lightType]->busNum = drvData->info[lightType]->busBNum; + /* 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; } - /* The light is steady on. */ - if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { - - if (GpioWrite(drvData->info[lightType]->busNum, GPIO_VAL_HIGH) != HDF_SUCCESS) { + /* If bits 0 to 7 are not 0, output the GPIO pin 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__); return HDF_FAILURE; } } + /* If bits 8 to 15 are not 0, output the GPIO pin 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; + } + } + /* If bits 16 to 23 are not 0, output the GPIO pin 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; + } + } + ..... + } + + /* 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, enable 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[lightType]->lightState = LIGHT_STATE_START; + 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[lightType]->onTime = buf->flashEffect.onTime < drvData->info[lightType]->onTime ? - drvData->info[lightType]->onTime : buf->flashEffect.onTime; - drvData->info[lightType]->offTime = buf->flashEffect.offTime < drvData->info[lightType]->offTime ? - drvData->info[lightType]->offTime : buf->flashEffect.offTime; + 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[lightType]->onTime, - LightTimerEntry, (uintptr_t)lightType) != HDF_SUCCESS) { - HDF_LOGE("%s: create light timer fail!", __func__); - return HDF_FAILURE; + if (OsalTimerCreate(&drvData->timer, drvData->info[lightId]->onTime, + LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) { + HDF_LOGE("%s: create light timer fail!", __func__); + return HDF_FAILURE; } /* Start the periodic timer. */ if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { @@ -274,7 +317,7 @@ The light driver model provides APIs to obtain information about all the lights } /* Turn off lights based on the specified light type. */ - static int32_t Disable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply) + static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) { /* Delete the timer. */ if (drvData->timer.realTimer != NULL) { @@ -283,9 +326,8 @@ The light driver model provides APIs to obtain information about all the lights HDF_LOGE("%s: delete haptic timer fail!", __func__); } } - /* Power off the corresponding GPIO. */ - if (GpioWrite(drvData->info[lightType]->busRNum, GPIO_VAL_LOW) != HDF_SUCCESS){ - HDF_LOGE("%s: gpio write failed", __func__); + if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) { + HDF_LOGE("%s: gpio write fail", __func__); return HDF_FAILURE; } @@ -298,16 +340,16 @@ The light driver model provides APIs to obtain information about all the lights 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 light interface instance before executing the test case. */ +/* Initialize the LightInterfaceInstance before executing the test case. */ void HdfLightTest::SetUpTestCase() { g_lightDev = NewLightInterfaceInstance(); if (g_lightDev == nullptr) { - printf("test light get Module instance failed\n\r"); + 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 failed\n\r"); + printf("get light informations fail\n\r"); } } @@ -334,9 +376,9 @@ HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) info = g_lightInfo; for (int i = 0; i < g_count; ++i) { - printf("get lightId[%d]\n\r", info->lightType); - EXPECT_GE(info->lightType, g_minLightType); - EXPECT_LE(info->lightType, g_maxLightType); + printf("get lightId[%d]\n\r", info->lightId); + EXPECT_GE(info->lightId, g_minLightId); + EXPECT_LE(info->lightId, g_maxLightId); info++; } } @@ -347,14 +389,14 @@ HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) int32_t i; int32_t ret; struct LightEffect effect; - effect->lightBrightness = 0x80000000; + 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]->lightType, effect); + ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); EXPECT_EQ(0, ret); OsalSleep(LIGHT_WAIT_TIME); @@ -370,14 +412,14 @@ HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1) int32_t i; int32_t ret; struct LightEffect effect; - effect->lightBrightness = 0x80000000; + 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]->lightType, effect); + ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); EXPECT_EQ(0, ret); OsalSleep(LIGHT_WAIT_TIME); diff --git a/en/device-dev/driver/figures/light_driver_model.png b/en/device-dev/driver/figures/light_driver_model.png index eafbab6d62a5020008faf1ac56c64d4bdefa05c7..a2adb1c908d3a263299248c95ad5c1e1f202e61f 100644 GIT binary patch literal 13595 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 literal 9493 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