当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]在MTK的机器中,如果不用特定的工具烧写MAC地址,在开机后打开WIFI后会显示: “NVRAM WARNING: Err=0x10” 这就是没有烧写mac地址的原因,所以每次打开wifi,wifi的MAC地址都是一个随机产生的值,为什么会这样?


微信公众号:morixinguan
关注可了解更多的教程。问题或建议,请公众号留言;
如果你觉得本文对你有帮助,欢迎赞赏

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


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

答案在:

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

源码描述如下:

 1public class CdsWifiInfoActivity extends Activity {  2  3 private static final String TAG = "CDSINFO/WifiInfo";  4  5 private static final int MAC_ADDRESS_ID = 30;  6 private static final int MAC_ADDRESS_DIGITS = 6;  7 private static final int MAX_ADDRESS_VALUE = 0xff;  8 private static final int INVALID_RSSI = -200;  9//定义了MAC地址存储的文件的绝对路径 10 private static final String MAC_ADDRESS_FILENAME = "/data/nvram/APCFG/APRDEB/WIFI"; 11 12 private static final String[] WIFI_SYSTEM_PROPERTY = new String[] { 13 "net.hostname", 14 "dhcp.wlan0.ipaddress", 15 "net.dns1", 16 "net.dns2", 17。。。。。

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

 1//获取mac地址的方法  2 private void getMacAddr() {  3  4  5 try {  6 IBinder binder = ServiceManager.getService("NvRAMAgent");  7 NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);  8  9 mRandomMacAddr = new short[MAC_ADDRESS_DIGITS]; 10 11 if (mUserMode) { 12 mMacAddrLabel.setVisibility(View.GONE); 13 mMacAddrEdit.setVisibility(View.GONE); 14 mMacAddBtn.setVisibility(View.GONE); 15 } else { 16 StringBuilder sb = new StringBuilder(); 17 Random rand = new Random(); 18 NumberFormat formatter = new DecimalFormat("00"); 19 int end1 = rand.nextInt(100); 20 int end2 = rand.nextInt(100); 21 String num1 = formatter.format(end1); 22 String num2 = formatter.format(end2); 23 //这几位是固定的值 24 sb.append("00:08:22:11:"); 25 sb.append(num1).append(":").append(num2); 26 27 mMacAddrLabel.setVisibility(View.VISIBLE); 28 mMacAddrEdit.setVisibility(View.VISIBLE); 29 mMacAddBtn.setVisibility(View.VISIBLE); 30 System.out.println("string buffer:" + sb); 31 mMacAddrEdit.setText(sb); 32 MacAddressRandom = sb.toString(); 33 34 } 35 } catch (Exception e) { 36 e.printStackTrace(); 37 } 38 }

更新mac地址的方法:

 1//更新mac地址  2 private void updateMacAddr() {  3  4 try {  5 int i = 0;  6 IBinder binder = ServiceManager.getService("NvRAMAgent");  7 NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);  8  9 //parse mac address firstly 10 StringTokenizer txtBuffer = new StringTokenizer(mMacAddrEdit.getText().toString(), ":"); 11 12 while (txtBuffer.hasMoreTokens()) { 13 mRandomMacAddr[i] = (short) Integer.parseInt(txtBuffer.nextToken(), 16); 14 System.out.println(i + ":" + mRandomMacAddr[i]); 15 i++; 16 } 17 18 if (i != 6) { 19 mToast.setText("The format of mac address is not correct"); 20 mToast.show(); 21 return; 22 } 23 24 byte[] buff = null; 25 26 try { 27 buff = agent.readFileByName(MAC_ADDRESS_FILENAME); 28 } catch (Exception e) { 29 e.printStackTrace(); 30 } 31 32 //随机产生的buff[i+4]开始就是mac地址存储的位置 33 for (i = 0; i < MAC_ADDRESS_DIGITS; i ++) { 34 buff[i + 4] = (byte) mRandomMacAddr[i]; 35 } 36 37 int flag = 0; 38 39 try { 40 flag = agent.writeFileByName(MAC_ADDRESS_FILENAME, buff); 41 } catch (Exception e) { 42 e.printStackTrace(); 43 } 44 45 if (flag > 0) { 46 mToast.setText("Update successfully.\r\nPlease reboot this device"); 47 mToast.show(); 48 } else { 49 mToast.setText("Update failed"); 50 mToast.show(); 51 } 52 53 } catch (Exception e) { 54 mToast.setText(e.getMessage() + ":" + e.getCause()); 55 mToast.show(); 56 e.printStackTrace(); 57 } 58 }

从这个代码中可以分析得知,此时的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。

 1#if defined(MT6628)  2WIFI_CFG_PARAM_STRUCT stWifiCfgDefault =  3{  4 0x0104, /* Own Version For MT6628*/  5 0x0000, /* Peer Version */  6 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* MAC ADDRESS */ ........................

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

 1#include    2#include    3#include    4#include    5#include   6#define WIFI_FILE "WIFI"   7int main(void)  8{  9 int fd = -1 ; 10 int ret ; 11 int i ; 12 char buffer[512] = {0}; 13 char Nvram_wifi_mac_address[6] = {0}; 14 char d_buf[100] = {0}; 15 char dd_buf[100] = {0}; 16 fd = open(WIFI_FILE,O_RDWR); 17 if(fd < 0){ 18 printf("open fair!\n"); 19 return -1 ; 20 } 21 22 ret = read(fd , buffer , 512); 23 if(ret < 0){ 24 printf("read wifi mac fair!\n"); 25 } 26 27 for(i = 4; i < 10 ; i++) 28 Nvram_wifi_mac_address[i-4] = buffer[i] ; 29 //为什么要 & 0xff,因为有些机器是64位的,为了保证和32位的机器显示一致,故只取低8位。  30 sprintf(d_buf,"%02x:%02x:%02x:%02x:%02x:%02x", 31 Nvram_wifi_mac_address[0]&0xff,Nvram_wifi_mac_address[1]&0xff, 32 Nvram_wifi_mac_address[2]&0xff,Nvram_wifi_mac_address[3]&0xff, 33 Nvram_wifi_mac_address[4]&0xff,Nvram_wifi_mac_address[5]&0xff 34 ); 35 printf("%s\n",d_buf); 36 for(i = 0 ; i < strlen(d_buf) ; i++) 37 { 38 dd_buf[i] = toupper(d_buf[i]); //字符串中小写转大写 39 } 40 printf("dd_buf:%s\n",dd_buf) ; 41 42 return 0 ; 43}

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

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

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

位置在:vendor\mediatek\proprietary\factory\src\test\ftm_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这里,在这个头文件中有相关的函数可以给我们使用:

 1extern int gsensor_calibration(int fd, int period, int count, int tolerance, int trace, HwmData *cali);  2extern int gsensor_write_nvram(HwmData *dat);  3extern int gsensor_read_nvram(HwmData *dat);  4extern int gsensor_rst_cali(int fd);  5extern int gsensor_set_cali(int fd, HwmData *dat);  6extern int gsensor_get_cali(int fd, HwmData *dat);  7extern int gsensor_read(int fd, HwmData *dat);  8extern int gsensor_init(int fd);  9extern int gsensor_close(int fd); 10extern int gsensor_open(int *fd); 11extern int gyroscope_calibration(int fd, int period, int count, int tolerance, int trace, HwmData *cali); 12extern int gyroscope_write_nvram(HwmData *dat); 13extern int gyroscope_read_nvram(HwmData *dat); 14extern int gyroscope_rst_cali(int fd); 15extern int gyroscope_set_cali(int fd, HwmData *dat); 16extern int gyroscope_get_cali(int fd, HwmData *dat); 17extern int gyroscope_read(int fd, HwmData *dat); 18extern int gyroscope_close(int fd); 19extern int gyroscope_open(int *fd); 20extern int gyroscope_init(int fd);

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

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

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

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

下面实现这个校准程序:

gs_cali.c

 1#include   2#include   3#include   4#include   5#include   6#include   7#include   8#include   9#include   10#include   11#include   12#include   13#include   14#include   15#include   16#include   17#include   18#include "Keypad.h"  19#include "libhwm.h"  20  21#define GSENSOR_NAME "/dev/gsensor"  22#define OPEN_FILE_FAIR -1   23#define OPEN_SUCCESS 0  24#define RETURE_SUCCESS 0  25#define ENABLED_SUCCESS 0  26#define GSENSOR_CALIBRATION_SUCCESS 0  27#define ENABLED_FAIR -2   28#define CALIBRATION_FAIR -3   29#define SET_CALIBRATION_FAIR -4  30#define WRITE_NVRAM_FAIR  -5   31  32int gs_fd ;  33  34//打开gsensor  35int gs_open(char *gs_name) ;  36//关闭gsensor  37int gs_close(int fd) ;  38//gsensor开始工作  39int gs_enable(unsigned int command) ;  40//校准gsensor  41int gs_calibration(unsigned int cali_delay ,unsigned int cali_num ,unsigned int cali_tolerance) ;  42  43int main(void)  44{  45 int gs_ret = 0 ;  46 int cali_delay = 50;  47int cali_num = 20;  48//这里的20表示把校准的数值做20次平均  49//如果想要更精确,也可以做40次平均计算  50 int cali_tolerance = 20 ; //40  51 //打开gsensor  52 gs_ret = gs_open(GSENSOR_NAME);  53 if(gs_ret != 0){  54 printf("gs open fair!\n") ;  55 return -1 ;  56 }  57 //使能gsensor  58 gs_ret = gs_enable(GSENSOR_IOCTL_INIT);  59 if(gs_ret != 0){  60 printf("gs enable fair!\n") ;  61 return -2 ;  62 }  63 //校准---->包括:执行校准的动作、设置校准数值、将校准数值写入nvram  64 gs_ret = gs_calibration(cali_delay,cali_num,cali_tolerance);  65 if(gs_ret != 0){  66 printf("gs_calibration fair!\n") ;  67 return -3 ;  68 }  69 //关闭gsensor  70 gs_ret = gs_close(gs_fd);  71 if(gs_ret != 0){  72 printf("gs_close fair!\n");  73 return -4 ;  74 }  75 printf("runexec call gsensorCalibrate end\n");  76 return 0 ;  77}  78  79//1、open  80int gs_open(char *gs_name)  81{  82 gs_fd = open(gs_name,O_RDONLY) ;  83 if(gs_fd < 0)  84 {  85 printf("open gsensor dev fair!\n") ;  86 return OPEN_FILE_FAIR ;  87 }  88 printf("gsensor open success!\n");  89 return OPEN_SUCCESS ;  90}  91  92//2、enable gsensor  93int gs_enable(unsigned int command)  94{  95 int err = 0;  96 unsigned int flags = 1;  97 int max_retry = 3, retry_period = 100, retry=0;  98 while ((err = ioctl(gs_fd, command, &flags)) && (retry ++ < max_retry)) ;  99 usleep(retry_period*1000); 100 if (err) { 101 printf("enable g-sensor fail: %s", strerror(errno)); 102 return ENABLED_FAIR; 103 } 104 printf("enable gsensor success!\n"); 105 return ENABLED_SUCCESS ; 106} 107//3、校准 108int gs_calibration(unsigned int cali_delay ,unsigned int cali_num ,unsigned cali_tolerance) 109{ 110 int err ; 111 int flag = 0; 112 HwmData dat; //dat.x  dat.y  dat.z  113 HwmData cali; 114 HwmData cali_nvram; 115 while(1) 116 { 117 //执行校准的动作 118 err = gsensor_calibration(gs_fd , cali_delay , cali_num , cali_tolerance , 0 , &cali); 119 if(err != 0) 120 { 121 printf("calibrate acc: %d\n", err); 122 return CALIBRATION_FAIR ; 123 } 124 //设置校准cali,让校准数据生效 125 err = gsensor_set_cali(gs_fd,&cali) ; 126 if(err != 0) 127 { 128 printf("set calibration fail: (%s) %d\n", strerror(errno), err); 129 return SET_CALIBRATION_FAIR ; 130 } 131 //将校准数据写入nvram中 132 err = gsensor_write_nvram(&cali) ; 133 if(err != 0) 134 { 135 printf ("write nvram fail: (%s) %d\n", strerror(errno), err); 136 return WRITE_NVRAM_FAIR ; 137 } 138 flag = 1 ; 139 if(flag == 1) 140 { 141 printf("Gsensor calibrate success!\n") ; 142 break ; 143 } 144 } 145 return GSENSOR_CALIBRATION_SUCCESS ; 146} 147 148//关闭 149int gs_close(int fd) 150{ 151 close(fd) ; 152 return 0 ; 153}

然后写一个简单的Android.mk

 1LOCAL_PATH:=$(call my-dir)  2include $(CLEAR_VARS)  3LOCAL_MODULE_TAGS := optional  4LOCAL_SHARED_LIBRARIES += libcutils libutils   libhwm  5LOCAL_STATIC_LIBRARIES += libz libstdc++  6LOCAL_SRC_FILES:= \  7 gs_cali.c  8  9LOCAL_MODULE:= gsensor_calibrate 10include $(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方法是读取从驱动中读取已经转化成十进制的数据,而我读取的是原始数据十六进制,所以必须要做进制转换,我们可以来看下这个函数:

 1static int gsensor_read(struct acc_priv *acc)  2{  3 static char buf[128];  4 int x, y, z, err;  5  6 if(acc->fd == -1)  7 {  8 FTGLOGE("invalid file descriptor\n");  9 err = -EINVAL; 10 } 11 else if((acc->support_selftest == 1) && (!acc->selftest) && (err = gsensor_selftest(acc, 10, 20))) 12 { 13 FTGLOGE("selftest fail: %s(%d)\n", strerror(errno), errno); 14 } 15 else 16 { 17 //使用GSENSOR_IOCTL_READ_SENSORDATA命令获取sensor的数据,并存储在buf里 18 err = ioctl(acc->fd, GSENSOR_IOCTL_READ_SENSORDATA, buf); 19 if(err) 20 { 21 FTGLOGE("read data fail: %s(%d)\n", strerror(errno), errno); 22 } 23 //从buf中将x,y,z三个值取出来 24 else if(3 != sscanf(buf, "%x %x %x", &x, &y, &z)) 25 { 26 FTGLOGE("read format fail: %s(%d)\n", strerror(errno), errno); 27 } 28 else 29 { 30 //除以1000,并转成浮点数 31 acc->evt.x = (float)(x)/1000; 32 acc->evt.y = (float)(y)/1000; 33 acc->evt.z = (float)(z)/1000; 34 err = 0; 35 gsensor_statistic(acc); 36 //返回gsensor数据 37 //add sensor data to struct sp_ata_data for PC side 38 return_data.gsensor.g_sensor_x = acc->evt.x; 39 return_data.gsensor.g_sensor_y = acc->evt.y; 40 return_data.gsensor.g_sensor_z = acc->evt.z; 41 return_data.gsensor.accuracy = 3; 42 43 } 44 } 45 return err; 46}

预知详情,可以去分析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读取

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

 1#define GSENSOR_NAME "/sys/bus/platform/drivers/gsensor/sensordata"  2//存储gsensor节点数据的结构体  3struct gsensor_info  4{  5 //x,y,z坐标值  6 char x[10] ;  7 char y[10] ;  8 char z[10] ;  9}; 10int Hex_to_dec(const char* str) ; 11static int check_flag ; 12int Gsensor_Test() 13{ 14 struct gsensor_info g ; 15 char ln[80];//用于存取读出数据的数组 16 FILE *f; 17 int i,n; 18 char *p; 19 int x,y,z ; 20 float x1,y1,z1 ; 21 int xv = 0 , yv = 0 , zv = 0 ; 22 while(1) 23 { 24 f=fopen(GSENSOR_NAME,"r");//打开txt文件 25 if(NULL==f){ 26 printf("Can not open file sensordata!\n");//判断是否可以打开文件 27 return 1; 28 } 29 i=0; 30 while (1) 31 { 32 //从文件中读取一行数据 33 if (NULL==fgets(ln,80,f)) 34 break; 35 p = ln ; 36 sscanf(p,"%s%s%s",g.x,g.y,g.z); 37 i++; 38 } 39 //存储的数据是十六进制,需要做数据转换 40 x = Hex_to_dec(g.x); 41 y = Hex_to_dec(g.y); 42 z = Hex_to_dec(g.z); 43 x1 = (float)x / 1000 ; 44 y1 = (float)y / 1000 ; 45 z1 = (float)z / 1000 ; 46 printf("x: %4.2f   y:%4.2f  z:%4.2f\n",x1,y1,z1); 47 break ; 48 } 49 return 0 ; 50 while_r: 51 while(1); 52} 53//16进制转10进制算法实现 54int Hex_to_dec(const char* str) 55{ 56 int value; 57 58 if (! str) 59 { 60 return 0; 61 } 62 value = 0; 63 while (1) 64 { 65 if ((*str >= '0') && (*str <= '9')) 66 { 67 value = value*16 + (*str - '0'); 68 } 69 else if ((*str >= 'A') && (*str <= 'F')) 70 { 71 value = value*16 + (*str - 'A') + 10; 72 } 73 else if ((*str >= 'a') && (*str <= 'f')) 74 { 75 value = value*16 + (*str - 'a') + 10; 76 } 77 else 78 { 79 break; 80 } 81 str++; 82 } 83 return value; 84}


长期商务合作服务:


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

天风国际分析师郭明錤表示,由于研发进度的中断,预计苹果AR/MR头显推迟至2023年第二季度发布。

关键字: 郭明錤 台积电 vr 苹果

1月10日消息,据媒体报道,腾讯拟收购游戏手机公司黑鲨科技。收购后,黑鲨整体将并入任宇昕主导的腾讯集团平台与内容事业群(PCG),业务重点将从游戏手机,整体转向VR设备——由腾讯提供内容,黑鲨提供VR硬件入口。

关键字: 腾讯 黑鲨科技 元宇宙 vr

GPS模块是集成了RF射频芯片、基带芯片和核心CPU,并加上相关外围电路而组成的一个集成电路。GPS模块的GPS芯片大部分采用全球市占率第一的SiRFIII系列为主。由于GPS模块采用的芯片组不一样,性能和价格也有区别,...

关键字: GPS模块 GPS芯片 MTK

基于8051内核的CISC微控制器迄今为止,MCS-51已成为8位机中运行最慢的系列。现在Dallas推出的DS89C430系列产品在保持与80C51引脚和指令集兼容的基础上,每个机器周期仅为一个时钟,实现了8051系列...

关键字: 微处理器 内核 MTK

摘 要:文中提出一种新的基于MTK手机平台的手持设备设计方案。硬件采用核心板加外部扩展的形式,以MTK手机平台为主体,扩展LCD、传感器、射频模块等为外设的方式实现。巡检仪核心板的CPU为MT6572 ,外扩RFID模块...

关键字: MTK 核心板 RFID Andriod

每一次重大更改都会在开发人员社区中引发痛苦。如果您的开发人员不多,那么破坏性更改不是大问题。而且您还必须考虑成本效益的权衡。如果你做一个突破性的改变,它会增加一些痛苦,但也会带来一些好处。JamesGosling:“您需...

关键字: 软件 vr

随着社会生产力和科学技术的不断发展,各行各业对VR技术的需求日益旺盛。VR技术也取得了巨大进步,并逐步成为一个新的科学技术领域。

关键字: vr 虚拟现实 ar

——魏德米勒带您遨游云展台

关键字: ias 魏德米勒 vr

21世纪是视频媒体的时代。和视频相关的应用,逐渐成为我们工作和生活不可或缺的组成部分。除了传统视频业务之外,最近几年,随着新兴技术的不断出现,越来越多的新型视觉体验服务来到我们的身边,例如4K/8K超高清视频、VR/AR...

关键字: AI vr 英特尔

10月20日,由虚拟现实产业联盟与南昌市人民政府共同举办的2020“南昌VR科创城杯”虚拟现实产业创新大赛决出全部奖项。

关键字: 虚拟现实 创新大赛 vr
关闭
关闭