微信公众号:morixinguan

关注可了解更多的教程。问题或建议,请公众号留言;

如果你觉得本文对你有帮助,欢迎赞赏

▲长按图片保存可分享至朋友圈

在MTK的机器中,如果不用特定的工具烧写MAC地址,在开机后打开WIFI后会显示: “NVRAM WARNING: Err=0x10” 这就是没有烧写mac地址的原因,所以每次打开wifi,wifi的MAC地址都是一个随机产生的值,为什么会这样?

答案在:

ndor/mediatek/proprietary/packages/apps/CdsInfo/src/com/mediatek/connnectivity/CdsWifiInfoActivity.java

源码描述如下:

public class CdsWifiInfoActivity extends Activity{ private static final StringTAG= "CDSINFO/WifiInfo"; private static final int MAC_ADDRESS_ID= 30; private static final int MAC_ADDRESS_DIGITS= 6; private static final int MAX_ADDRESS_VALUE= 0xff; private static final int INVALID_RSSI=-200; //定义了MAC地址存储的文件的绝对路径 private static final StringMAC_ADDRESS_FILENAME= "/data/nvram/APCFG/APRDEB/WIFI"; private static final String[]WIFI_SYSTEM_PROPERTY= new String[]{ "net.hostname", "dhcp.wlan0.ipaddress", "net.dns1", "net.dns2", 。。。。

以下是获取mac地址的方法:

//获取mac地址的方法 private void getMacAddr(){ try { tService("NvRAMAgent"); MAgent.Stub.asInterface(binder); new short[MAC_ADDRESS_DIGITS]; if (mUserMode){ l.setVisibility(View.GONE); AddrEdit.setVisibility(View.GONE); etVisibility(View.GONE); else { new StringBuilder(); new Random(); atter= new DecimalFormat("00"); int end1=rand.nextInt(100); int end2=rand.nextInt(100); ringnum2=formatter.format(end2); //这几位是固定的值 "00:08:22:11:"); ":").append(num2); drLabel.setVisibility(View.VISIBLE); out.println("stringbuffer:" +sb); dom=sb.toString(); catch (Exceptione){

更新mac地址的方法:

//更新mac地址 private void updateMacAddr(){ try { int i= 0; r.getService("NvRAMAgent"); ; //parsemacaddressfirstly okenizertxtBuffer= new StringTokenizer(mMacAddrEdit.getText().toString(), ":"); while (txtBuffer.hasMoreTokens()){ (short)Integer.parseInt(txtBuffer.nextToken(), 16); out.println(i+ ":" +mRandomMacAddr[i]); if (i!= 6){ "Theformatofmacaddressisnotcorrect"); return; byte[]buff= null; try { eadFileByName(MAC_ADDRESS_FILENAME); catch (Exceptione){ ); //随机产生的buff[i+4]开始就是mac地址存储的位置 for (i= 0;i34 buff[i+ 4]=(byte)mRandomMacAddr[i]; int flag= 0; try { catch (Exceptione){ intStackTrace(); if (flag> 0){ "Updatesuccessfully.rnPleaserebootthisdevice"); else { ext("Updatefailed"); catch (Exceptione){ ":" +e.getCause());

从这个代码中可以分析得知,此时的Wifi MAC地址除了前面几位是固定值,而后面都是随机产生的。 但只有一个文件才是正确的WIFI MAC地址保存的值。如果没有烧写WIFI MAC地址,那么这个文件的第4到第9个字节是固定为0的,只有烧写了MAC地址,这6个字节才是有数据的。 通过代码分析,得知烧写mac地址后的文件是保存在: /data/nvram/APCFG/APRDEB/WIFI 这个文件中。

通过adb pull /data/nvram/APCFG/APRDEB/WIFI获取这个文件到我当前的系统,打开一看:

是一堆乱码,那么如何正确打开查看呢?可以上百度去下一个WinHex打开,其实这个文件里面保存的是十六进制的数据。打开后可以看到:

从这段数据中:,格式是这样的:04 01 00 00 CC 79 CF FF 35 54 44 。。偏移从0开始一直往后依次类推,分析代码得知:

CC 79 CF FF 35 54 44就是通过特定工具刷写进去的WIFI MAC地址,如果不刷,那么这6个字节的数据默认为0。关于这个表,我们可以参考MTK的文档得知:

NVRAM在EMMC中是只读数据,一般存储在data分区中,所以格式化机器是会将NVRAM中的数据擦除的。

当然Nvram中不止存放wifi的MAC地址,也存放Gsensor校准的数据,这点以后我们再来写怎么获取。

下面就是NVRAM,WIFI的春初数值对应的。

我的机器上对应的是MT6628这个驱动模块,所以是下面这个宏:

在MAC地址没有刷写的时候,默认的6个字节都是0x00。

#if defined(MT6628) stWifiCfgDefault= 0x0104, /*OwnVersionForMT6628*/ 0x0000, /*PeerVersion*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /*MACADDRESS*/ ........................

现在我们可以写一个程序将它读出来,很简单:

#include #include #include #include #include #define WIFI_FILE "WIFI" int main(void){ int fd= -1 ; int ret; int i; char buffer[512]={0}; char Nvram_wifi_mac_address[6]={0}; char d_buf[100]={0}; char dd_buf[100]={0}; E,O_RDWR); if(fd0){ printf("openfair!n"); return -1 ; 512); if(ret0){ printf("readwifimacfair!n"); for(i= 4;i10 ;i++) am_wifi_mac_address[i-4]=buffer[i]; //为什么要&0xff,因为有些机器是64位的,为了保证和32位的机器显示一致,故只取低8位。 sprintf(d_buf,"%02x:%02x:%02x:%02x:%02x:%02x", ddress[0]&0xff,Nvram_wifi_mac_address[1]&0xff, 2]&0xff,Nvram_wifi_mac_address[3]&0xff, 4]&0xff,Nvram_wifi_mac_address[5]&0xff printf("%sn",d_buf); for(i= 0 ;istrlen(d_buf);i++) _buf[i]= toupper(d_buf[i]); //字符串中小写转大写 printf("dd_buf:%sn",dd_buf); return 0 ;

MTKAndroid系统的Gsensor校准的数据其实也是存储在NVRAM中的,Gsensor隶属于传感器系统架构。

接下来我们来看下Gsensor校准的基准图像:

那么如何来校准Gsensor的X,Y,Z三个方向呢?我们可以参考MTK提供的工厂测试factroymode的代码:

位置在:vendormediatekproprietaryfactorysrctestftm_gs_cali.c ftm_gsensor.c

ftm_gs_cali.c就是校准的源码,我们可以打开来看看它具体的实现原理:

在ftm_gs_cali.c的static void*gs_cali_update_iv_thread(void *priv)这个函数中,我们可以分析得知如何校准Gsensor数值的过程,由于源码太长,这里只说流程:

(1) 打开Gsensor

(2) 使能Gsensor

(3) 执行校准的动作

(4) 设置校准的Cail,让校准的数据生效

(5) 将校准得到的数据写入到nvram中

(6) 关闭Gsensor

核心流程我们已经清楚了,那么接下来如何来写这个程序呢?我们要弄明白,这些函数上哪个文件里去找这是第一步:

通过grep命令搜索相关函数,最终确定,这些函数的头文件在:

./pskyed/libs/em_emmc_comm/libhwm/include/libhwm.h这里,在这个头文件中有相关的函数可以给我们使用:

extern int gsensor_calibration(int fd, int period, int count, int tolerance, int trace,HwmData*cali); extern int gsensor_write_nvram(HwmData*dat); extern int gsensor_read_nvram(HwmData*dat); extern int gsensor_rst_cali(int fd); extern int gsensor_set_cali(int fd,HwmData*dat); extern int gsensor_get_cali(int fd,HwmData*dat); extern int gsensor_read(int fd,HwmData*dat); extern int gsensor_init(int fd); extern int gsensor_close(int fd); extern int gsensor_open(int *fd); extern int gyroscope_calibration(int fd, int period, int count, int tolerance, int trace,HwmData*cali); extern int gyroscope_write_nvram(HwmData*dat); extern int gyroscope_read_nvram(HwmData*dat); extern int gyroscope_rst_cali(int fd); extern int gyroscope_set_cali(int fd,HwmData*dat); extern int gyroscope_get_cali(int fd,HwmData*dat); extern int gyroscope_read(int fd,HwmData*dat); extern int gyroscope_close(int fd); extern int gyroscope_open(int *fd); extern int gyroscope_init(int fd);

那么这些函数的源码在哪里呢?源码是没有的,因为MTK厂商将这部分代码给封装成了so动态库文件,所以,我们需要找到这个头文件对应的so文件,这样我们才能使用这个头文件,调用到so动态库中的函数。

通过搜索得知,这个so动态库文件在以下路径:

./pskyed/libs/em_emmc_comm/libhwm/libhwm.so

知道这些以后,下面我们就可以写一个简单的程序来验证这个过程了,这个留给读者自己去测试,接口我已经写好了,我的项目源码不便于公开,请读者自己拿去修改验证,流程是一样的,接口没有改过,至于想实现什么样的效果请读者自己去尝试添加,移植我的程序进行修改。

下面实现这个校准程序:

gs_cali.c

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Keypad.h" #include "libhwm.h" #define GSENSOR_NAME "/dev/gsensor" #define OPEN_FILE_FAIR-1 #define OPEN_SUCCESS0 #define RETURE_SUCCESS0 #define ENABLED_SUCCESS0 #define GSENSOR_CALIBRATION_SUCCESS0 #define ENABLED_FAIR-2 #define CALIBRATION_FAIR-3 #define SET_CALIBRATION_FAIR-4 #define WRITE_NVRAM_FAIR-5 int gs_fd; //打开gsensor int gs_open(char *gs_name); //关闭gsensor int gs_close(int fd); //gsensor开始工作 int gs_enable(unsigned int command); //校准gsensor int gs_calibration(unsigned int cali_delay,unsigned int cali_num,unsigned int cali_tolerance); int main(void){ int gs_ret= 0 ; int cali_delay= 50; int cali_num= 20; //这里的20表示把校准的数值做20次平均 //如果想要更精确,也可以做40次平均计算 int cali_tolerance= 20 ; //40 //打开gsensor SENSOR_NAME); if(gs_ret!= 0){ printf("gsopenfair!n"); return -1 ; //使能gsensor if(gs_ret!= 0){ printf("gsenablefair!n"); return -2 ; //校准---->包括:执行校准的动作、设置校准数值、将校准数值写入nvram _calibration(cali_delay,cali_num,cali_tolerance); if(gs_ret!= 0){ printf("gs_calibrationfair!n"); return -3 ; //关闭gsensor if(gs_ret!= 0){ printf("gs_closefair!n"); return -4 ; printf("runexeccallgsensorCalibrateendn"); return 0 ; //1、open int gs_open(char *gs_name){ _name,O_RDONLY); if(gs_fd0) printf("opengsensordevfair!n"); return OPEN_FILE_FAIR; printf("gsensoropensuccess!n"); return OPEN_SUCCESS; //2、enablegsensor int gs_enable(unsigned int command){ int err= 0; unsigned int flags= 1; int max_retry= 3,retry_period= 100,retry=0; while ((err=ioctl(gs_fd,command,&flags))&&(retry++ 99 usleep(retry_period*1000); if (err){ printf("enableg-sensorfail:%s",strerror(errno)); return ENABLED_FAIR; printf("enablegsensorsuccess!n"); return ENABLED_SUCCESS; //3、校准 int gs_calibration(unsigned int cali_delay,unsigned int cali_num,unsigned cali_tolerance){ int err; int flag= 0; //dat.xdat.ydat.z Datacali; while(1) //执行校准的动作 0 ,&cali); if(err!= 0) printf("calibrateacc:%dn",err); return CALIBRATION_FAIR; //设置校准cali,让校准数据生效 if(err!= 0) printf("setcalibrationfail:(%s)%dn",strerror(errno),err); return SET_CALIBRATION_FAIR; //将校准数据写入nvram中 nvram(&cali); if(err!= 0) printf ("writenvramfail:(%s)%dn",strerror(errno),err); return WRITE_NVRAM_FAIR; ag= 1 ; if(flag== 1) printf("Gsensorcalibratesuccess!n"); break ; return GSENSOR_CALIBRATION_SUCCESS; //关闭 int gs_close(int fd){ return 0 ;

然后写一个简单的Android.mk

$(call my-dir) include $(CLEAR_VARS) tional include $(BUILD_EXECUTABLE)

将.c和Android.mk一并放在external下的一个自己定义的文件夹中,比如gs_cali文件夹,然后最后编译会在out目录下生成gsensor_calibrate这个二进制文件。

特别需要注意一点:使用这种方法进行校准后,需要将gsensor驱动的自动校准功能屏蔽,具体屏蔽方法还需要分析驱动源代码。

但这仅仅只是校准数值而已,如何把校准完的数值读出来呢?参考ftm_gsensor.c这个文件源代码,最终得知是通过打开/dev/gsensor这个节点,然后通过总线访问机制获取:

/sys/bus/platform/drivers/gsensor/sensordata这个文件存放的数据。

读取Gsensor的x,y,z的数据的方法可以参考static int gsensor_read(struct acc_priv *acc)这个函数的实现方法,但它的方法和我的是有区别的,MTK中实现的gsensor_read方法是读取从驱动中读取已经转化成十进制的数据,而我读取的是原始数据十六进制,所以必须要做进制转换,我们可以来看下这个函数:

static intgsensor_read(structacc_priv*acc) static charbuf[128]; if(acc->fd== -1) "invalidfiledescriptorn"); else if((acc->support_selftest== 1)&&(!acc->selftest)&&(err=gsensor_selftest(acc, 10, 20))) "selftestfail:%s(%d)n",strerror(errno),errno); else //使用GSENSOR_IOCTL_READ_SENSORDATA命令获取sensor的数据,并存储在buf里 SENSOR_IOCTL_READ_SENSORDATA,buf); if(err) "readdatafail:%s(%d)n",strerror(errno),errno); //从buf中将x,y,z三个值取出来 else if(3 !=sscanf(buf, "%x%x%x",&x,&y,&z)) "readformatfail:%s(%d)n",strerror(errno),errno); else //除以1000,并转成浮点数 >evt.x=(float)(x)/1000; at)(y)/1000; 1000; rr= 0; or_statistic(acc); //返回gsensor数据 //addsensordatatostructsp_ata_dataforPCside x=acc->evt.x; sensor.g_sensor_y=acc->evt.y; .z; eturn_data.gsensor.accuracy= 3; return err;

预知详情,可以去分析MTK factory工厂测试的源码,看看具体实现,这里就简单的一笔带过了。

当然我们也可以采用:

./pskyed/libs/em_emmc_comm/libhwm/include/libhwm.h这里面的读取gsensor数据的接口,如果要用就需要在Android.mk中包含相关的动态库。

使用adb进入Android根文件系统,此时,通过cat命令可以得知/sys/bus/platform/drivers/gsensor/sensordata这个文件存放的数据并不是字符串,而是十六进制数据,以下是机器平放在桌子上读取的x,y,z的数值:

Sensordata文件的数值: 算法转换:

x,y,z数值的校准范围是(0,0,9.8),以上数值说明机器校准后的数值是正确的,误差比较小。

在Window上用Notepad++打开这个文件看到里面的数据如下。

以下是我实现的方法:

//Gsensor读取

//这个文件存放的数据不是字符串,而是十六进制数据,所以必须做进制转换,然后才能转成浮点数

#define GSENSOR_NAME"/sys/bus/platform/drivers/gsensor/sensordata" //存储gsensor节点数据的结构体 struct gsensor_info //x,y,z坐标值 char x[10]; char y[10]; char z[10]; int Hex_to_dec(const char*str); static int check_flag; int Gsensor_Test(){ struct gsensor_infog; char ln[80];//用于存取读出数据的数组 int i,n; char *p; int x,y,z; float x1,y1,z1; int xv= 0 ,yv= 0 ,zv= 0 ; while(1) "r");//打开txt文件 if(NULL==f){ "Cannotopenfilesensordata!n");//判断是否可以打开文件 return 1; 0; while (1) //从文件中读取一行数据 if (NULL==fgets(ln,80,f)) break; "%s%s%s",g.x,g.y,g.z); //存储的数据是十六进制,需要做数据转换 float)x/ 1000 ; float)y/ 1000 ; float)z/ 1000 ; "x:%4.2fy:%4.2fz:%4.2fn",x1,y1,z1); break ; return 0 ; while(1); //16进制转10进制算法实现 int Hex_to_dec(const char*str){ int value; if (!str) return 0; value = 0; while (1) if ((*str>= '0')&&(*str'9')) value = value*16 +(*str- '0'); else if ((*str>= 'A')&&(*str'F')) value = value*16 +(*str- 'A')+ 10; else if ((*str>= 'a')&&(*str'f')) value = value*16 +(*str- 'a')+ 10; else break; return value;

长期服务:

android nvram读写,MTK Android平台Nvram与Gensor数据获取相关推荐

  1. Android单元测试读写文件,Android Studio单元测试:读取数据(输入)文件

    根据android-gradle-plugin版本: 1.版本1.5和更高版本: 只需把json文件到src / test / resources / test.json并引用它 classLoade ...

  2. android 工程模式mtk,Android L版本上user版本工程模式中gsensor校准失败

    [DESCRIPTION] 工程模式中gsensor的校准需要用到em_svr这个service,但是因为build选项的原因,在user编译时,这段code没有被build,导致user版本工程模式 ...

  3. android otg读写文件,Android USB Host在USB设备OTG中读/写文件

    我正在编写Android设备是主机的应用程序.用户将USB驱动器连接到Android设备,我的应用程序将在USB驱动器中写入一些文本文件.文本文件的路径就像USB_DRIVE/Data/APP_NAM ...

  4. mtk android 编译过程,MTK android 快速编译方法.doc

    . . [FAQ10625] 提升Android编译速度 Platform: MT6572 MT6582 MT6588 MT6589 MT6592 MT6595 MT6571 MT6582/92+MT ...

  5. android usb读写,安卓(Android)下如何开发USB NFC读写器app

    对安卓工程师来说,在安卓下使用USB设备需要了解很多硬件的内容,这可能会导致工程周期的延长或者app的不稳定.为了将这种风险降到最低,友我科技发布了NFC读写器在安卓下的sdk,使用NFC读写器的类接 ...

  6. android gsensor 坐标,MTK Android G sensor 原理,配置,调试

    原理图: g_sensor的驱动目录在mediatek/custom/common/kernel/accelerometer下. 一.g_sensor 的移植步骤 1.在ProjectConfig.m ...

  7. android studio读写txt,Android Studio从.txt文件读取/写入,保存路径?

    我有这2种方法在我的MainActivity(只是测试,看看如何读取和/写入到文件中的作品): public void WriteBtn() { // add-write text into file ...

  8. mtk android关机铃声,mtk android power key 长按8s 关机功能实现

    该功能是系统启动后,在任何情况下,长按power key 8s都能做到直接关机.因此在kernel中实现. 所有修改都在keypad driver中,如下文件. mediatek\platform\m ...

  9. MTK |Android KKL 平台TP调试

    MTK Android KK&L 平台TP调试 一. 简介 二. 硬件电路 三. 添加TP的简单流程(以GT9XX为例) 3.1首先在Projecconfig.mk定义的TP宏控 3.2如果是 ...

最新文章

  1. 关闭页面时执行“退出”的解决方案
  2. Kotlin与Java的几种单例模式
  3. 关于谷歌浏览器 点击元素便签出现外边框的情况解决办法
  4. [mmu/cache]-MMU的寄存器学习
  5. linux gnome3安装_Windows 10安装与管理WSL体验原生Linux系统
  6. ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法
  7. C/C++——C风格的字符串的指针指向的内存位置问题(易错)
  8. Selenium 特点
  9. pylon 内存泄露的问题
  10. VUE+Django项目编写
  11. 智能雷达感应人体存在,照明雷达技术应用,雷达模块技术方案
  12. 模拟电路电源芯片PROTUES
  13. Android Studio新建项目
  14. html 文字竖排效果
  15. Activiti学习——生成历史流程跟踪图
  16. 计算机excel公式2010,计算机二级Office2010Eexcel公式汇总
  17. Cross-modal Pretraining in BERT(跨模态预训练)
  18. 事务(Transaction)的简单理解
  19. java创建response对象_创建一个HttpResponse对象
  20. STM32内部flash详解(1)

热门文章

  1. 群晖DSM7.0设置群晖NAS域名外网访问
  2. MTK 驱动(100)---GPS调试宝典
  3. 英文投稿过程中的十种状态
  4. 不规格图片等比例展示---上下/左右留白
  5. python使用百度aip文字识别
  6. cas112592-50-4/四溴苯基卟啉镍/nickel(II) tetra(p-Br-phenyl)porphyrin/分子式:C44H24Br4N4Ni++/分子量:986.99800
  7. fuchsia学习_下载编译遇到问题和demo运行
  8. 圣诞礼物c语言代码大全,圣诞节到咯,教大家用C语言画个圣诞树
  9. DNA甲基化测序数据的分析流程及相关软件总结
  10. Linux提示 /usr/bin/ld:cannot find-lxxx 系列解决方法