1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "light_controller.h"
17#include <fcntl.h>
18#include <securec.h>
19#include <stdio.h>
20#include "osal_mem.h"
21#include "hdf_base.h"
22#include "hdf_dlist.h"
23#include "hdf_io_service_if.h"
24#include "light_uhdf_log.h"
25#include "light_dump.h"
26#include "light_if.h"
27#include "light_type.h"
28
29#define HDF_LOG_TAG           uhdf_light_service
30#define LIGHT_SERVICE_NAME    "hdf_light"
31
32#define MULTI_LIGHT_MAX_NUMBER    48
33#define LIGHT_ON    1
34#define LIGHT_OFF   0
35
36struct LightEffect g_lightEffect;
37uint8_t g_lightState[LIGHT_ID_BUTT] = {0};
38
39struct LightDevice *GetLightDevicePriv(void)
40{
41    static struct LightDevice lightDeviceData = {
42        .initState = false,
43        .lightNum = 0,
44        .ioService = NULL,
45        .lightInfoEntry = NULL,
46    };
47
48    return &lightDeviceData;
49}
50
51struct LightEffect *GetLightEffect(void)
52{
53    return &g_lightEffect;
54}
55
56uint8_t *GetLightState(void)
57{
58    return g_lightState;
59}
60
61static int32_t SendLightMsg(uint32_t cmd, struct HdfSBuf *msg, struct HdfSBuf *reply)
62{
63    struct LightDevice *priv = GetLightDevicePriv();
64
65    if (priv->ioService == NULL || priv->ioService->dispatcher == NULL ||
66        priv->ioService->dispatcher->Dispatch == NULL) {
67        HDF_LOGE("%s: para invalid", __func__);
68        return HDF_FAILURE;
69    }
70
71    int32_t ret = priv->ioService->dispatcher->Dispatch(&priv->ioService->object, cmd, msg, reply);
72    if (ret != HDF_SUCCESS) {
73        HDF_LOGE("%{public}s: Light dispatch failed", __func__);
74        return ret;
75    }
76
77    return HDF_SUCCESS;
78}
79
80static int32_t ReadLightInfo(struct HdfSBuf *reply, struct LightDevice *priv)
81{
82    struct LightInfo *pos = NULL;
83    const char *name = NULL;
84
85    if (!HdfSbufReadUint32(reply, &priv->lightNum)) {
86        HDF_LOGE("%s: sbuf read lightNum failed", __func__);
87        return HDF_FAILURE;
88    }
89
90    if (priv->lightInfoEntry != NULL) {
91        OsalMemFree(priv->lightInfoEntry);
92        priv->lightInfoEntry = NULL;
93    }
94
95    priv->lightInfoEntry = (struct LightInfo *)OsalMemCalloc(sizeof(*priv->lightInfoEntry) * priv->lightNum);
96    if (priv->lightInfoEntry == NULL) {
97        HDF_LOGE("%s: malloc fail", __func__);
98        return HDF_FAILURE;
99    }
100
101    pos = priv->lightInfoEntry;
102
103    for (uint32_t i = 0; i < priv->lightNum; ++i) {
104        if (!HdfSbufReadUint32(reply, &pos->lightId)) {
105            HDF_LOGE("%{public}s:read lightId failed!", __func__);
106            return HDF_FAILURE;
107        }
108
109        name = HdfSbufReadString(reply);
110        if (strcpy_s(pos->lightName, NAME_MAX_LEN, name) != EOK) {
111            HDF_LOGE("%{public}s:copy lightName failed!", __func__);
112            return HDF_FAILURE;
113        }
114
115        if (!HdfSbufReadUint32(reply, &pos->lightNumber)) {
116            HDF_LOGE("%{public}s:read lightNumber failed!", __func__);
117            return HDF_FAILURE;
118        }
119
120        if (!HdfSbufReadInt32(reply, &pos->lightType)) {
121            HDF_LOGE("%{public}s:read lightType failed!", __func__);
122            return HDF_FAILURE;
123        }
124        pos++;
125    }
126
127    return HDF_SUCCESS;
128}
129
130static int32_t GetLightInfo(struct LightInfo **lightInfo, uint32_t *count)
131{
132    if ((lightInfo == NULL) || (count == NULL)) {
133        HDF_LOGE("%s:line:%{public}d pointer is null and return ret", __func__, __LINE__);
134        return HDF_FAILURE;
135    }
136
137    struct LightDevice *priv = GetLightDevicePriv();
138
139    if (priv->lightNum > 0) {
140        *count = priv->lightNum;
141        *lightInfo = priv->lightInfoEntry;
142        return HDF_SUCCESS;
143    }
144
145    (void)OsalMutexLock(&priv->mutex);
146    struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
147    if (reply == NULL) {
148        HDF_LOGE("%s: get sbuf failed", __func__);
149        (void)OsalMutexUnlock(&priv->mutex);
150        return HDF_FAILURE;
151    }
152
153    int32_t ret = SendLightMsg(LIGHT_IO_CMD_GET_INFO_LIST, NULL, reply);
154    if (ret != HDF_SUCCESS) {
155        HDF_LOGE("%{public}s: Light send cmd failed, ret[%{public}d]", __func__, ret);
156        HdfSbufRecycle(reply);
157        (void)OsalMutexUnlock(&priv->mutex);
158        return ret;
159    }
160
161    if (ReadLightInfo(reply, priv) != HDF_SUCCESS) {
162        HdfSbufRecycle(reply);
163        (void)OsalMutexUnlock(&priv->mutex);
164        return HDF_FAILURE;
165    }
166
167    HdfSbufRecycle(reply);
168    (void)OsalMutexUnlock(&priv->mutex);
169
170    *count = priv->lightNum;
171    *lightInfo = priv->lightInfoEntry;
172
173    return HDF_SUCCESS;
174}
175
176static int32_t OnLightValidityJudgment(uint32_t lightId, struct LightEffect *effect)
177{
178    if (lightId >= LIGHT_ID_BUTT) {
179        HDF_LOGE("%{public}s: id not supported", __func__);
180        return LIGHT_NOT_SUPPORT;
181    }
182
183    if (effect->flashEffect.flashMode < LIGHT_FLASH_NONE || effect->flashEffect.flashMode > LIGHT_FLASH_BLINK) {
184        HDF_LOGE("%{public}s: flashMode not supported", __func__);
185        return LIGHT_NOT_FLASH;
186    }
187
188    if ((effect->flashEffect.flashMode == LIGHT_FLASH_BLINK) && (effect->flashEffect.onTime == 0 ||
189        effect->flashEffect.offTime == 0)) {
190        HDF_LOGE("%{public}s: flashMode not supported", __func__);
191        return LIGHT_NOT_FLASH;
192    }
193
194    return LIGHT_SUCCESS;
195}
196
197static int32_t OnLight(uint32_t lightId, struct LightEffect *effect)
198{
199    int32_t ret;
200
201    if (effect == NULL) {
202        HDF_LOGE("%{public}s: effect is NULL", __func__);
203        return HDF_FAILURE;
204    }
205
206    ret = OnLightValidityJudgment(lightId, effect);
207    if (ret != HDF_SUCCESS) {
208        HDF_LOGE("%{public}s: effect is false", __func__);
209        return ret;
210    }
211
212    struct LightDevice *priv = GetLightDevicePriv();
213    (void)OsalMutexLock(&priv->mutex);
214
215    struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
216    if (msg == NULL) {
217        HDF_LOGE("%{public}s: Failed to obtain sBuf size", __func__);
218        (void)OsalMutexUnlock(&priv->mutex);
219        return HDF_FAILURE;
220    }
221
222    if (!HdfSbufWriteInt32(msg, lightId)) {
223        HDF_LOGE("%{public}s: Light write id failed", __func__);
224        HdfSbufRecycle(msg);
225        (void)OsalMutexUnlock(&priv->mutex);
226        return HDF_FAILURE;
227    }
228
229    if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_ENABLE)) {
230        HDF_LOGE("%{public}s: Light write enable failed", __func__);
231        HdfSbufRecycle(msg);
232        (void)OsalMutexUnlock(&priv->mutex);
233        return HDF_FAILURE;
234    }
235
236    if (!HdfSbufWriteBuffer(msg, effect, sizeof(*effect))) {
237        HDF_LOGE("%{public}s: Light write enable failed", __func__);
238        HdfSbufRecycle(msg);
239        (void)OsalMutexUnlock(&priv->mutex);
240        return HDF_FAILURE;
241    }
242
243    ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
244    if (ret != HDF_SUCCESS) {
245        HDF_LOGE("%{public}s: Light enable failed, ret[%{public}d]", __func__, ret);
246    }
247    HdfSbufRecycle(msg);
248    (void)OsalMutexUnlock(&priv->mutex);
249
250    if (memcpy_s(&g_lightEffect, sizeof(g_lightEffect), effect, sizeof(*effect)) != EOK) {
251        HDF_LOGE("%{public}s: Light effect cpy faild", __func__);
252        return HDF_FAILURE;
253    }
254
255    g_lightState[lightId] = LIGHT_ON;
256
257    return ret;
258}
259
260static int32_t OnMultiLightsValidityJudgment(uint32_t lightId, const struct LightColor *colors, const uint32_t count)
261{
262    if (lightId >= LIGHT_ID_BUTT) {
263        HDF_LOGE("%{public}s: id not supported", __func__);
264        return HDF_ERR_NOT_SUPPORT;
265    }
266
267    if (colors == NULL) {
268        HDF_LOGE("%{public}s: colors is nullptr", __func__);
269        return HDF_ERR_INVALID_PARAM;
270    }
271
272    if (count == 0 || count > MULTI_LIGHT_MAX_NUMBER) {
273        HDF_LOGE("%{public}s: count out of range", __func__);
274        return HDF_ERR_INVALID_PARAM;
275    }
276
277    return HDF_SUCCESS;
278}
279
280static int32_t OnMultiLights(uint32_t lightId, const struct LightColor *colors, const uint32_t count)
281{
282    int32_t ret;
283    struct HdfSBuf *sbuf = NULL;
284
285    ret = OnMultiLightsValidityJudgment(lightId, colors, count);
286    if (ret != HDF_SUCCESS) {
287        HDF_LOGE("%{public}s: effect is false", __func__);
288        return ret;
289    }
290
291    struct LightDevice *priv = GetLightDevicePriv();
292    (void)OsalMutexLock(&priv->mutex);
293
294    sbuf = HdfSbufObtain(sizeof(struct LightColor) * count);
295    if (sbuf == NULL) {
296        (void)OsalMutexUnlock(&priv->mutex);
297        return HDF_DEV_ERR_NO_MEMORY;
298    }
299
300    if (!HdfSbufWriteInt32(sbuf, lightId)) {
301        HDF_LOGE("%{public}s: light write id failed", __func__);
302        ret = HDF_FAILURE;
303        goto EXIT;
304    }
305
306    if (!HdfSbufWriteInt32(sbuf, LIGHT_OPS_IO_CMD_ENABLE_MULTI_LIGHTS)) {
307        HDF_LOGE("%{public}s: light write cmd failed", __func__);
308        ret = HDF_FAILURE;
309        goto EXIT;
310    }
311
312    if (!HdfSbufWriteBuffer(sbuf, colors, sizeof(*colors))) {
313        HDF_LOGE("%{public}s: light write buf failed", __func__);
314        ret = HDF_FAILURE;
315        goto EXIT;
316    }
317
318    if (!HdfSbufWriteInt32(sbuf, count)) {
319        HDF_LOGE("%{public}s: light write count failed", __func__);
320        ret = HDF_FAILURE;
321        goto EXIT;
322    }
323
324    ret = SendLightMsg(LIGHT_IO_CMD_OPS, sbuf, NULL);
325    if (ret != HDF_SUCCESS) {
326        HDF_LOGE("%{public}s: light enable failed, ret[%{public}d]", __func__, ret);
327    }
328
329EXIT:
330    HdfSbufRecycle(sbuf);
331    (void)OsalMutexUnlock(&priv->mutex);
332
333    if (memcpy_s(&(g_lightEffect.lightColor), sizeof(g_lightEffect.lightColor),
334        colors, sizeof(*colors)) != EOK) {
335        HDF_LOGE("%{public}s: Light colors cpy faild", __func__);
336        return HDF_FAILURE;
337    }
338
339    g_lightState[lightId] = LIGHT_ON;
340
341    return ret;
342}
343
344static int32_t OffLight(uint32_t lightId)
345{
346    if (lightId >= LIGHT_ID_BUTT) {
347        HDF_LOGE("%{public}s: id not supported", __func__);
348        return HDF_FAILURE;
349    }
350
351    struct LightDevice *priv = GetLightDevicePriv();
352    (void)OsalMutexLock(&priv->mutex);
353
354    struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
355    if (msg == NULL) {
356        HDF_LOGE("%{public}s: Failed to obtain sBuf", __func__);
357        (void)OsalMutexUnlock(&priv->mutex);
358        return HDF_FAILURE;
359    }
360
361    if (!HdfSbufWriteInt32(msg, lightId)) {
362        HDF_LOGE("%{public}s: Light write id failed", __func__);
363        HdfSbufRecycle(msg);
364        (void)OsalMutexUnlock(&priv->mutex);
365        return HDF_FAILURE;
366    }
367
368    if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_DISABLE)) {
369        HDF_LOGE("%{public}s: Light write disable failed", __func__);
370        HdfSbufRecycle(msg);
371        (void)OsalMutexUnlock(&priv->mutex);
372        return HDF_FAILURE;
373    }
374
375    int32_t ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
376    if (ret != HDF_SUCCESS) {
377        HDF_LOGE("%{public}s: Light disable failed, ret[%{public}d]", __func__, ret);
378    }
379    HdfSbufRecycle(msg);
380    (void)OsalMutexUnlock(&priv->mutex);
381
382    g_lightState[lightId] = LIGHT_OFF;
383
384    return ret;
385}
386
387const struct LightInterface *NewLightInterfaceInstance(void)
388{
389    static struct LightInterface lightDevInstance;
390    struct LightDevice *priv = GetLightDevicePriv();
391
392    if (priv->initState) {
393        return &lightDevInstance;
394    }
395
396    OsalMutexInit(&priv->mutex);
397    lightDevInstance.GetLightInfo = GetLightInfo;
398    lightDevInstance.TurnOnLight = OnLight;
399    lightDevInstance.TurnOffLight = OffLight;
400    lightDevInstance.TurnOnMultiLights = OnMultiLights;
401
402    priv->ioService = HdfIoServiceBind(LIGHT_SERVICE_NAME);
403    if (priv->ioService == NULL) {
404        HDF_LOGE("%s: get light ioService failed", __func__);
405        OsalMutexDestroy(&priv->mutex);
406        return NULL;
407    }
408
409    priv->initState = true;
410    HDF_LOGI("get light devInstance success");
411
412    return &lightDevInstance;
413}
414
415int32_t FreeLightInterfaceInstance(void)
416{
417    struct LightDevice *priv = GetLightDevicePriv();
418
419    if (!priv->initState) {
420        HDF_LOGI("%s: light instance had released", __func__);
421        return HDF_SUCCESS;
422    }
423
424    priv->lightNum = 0;
425
426    if (priv->ioService != NULL) {
427        HdfIoServiceRecycle(priv->ioService);
428    }
429
430    if (priv->lightInfoEntry != NULL) {
431        OsalMemFree(priv->lightInfoEntry);
432        priv->lightInfoEntry = NULL;
433    }
434
435    OsalMutexDestroy(&priv->mutex);
436
437    return HDF_SUCCESS;
438}