/*
* Copyright 2012 The Android Open Source Project
*
* 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 <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#define LOG_TAG "bdAddrLoader"
#include <cutils/log.h>
#include <cutils/properties.h>
#define FILE_PATH_MAX 100
#define BD_ADDR_LEN 6
#define BD_ADDR_STR_LEN 18
#define ARG_TYPE_PATH_FILE 0x11
#define ARG_TYPE_PATH_PROP 0x12
#define ARG_TYPE_DATA_HEX 0x21
#define ARG_TYPE_DATA_ASCII 0x22
typedef struct _ArgEl
{
const char *szSrc; // Source Path
int nPathType; // Type of Source Path
int nDataType; // Type of Data
}ArgEl;
typedef ArgEl InArg;
#define DEFAULT_BDADDR_PROP "persist.service.bdroid.bdaddr"
typedef struct _OutArg
{
ArgEl dest;
char cSeperator; // a character to be used for sperating like ':' of "XX:XX:XX:XX:XX:XX"
char bPrintOut; // Print out bd addr in standard out or not
}OutArg;
typedef struct _LoadedData
{
union {
unsigned char bin[BD_ADDR_LEN];
char sz[BD_ADDR_STR_LEN];
}data;
int nDataType;
}LoadedBDAddr;
typedef enum _res
{
SUCCESS = 0,
FAIL
}Res;
int hexa_to_ascii(const unsigned char* hexa, char* ascii, int nHexLen)
{
int i, j;
char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
for (i = 0, j = 0; i <nHexLen; i++, j += 2) {
ascii[j] = hex_table[hexa[i] >> 4];
ascii[j + 1] = hex_table[hexa[i] & 0x0F];
}
ascii[nHexLen*2] = '\0';
ALOGI("hex_to_ascii() - converted Data (%s)", ascii);
return SUCCESS;
}
int readBDAddrData(const char* szFilePath, unsigned char* addrData, int nDataLen)
{
int nFd, nRdCnt;
nFd = open(szFilePath, O_RDONLY);
if(nFd < 0){
ALOGW("There is no Address File in FTM area : %s\n", szFilePath);
return FAIL;
}
nRdCnt = read(nFd, addrData, nDataLen);
if(nRdCnt != nDataLen){
ALOGE("Fail to read Address data from FTM area\n");
close(nFd);
return FAIL;
}
close(nFd);
return SUCCESS;
}
void formattingBdAddr(char *szBDAddr, const char cSep)
{
int i=1, j=0;
int pos=0;
for(i=1; i<BD_ADDR_LEN; i++){
pos = strlen(szBDAddr);
for(j=0; j<(BD_ADDR_LEN*2)-i*2; j++){
szBDAddr[pos-j] = szBDAddr[pos-j-1];
}
szBDAddr[pos-j]=cSep;
}
}
int readBDAddr(InArg inArg, LoadedBDAddr *loadedBDAddr)
{
Res res = FAIL;
unsigned char addrData[BD_ADDR_LEN] = {0,};
int nDataLen = 0;
ALOGI("Read From %s by Path type(0x%2x), Data type (0x%2x)", inArg.szSrc, inArg.nPathType, inArg.nDataType);
if(inArg.nPathType == ARG_TYPE_PATH_FILE){
switch(inArg.nDataType){
case ARG_TYPE_DATA_HEX:
if(!readBDAddrData(inArg.szSrc, loadedBDAddr->data.bin, BD_ADDR_LEN)){
loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX;
return SUCCESS;
}
break;
case ARG_TYPE_DATA_ASCII:
if(!readBDAddrData(inArg.szSrc, (unsigned char *)loadedBDAddr->data.sz, BD_ADDR_STR_LEN)){
loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII;
return SUCCESS;
}
break;
default:
return FAIL;
}
}else if(inArg.nPathType == ARG_TYPE_PATH_PROP){
char prop_value[PROPERTY_VALUE_MAX];
switch(inArg.nDataType){
case ARG_TYPE_DATA_HEX:
if(property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_LEN){
strlcpy((char *)loadedBDAddr->data.bin, prop_value, BD_ADDR_LEN);
loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX;
return SUCCESS;
}
break;
case ARG_TYPE_DATA_ASCII:
if(property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_STR_LEN){
strlcpy(loadedBDAddr->data.sz, prop_value, BD_ADDR_STR_LEN);
loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII;
return SUCCESS;
}
break;
default:
return FAIL;
}
}else{
ALOGE("Error invalid argument : (%d)", inArg.nPathType);
}
ALOGE("Fail to read BDAddr from %s", inArg.szSrc);
return FAIL;
}
int writeBDAddr(OutArg outArg, LoadedBDAddr *loadedBDAddr)
{
char szTmp[BD_ADDR_STR_LEN] = {0,};
ALOGI("Output Data type(0x%2x), bPrintout(%d), bPath(%s)",
outArg.dest.nDataType, outArg.bPrintOut, outArg.dest.szSrc);
ALOGI("Loaded Data type(0x%2x)", loadedBDAddr->nDataType);
if(outArg.dest.nDataType == ARG_TYPE_DATA_ASCII
&& loadedBDAddr->nDataType == ARG_TYPE_DATA_HEX
){
if(!hexa_to_ascii(loadedBDAddr->data.bin, szTmp, BD_ADDR_LEN)){
memcpy(loadedBDAddr->data.sz, szTmp, BD_ADDR_STR_LEN);
loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII;
}
else{
ALOGE("Fail to convert data");
return FAIL;
}
}
if(loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII){
// check out which addr data is already formated
if(strchr(loadedBDAddr->data.sz, '.') == NULL
&& strchr(loadedBDAddr->data.sz, ':') == NULL
){
formattingBdAddr(loadedBDAddr->data.sz, outArg.cSeperator);
}
}
// print out szBDAddr
if(outArg.bPrintOut
&& loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII
&& strlen(loadedBDAddr->data.sz)==(BD_ADDR_STR_LEN-1)) {
printf("%s",loadedBDAddr->data.sz);
if (property_set(DEFAULT_BDADDR_PROP, loadedBDAddr->data.sz) < 0)
ALOGE("Failed to set address in prop %s", DEFAULT_BDADDR_PROP);
}
else{
ALOGE("Invalid Data is loaded : %s", loadedBDAddr->data.sz);
return FAIL;
}
// TODO :: writing File or Property
return SUCCESS;
}
int main(int argc, char *argv[])
{
int nFd, nRdCnt;
int c;
InArg inArg;
OutArg outArg;
LoadedBDAddr loadedBDAddr;
//initialize arg
memset(&inArg, 0, sizeof(InArg));
memset(&outArg, 0, sizeof(OutArg));
memset(&loadedBDAddr, 0, sizeof(LoadedBDAddr));
//load args;
while((c=getopt(argc, argv, ":f:p:hsx")) != -1){
switch(c){
case 'f': // input path
if(optarg != NULL){
ALOGI("option : f=%s", optarg);
inArg.szSrc = optarg;
}else{
ALOGW("Invalid Argument(%s) of input path", optarg);
}
inArg.nPathType = ARG_TYPE_PATH_FILE;
break;
case 'p': // output path
if(optarg != NULL){
ALOGI("option : p=%s", optarg);
inArg.szSrc = optarg;
}else{
ALOGW("Invalid Argument(%s) of out Path", optarg);
}
inArg.nPathType = ARG_TYPE_PATH_PROP;
break;
case 'h': // data type to be read is hex
ALOGI("option : h");
inArg.nDataType = ARG_TYPE_DATA_HEX;
break;
case 's': // data type to be read is ascii
ALOGI("option : s");
inArg.nDataType = ARG_TYPE_DATA_ASCII;
break;
case 'x':
ALOGI("option : x");
outArg.bPrintOut = 1; //true
break;
default:
ALOGW("Unknown option : %c", c);
break;
}
}
// setting up Arguments with default value
outArg.cSeperator = ':';
outArg.dest.nDataType = ARG_TYPE_DATA_ASCII;
// load bd addr and print out bd addr in formated ascii
if(readBDAddr(inArg, &loadedBDAddr)){
ALOGE("Fail to load data !!");
return FAIL;
}
if(writeBDAddr(outArg, &loadedBDAddr)){
ALOGE("Fail to write data !!");
return FAIL;
}
return 1;
}