1/*
2 * Copyright (C) Texas Instruments - http://www.ti.com/
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18* @file OMXDccDataSave.cpp
19*
20* This file contains functionality for handling DCC data save
21*
22*/
23
24#include "CameraHal.h"
25#include "OMXCameraAdapter.h"
26
27
28namespace Ti {
29namespace Camera {
30
31status_t OMXCameraAdapter::initDccFileDataSave(OMX_HANDLETYPE* omxHandle, int portIndex)
32{
33    OMX_CONFIG_EXTRADATATYPE extraDataControl;
34    status_t ret = NO_ERROR;
35    OMX_ERRORTYPE eError = OMX_ErrorNone;
36
37    LOG_FUNCTION_NAME;
38
39    OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE);
40    extraDataControl.nPortIndex = portIndex;
41    extraDataControl.eExtraDataType = OMX_TI_DccData;
42    extraDataControl.bEnable = OMX_TRUE;
43
44    eError =  OMX_SetConfig(*omxHandle,
45                        ( OMX_INDEXTYPE ) OMX_IndexConfigOtherExtraDataControl,
46                        &extraDataControl);
47
48    if ( OMX_ErrorNone != eError )
49        {
50        CAMHAL_LOGEB("Error while configuring dcc data overwrite extra data 0x%x",
51                    eError);
52
53        ret =  NO_INIT;
54        }
55
56    if (mDccData.pData) {
57        free(mDccData.pData);
58        mDccData.pData = NULL;
59    }
60    LOG_FUNCTION_NAME_EXIT;
61
62    return ret;
63}
64
65status_t OMXCameraAdapter::sniffDccFileDataSave(OMX_BUFFERHEADERTYPE* pBuffHeader)
66{
67    OMX_OTHER_EXTRADATATYPE *extraData;
68    OMX_TI_DCCDATATYPE* dccData;
69    status_t ret = NO_ERROR;
70
71    LOG_FUNCTION_NAME;
72
73    android::AutoMutex lock(mDccDataLock);
74
75    if ( NULL == pBuffHeader ) {
76        CAMHAL_LOGEA("Invalid Buffer header");
77        LOG_FUNCTION_NAME_EXIT;
78        return -EINVAL;
79    }
80
81    extraData = getExtradata(pBuffHeader->pPlatformPrivate,
82                             (OMX_EXTRADATATYPE)OMX_TI_DccData);
83
84    if ( NULL != extraData ) {
85        CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x",
86                     extraData->nSize,
87                     sizeof(OMX_OTHER_EXTRADATATYPE),
88                     extraData->eType,
89                     extraData->nDataSize,
90                     extraData->nPortIndex,
91                     extraData->nVersion);
92    } else {
93        CAMHAL_LOGVA("Invalid OMX_TI_DCCDATATYPE");
94        LOG_FUNCTION_NAME_EXIT;
95        return NO_ERROR;
96    }
97
98    dccData = ( OMX_TI_DCCDATATYPE * ) extraData->data;
99
100    if (NULL == dccData) {
101        CAMHAL_LOGVA("OMX_TI_DCCDATATYPE is not found in extra data");
102        LOG_FUNCTION_NAME_EXIT;
103        return NO_ERROR;
104    }
105
106    if (mDccData.pData) {
107        free(mDccData.pData);
108    }
109
110    memcpy(&mDccData, dccData, sizeof(mDccData));
111
112    int dccDataSize = (int)dccData->nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData));
113
114    mDccData.pData = (OMX_PTR)malloc(dccDataSize);
115
116    if (NULL == mDccData.pData) {
117        CAMHAL_LOGVA("not enough memory for DCC data");
118        LOG_FUNCTION_NAME_EXIT;
119        return NO_ERROR;
120    }
121
122    memcpy(mDccData.pData, &(dccData->pData), dccDataSize);
123
124    LOG_FUNCTION_NAME_EXIT;
125
126    return ret;
127}
128
129// Recursively searches given directory contents for the correct DCC file.
130// The directory must be opened and its stream pointer + path passed
131// as arguments. As this function is called recursively, to avoid excessive
132// stack usage the path param is reused -> this MUST be char array with
133// enough length!!! (260 should suffice). Path must end with "/".
134// The directory must also be closed in the caller function.
135// If the correct camera DCC file is found (based on the OMX measurement data)
136// its file stream pointer is returned. NULL is returned otherwise
137FILE * OMXCameraAdapter::parseDCCsubDir(DIR *pDir, char *path)
138{
139    FILE *pFile;
140    DIR *pSubDir;
141    struct dirent *dirEntry;
142    int initialPathLength = strlen(path);
143
144    LOG_FUNCTION_NAME;
145
146    /* check each directory entry */
147    while ((dirEntry = readdir(pDir)) != NULL)
148    {
149        if (dirEntry->d_name[0] == '.')
150            continue;
151
152        strcat(path, dirEntry->d_name);
153        // dirEntry might be sub directory -> check it
154        pSubDir = opendir(path);
155        if (pSubDir) {
156            // dirEntry is sub directory -> parse it
157            strcat(path, "/");
158            pFile = parseDCCsubDir(pSubDir, path);
159            closedir(pSubDir);
160            if (pFile) {
161                // the correct DCC file found!
162                LOG_FUNCTION_NAME_EXIT;
163                return pFile;
164            }
165        } else {
166            // dirEntry is file -> open it
167            pFile = fopen(path, "rb");
168            if (pFile) {
169                // now check if this is the correct DCC file for that camera
170                OMX_U32 dccFileIDword;
171                OMX_U32 *dccFileDesc = (OMX_U32 *) &mDccData.nCameraModuleId;
172                int i;
173
174                // DCC file ID is 3 4-byte words
175                for (i = 0; i < 3; i++) {
176                    if (fread(&dccFileIDword, sizeof(OMX_U32), 1, pFile) != 1) {
177                        // file too short
178                        break;
179                    }
180                    if (dccFileIDword != dccFileDesc[i]) {
181                        // DCC file ID word i does not match
182                        break;
183                    }
184                }
185
186                fclose(pFile);
187                if (i == 3) {
188                    // the correct DCC file found!
189                    CAMHAL_LOGDB("DCC file to be updated: %s", path);
190                    // reopen it for modification
191                    pFile = fopen(path, "rb+");
192                    if (!pFile)
193                        CAMHAL_LOGEB("ERROR: DCC file %s failed to open for modification", path);
194                    LOG_FUNCTION_NAME_EXIT;
195                    return pFile;
196                }
197            } else {
198                CAMHAL_LOGEB("ERROR: Failed to open file %s for reading", path);
199            }
200        }
201        // restore original path
202        path[initialPathLength] = '\0';
203    }
204
205    LOG_FUNCTION_NAME_EXIT;
206
207    // DCC file not found in this directory tree
208    return NULL;
209}
210
211// Finds the DCC file corresponding to the current camera based on the
212// OMX measurement data, opens it and returns the file stream pointer
213// (NULL on error or if file not found).
214// The folder string dccFolderPath must end with "/"
215FILE * OMXCameraAdapter::fopenCameraDCC(const char *dccFolderPath)
216{
217    FILE *pFile;
218    DIR *pDir;
219    char dccPath[260];
220
221    LOG_FUNCTION_NAME;
222
223    strcpy(dccPath, dccFolderPath);
224
225    pDir = opendir(dccPath);
226    if (!pDir) {
227        CAMHAL_LOGEB("ERROR: Opening DCC directory %s failed", dccPath);
228        LOG_FUNCTION_NAME_EXIT;
229        return NULL;
230    }
231
232    pFile = parseDCCsubDir(pDir, dccPath);
233    closedir(pDir);
234    if (pFile) {
235        CAMHAL_LOGDB("DCC file %s opened for modification", dccPath);
236    }
237
238    LOG_FUNCTION_NAME_EXIT;
239
240    return pFile;
241}
242
243// Positions the DCC file stream pointer to the correct offset within the
244// correct usecase based on the OMX mesurement data. Returns 0 on success
245status_t OMXCameraAdapter::fseekDCCuseCasePos(FILE *pFile)
246{
247    OMX_U32 dccNumUseCases = 0;
248    OMX_U32 dccUseCaseData[3];
249    OMX_U32 i;
250
251    LOG_FUNCTION_NAME;
252
253    // position the file pointer to the DCC use cases section
254    if (fseek(pFile, 80, SEEK_SET)) {
255        CAMHAL_LOGEA("ERROR: Unexpected end of DCC file");
256        LOG_FUNCTION_NAME_EXIT;
257        return -EINVAL;
258    }
259
260    if (fread(&dccNumUseCases, sizeof(OMX_U32), 1, pFile) != 1 ||
261        dccNumUseCases == 0) {
262        CAMHAL_LOGEA("ERROR: DCC file contains 0 use cases");
263        LOG_FUNCTION_NAME_EXIT;
264        return -EINVAL;
265    }
266
267    for (i = 0; i < dccNumUseCases; i++) {
268        if (fread(dccUseCaseData, sizeof(OMX_U32), 3, pFile) != 3) {
269            CAMHAL_LOGEA("ERROR: Unexpected end of DCC file");
270            LOG_FUNCTION_NAME_EXIT;
271            return -EINVAL;
272        }
273
274        if (dccUseCaseData[0] == mDccData.nUseCaseId) {
275            // DCC use case match!
276            break;
277        }
278    }
279
280    if (i == dccNumUseCases) {
281        CAMHAL_LOGEB("ERROR: Use case ID %lu not found in DCC file", mDccData.nUseCaseId);
282        LOG_FUNCTION_NAME_EXIT;
283        return -EINVAL;
284    }
285
286    // dccUseCaseData[1] is the offset to the beginning of the actual use case
287    // from the beginning of the file
288    // mDccData.nOffset is the offset within the actual use case (from the
289    // beginning of the use case to the data to be modified)
290
291    if (fseek(pFile,dccUseCaseData[1] + mDccData.nOffset, SEEK_SET ))
292    {
293        CAMHAL_LOGEA("ERROR: Error setting the correct offset");
294        LOG_FUNCTION_NAME_EXIT;
295        return -EINVAL;
296    }
297
298    LOG_FUNCTION_NAME_EXIT;
299
300    return NO_ERROR;
301}
302
303status_t OMXCameraAdapter::saveDccFileDataSave()
304{
305    status_t ret = NO_ERROR;
306
307    LOG_FUNCTION_NAME;
308
309    android::AutoMutex lock(mDccDataLock);
310
311    if (mDccData.pData)
312        {
313        FILE *fd = fopenCameraDCC(DCC_PATH);
314
315        if (fd)
316            {
317            if (!fseekDCCuseCasePos(fd))
318                {
319                int dccDataSize = (int)mDccData.nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData));
320
321                if (fwrite(mDccData.pData, dccDataSize, 1, fd) != 1)
322                    {
323                    CAMHAL_LOGEA("ERROR: Writing to DCC file failed");
324                    }
325                else
326                    {
327                    CAMHAL_LOGDA("DCC file successfully updated");
328                    }
329                }
330            fclose(fd);
331            }
332        else
333            {
334            CAMHAL_LOGEA("ERROR: Correct DCC file not found or failed to open for modification");
335            }
336        }
337
338    LOG_FUNCTION_NAME_EXIT;
339
340    return ret;
341}
342
343status_t OMXCameraAdapter::closeDccFileDataSave()
344{
345    status_t ret = NO_ERROR;
346
347    LOG_FUNCTION_NAME;
348
349    android::AutoMutex lock(mDccDataLock);
350
351    if (mDccData.pData) {
352        free(mDccData.pData);
353        mDccData.pData = NULL;
354    }
355    LOG_FUNCTION_NAME_EXIT;
356
357    return ret;
358}
359
360} // namespace Camera
361} // namespace Ti
362