/****************************************************************************** * $Id: main.c 580 2012-03-29 09:56:21Z yamada.rj $ ****************************************************************************** * * Copyright (C) 2012 Asahi Kasei Microdevices Corporation, Japan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "AKFS_Common.h" #include "AKFS_Compass.h" #include "AKFS_Disp.h" #include "AKFS_FileIO.h" #include "AKFS_Measure.h" #include "AKFS_APIs.h" #ifndef WIN32 #include <sched.h> #include <pthread.h> #include <linux/input.h> #endif #define ERROR_INITDEVICE (-1) #define ERROR_OPTPARSE (-2) #define ERROR_SELF_TEST (-3) #define ERROR_READ_FUSE (-4) #define ERROR_INIT (-5) #define ERROR_GETOPEN_STAT (-6) #define ERROR_STARTCLONE (-7) #define ERROR_GETCLOSE_STAT (-8) /* Global variable. See AKFS_Common.h file. */ int g_stopRequest = 0; int g_opmode = 0; int g_dbgzone = 0; int g_mainQuit = AKD_FALSE; /* Static variable. */ static pthread_t s_thread; /*!< Thread handle */ /*! A thread function which is raised when measurement is started. @param[in] args This parameter is not used currently. */ static void* thread_main(void* args) { AKFS_MeasureLoop(); return ((void*)0); } /*! Signal handler. This should be used only in DEBUG mode. @param[in] sig Event */ static void signal_handler(int sig) { if (sig == SIGINT) { ALOGE("SIGINT signal"); g_stopRequest = 1; g_mainQuit = AKD_TRUE; } } /*! Starts new thread. @return If this function succeeds, the return value is 1. Otherwise, the return value is 0. */ static int startClone(void) { pthread_attr_t attr; pthread_attr_init(&attr); g_stopRequest = 0; if (pthread_create(&s_thread, &attr, thread_main, NULL) == 0) { return 1; } else { return 0; } } /*! This function parse the option. @retval 1 Parse succeeds. @retval 0 Parse failed. @param[in] argc Argument count @param[in] argv Argument vector @param[out] layout_patno */ int OptParse( int argc, char* argv[], AKFS_PATNO* layout_patno) { #ifdef WIN32 /* Static */ #if defined(AKFS_WIN32_PAT1) *layout_patno = PAT1; #elif defined(AKFS_WIN32_PAT2) *layout_patno = PAT2; #elif defined(AKFS_WIN32_PAT3) *layout_patno = PAT3; #elif defined(AKFS_WIN32_PAT4) *layout_patno = PAT4; #elif defined(AKFS_WIN32_PAT5) *layout_patno = PAT5; #else *layout_patno = PAT1; #endif g_opmode = OPMODE_CONSOLE; /*g_opmode = 0;*/ g_dbgzone = AKMDATA_LOOP | AKMDATA_TEST; #else int opt; char optVal; *layout_patno = PAT_INVALID; while ((opt = getopt(argc, argv, "sm:z:")) != -1) { switch(opt){ case 'm': optVal = (char)(optarg[0] - '0'); if ((PAT1 <= optVal) && (optVal <= PAT8)) { *layout_patno = (AKFS_PATNO)optVal; AKMDEBUG(DBG_LEVEL2, "%s: Layout=%d\n", __FUNCTION__, optVal); } break; case 's': g_opmode |= OPMODE_CONSOLE; break; case 'z': /* If error detected, hopefully 0 is returned. */ errno = 0; g_dbgzone = (int)strtol(optarg, (char**)NULL, 0); AKMDEBUG(DBG_LEVEL2, "%s: Dbg Zone=%d\n", __FUNCTION__, g_dbgzone); break; default: ALOGE("%s: Invalid argument", argv[0]); return 0; } } /* If layout is not specified with argument, get parameter from driver */ if (*layout_patno == PAT_INVALID) { int16_t n; if (AKD_GetLayout(&n) == AKM_SUCCESS) { if ((PAT1 <= n) && (n <= PAT8)) { *layout_patno = (AKFS_PATNO)n; } } } /* Error */ if (*layout_patno == PAT_INVALID) { ALOGE("No layout is specified."); return 0; } #endif return 1; } void ConsoleMode(void) { /*** Console Mode *********************************************/ while (AKD_TRUE) { /* Select operation */ switch (Menu_Main()) { case MODE_SelfTest: AKFS_SelfTest(); break; case MODE_Measure: /* Reset flag */ g_stopRequest = 0; /* Measurement routine */ AKFS_MeasureLoop(); break; case MODE_Quit: return; default: AKMDEBUG(DBG_LEVEL0, "Unknown operation mode.\n"); break; } } } int main(int argc, char **argv) { int retValue = 0; AKFS_PATNO pat; uint8 regs[3]; /* Show the version info of this software. */ Disp_StartMessage(); #if ENABLE_AKMDEBUG /* Register signal handler */ signal(SIGINT, signal_handler); #endif /* Open device driver */ if(AKD_InitDevice() != AKD_SUCCESS) { retValue = ERROR_INITDEVICE; goto MAIN_QUIT; } /* Parse command-line options */ /* This function calls device driver function to get layout */ if (OptParse(argc, argv, &pat) == 0) { retValue = ERROR_OPTPARSE; goto MAIN_QUIT; } /* Self Test */ if (g_opmode & OPMODE_FST){ if (AKFS_SelfTest() != AKD_SUCCESS) { retValue = ERROR_SELF_TEST; goto MAIN_QUIT; } } /* OK, then start */ if (AKFS_ReadAK8975FUSEROM(regs) != AKM_SUCCESS) { retValue = ERROR_READ_FUSE; goto MAIN_QUIT; } /* Initialize library. */ if (AKFS_Init(pat, regs) != AKM_SUCCESS) { retValue = ERROR_INIT; goto MAIN_QUIT; } /* Start console mode */ if (g_opmode & OPMODE_CONSOLE) { ConsoleMode(); goto MAIN_QUIT; } /*** Start Daemon ********************************************/ while (g_mainQuit == AKD_FALSE) { int st = 0; /* Wait until device driver is opened. */ if (AKD_GetOpenStatus(&st) != AKD_SUCCESS) { retValue = ERROR_GETOPEN_STAT; goto MAIN_QUIT; } if (st == 0) { ALOGI("Suspended."); } else { ALOGI("Compass Opened."); /* Reset flag */ g_stopRequest = 0; /* Start measurement thread. */ if (startClone() == 0) { retValue = ERROR_STARTCLONE; goto MAIN_QUIT; } /* Wait until device driver is closed. */ if (AKD_GetCloseStatus(&st) != AKD_SUCCESS) { retValue = ERROR_GETCLOSE_STAT; g_mainQuit = AKD_TRUE; } /* Wait thread completion. */ g_stopRequest = 1; pthread_join(s_thread, NULL); ALOGI("Compass Closed."); } } MAIN_QUIT: /* Release library */ AKFS_Release(); /* Close device driver. */ AKD_DeinitDevice(); /* Show the last message. */ Disp_EndMessage(retValue); return retValue; }