1.imx6上面直接在ubuntu上用arm-linux-交叉编译工具编译,编完看是直接U盘还是ssh+scp搞出来;imx8到自己客制的文件夹目录里面,配置好当前层的mk和设备树的mk后,到顶部目录export导入环境变量,然后source ,lunch,之后到对应的修改好的目录里面mm单编,编成功后的Log会提示编出来的东西在哪个目录里,一般是out/里面
- $ export AARCH64_GCC_CROSS_COMPILE=/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu-
- $ export CLANG_PATH=/opt/prebuilt-android-clang
- $ export ARMGCC_DIR=/opt/gcc-arm-none-eabi-7-2018-q2-update //这三条是导入环境变量
- $ source build/envsetup.sh //回顶层目录source和lunch
- $ bash build/envsetup.sh //跟source一样,source 不行的时候用bash
- $ lunch mek_8q_car-userdebug
- $去对应的目录mm
2.暂且用网线连接imx6和imx8,二者的通讯暂用udp;imx6发imx8接,并且把接到的rtc时间同步(写入)到自己的里面作为自己时间。收的这边固定设IP为192.168.100.3
注意:
1)imx8这边把编好的应用程序直接adb push进去,这时候确保先adb root ,之后adb remount,然后再进去;
2)adb push进去的时候,不要push到imx8的/storage下面,去这下面跑应用程序是permission denied,最后是挪到/data下面才跑通的,确保跑之前把应用程序chmod 777一下
代码
发送端:
- #include
- #include
- #include
in.h> - #include
- #include
- #include <string.h>
- #include
- #include
-
-
- #include
- #include
- #include
//文件io必须定义这个 -
-
- #define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */
- #define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
- #define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */
- #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */
- #define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
- #define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
- #define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
- #define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
-
- //前面这些RTC_xxx是定义的io控制,这些要去rtc驱动的.c或者.h里面找
-
- #define SERVER_IP "192.168.100.3" //IP号之间不能有空格
-
- void ClientDataHandle_connect_read_write(int socketfd)
- {
- /*int byte, cnt = 0;
- unsigned char data[1024];
- struct rtc_device rtc;
- struct rtc_time tm;
-
- while(1)
- {
- data=rtc_read_time(&rtc,&tm);
- memset(data, 0, 1024);
- sprintf(data, "client send data cnt:%d", ++cnt);
- write(socketfd, data, strlen(data));
- printf("client write to server successful\n");
-
- memset(data, 0, 1024);
- byte = read(socketfd, data, 1024); //读取server数据,有数据更新才读取,否则阻塞
- if(byte == 0)
- {
- perror("read over");
- break;
- }
- if(byte < 0)
- {
- perror("read failed");
- break;
- }
- printf("server-->client datelen:%d info:%s\r\n",byte, data);
- sleep(5);
- }
- return;*/
- }
-
- void ClientDataHandle_connect_recvfrom_sendto(int socketfd)
- {
- /*int cnt = 0, byte = 0;
- unsigned char data[1024];
-
- while(1)
- {
- memset(data, 0, 1024);
- sprintf(data, "client send data cnt:%d\n", ++cnt); //
- sendto(socketfd, data, strlen(data), 0, NULL, 0);
- memset(data, 0, 1024);
- //读取server数据,有数据更新才读取,否则阻塞
- byte = recvfrom(socketfd, data, 1024, 0, NULL, NULL);
- if(byte == 0)
- {
- perror("read over");
- break;
- }
- if(byte < 0)
- {
- perror("read failed");
- break;
- }
- printf("server-->client datelen:%d info:%s\r\n",byte, data);
- sleep(5);
- }
- */
- }
-
- int main(int argc, void *argv[] )
- {
- int socketfd = -1;
- struct sockaddr_in servaddr;
- int rtcfd = -1;
- const char *rtcdev = "/dev/rtc0";
- int ret = 0;
- // struct rtc_device rtc;
- struct rtc_time tm;
- char buf[1024]; //时间保存到这个buf里面,是char,字符
-
- memset(&servaddr,0,sizeof(servaddr));
- servaddr.sin_family=AF_INET;
- servaddr.sin_addr.s_addr=inet_addr(SERVER_IP);
- servaddr.sin_port=htons(1025);
-
-
-
- if( (socketfd = socket(AF_INET, SOCK_DGRAM, 0) ) == -1) //socket函数类似于open函数,打开并创建一个socket,AF_INET使用IPV4协议族,SOCK_STREAM为TCP套接口
- {
- perror("socket create failed!\n");
- return -1;
- }
-
- if(connect(socketfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){
- perror("socket connect failed\n");
- return -1;
- }
-
-
-
-
-
- rtcfd = open(rtcdev,O_RDWR);
- if(rtcfd == -1){
- perror("open rtc error!");
- }
-
- while(1){
- ret = ioctl(rtcfd, RTC_RD_TIME, &tm); //获取时间
- printf("[app] ret= %d , tm_sec=%d,tm_min=%d,tm_hour=%d\r\n",ret, tm.tm_sec, tm.tm_min,tm.tm_hour);
- memset(buf,0,1024);
- sprintf(buf,"%d:%d:%d\n",tm.tm_hour,tm.tm_min,tm.tm_sec); //这里确保打印出的是字符
- sendto(socketfd,buf,sizeof(buf),0,NULL,0);
-
- sleep(1);
-
-
- /*memset(&servaddr, 0, sizeof(servaddr) );
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);
- servaddr.sin_port = htons(1025); //1024以后的端口号是动态的可随意取用
-
- if(connect(socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0 )
- {
- perror("socket connect failed!");
- return -1;
- }*/
-
- }
-
- //ClientDataHandle_connect_read_write(socketfd);//效果与下方函数一样
- //ClientDataHandle_connect_recvfrom_sendto(socketfd);
-
- return 0;
- }
接收端:
- #include
- #include
- #include
in.h> - #include
- #include
- #include <string.h>
- #include
- #include
- #include
- #define BUF_SIZE 1024
- #define SERVER_IP "192.168.100.3"
- #define FILE_NAME "1.txt"
-
- void ServerDataHandle_recvform_sendto(int fd)
- {
- int byte = 0, cnt = 0;
- char buf[BUF_SIZE] = {0};
- socklen_t len = sizeof(struct sockaddr_in);
- struct sockaddr_in clientaddr;
- int file_fd=0;
-
- file_fd=open(FILE_NAME,O_TRUNC|O_WRONLY); //这里的打开方式很重要不能改
-
- if(file_fd<0){
- perror("open file err");
- return ;
- }
-
-
- if(fd <= 0)
- {
- perror("socket fd value err");
- return ;
- }
-
- while(1)
- {
- memset(buf, 0, BUF_SIZE );
- byte = recvfrom(fd, buf, BUF_SIZE, 0, (struct sockaddr *)&clientaddr, &len); //读取client数据,有数据更新才读取,否则阻塞
- if(byte == 0) //客户端关闭时,读取数据个数为0
- {
- printf("sockfd:%d read over\n", fd);
- break;
- }
- if(byte < 0)
- {
- perror("read failed");
- break;
- }
- printf("client IP:%s, port:%d, datalen:%d, info:%s\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, byte, buf );
-
- write(file_fd,buf,byte);
- write(file_fd,"\n",1);
- fsync(file_fd);
-
- memset(buf, 0, BUF_SIZE );
- sprintf(buf, "server send cnt:%d\n", ++cnt);
- sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
- //sleep(5);
- //
- ioctl(listenfd,RTC_SET_TIME,&tm);
- }
- close(fd);
- close(file_fd);
- }
-
- int main()
- {
- int listenfd, opt = 1;
- struct sockaddr_in serveraddr;
- int time_buf[]={0};
-
- listenfd = socket(AF_INET, SOCK_DGRAM, 0);
- if(listenfd < 0)
- {
- perror("Create socket fail.");
- return -1;
- }
-
- memset( (void*)&serveraddr,0,sizeof(struct sockaddr_in) );
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_port = htons(1025);
- //serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP); //自动生成自身IP做服务器IP给客户端连接
-
- if(bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in))<0) //绑定
- {
- perror("bind error.");
- return -1;
- }
-
- ServerDataHandle_recvform_sendto(listenfd); //注意这里传进来的listenfd对应前面的fd
-
- return 0;
- }
对应接收端,imx8这边的还需要按上面所说的配mk
一个是设备树的:
- # -------@block_infrastructure-------
- CONFIG_REPO_PATH := device/nxp
- CURRENT_FILE_PATH := $(lastword $(MAKEFILE_LIST))
- IMX_DEVICE_PATH := $(strip $(patsubst %/, %, $(dir $(CURRENT_FILE_PATH))))
-
- # -------@block_kernel_bootimg-------
- # Don't enable vendor boot for Android Auto with M4 EVS for now
- TARGET_USE_VENDOR_BOOT ?= false
-
- # -------@block_storage-------
- # Android Auto with M4 EVS does not use dynamic partition
- TARGET_USE_DYNAMIC_PARTITIONS ?= false
-
- # -------@block_infrastructure-------
- include $(IMX_DEVICE_PATH)/mek_8q.mk
-
- # -------@block_common_config-------
- # Overrides
- PRODUCT_NAME := mek_8q_car
- PRODUCT_PACKAGE_OVERLAYS += $(IMX_DEVICE_PATH)/overlay_car
-
- # -------@block_app-------
- PRODUCT_COPY_FILES += \
- $(IMX_DEVICE_PATH)/privapp-permissions-imx.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/permissions/privapp-permissions-imx.xml
-
- # Add Google prebuilt services
- PRODUCT_PACKAGES += \
- HeadUnit \
- privapp_permissions_google_auto
-
- # -------@block_camera-------
- # Add Car related HAL
- PRODUCT_PACKAGES += \
- android.hardware.automotive.vehicle@2.0-service \
- android.automotive.sv.service@1.0-impl \
- sv_app
-
- # -------@block_miscellaneous-------
- PRODUCT_COPY_FILES += \
- packages/services/Car/car_product/init/init.bootstat.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.bootstat.rc \
- packages/services/Car/car_product/init/init.car.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.car.rc \
-
- # ONLY devices that meet the CDD's requirements may declare these features
- PRODUCT_COPY_FILES += \
- frameworks/native/data/etc/android.hardware.screen.landscape.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.screen.landscape.xml \
- frameworks/native/data/etc/android.hardware.type.automotive.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.type.automotive.xml
-
- ifeq ($(PRODUCT_IMX_CAR_M4),false)
- # Simulate the vehical rpmsg register event for non m4 car image
- PRODUCT_PROPERTY_OVERRIDES += \
- vendor.vehicle.register=1 \
- vendor.evs.video.ready=1
- else
- #open bootanimation
- PRODUCT_PROPERTY_OVERRIDES += \
- debug.sf.nobootanimation=0
- endif # PRODUCT_IMX_CAR_M4
-
- #isoftstone
- PRODUCT_PACKAGES += \
- spidev_test \
- uartdev_test \
- RTCdev_test \
- sensor_test \
- memtester \
- badblocks \
- SmartCockpitLauncher \
- ApaCamera2 \
- Upgrade
-
- PRODUCT_COPY_FILES += \
- vendor/isoftstone/product/media/bootanimation.zip:$(TARGET_COPY_OUT_PRODUCT)/media/bootanimation.zip \
- vendor/isoftstone/idc/Vendor_1a86_Product_e2e4.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/Vendor_1a86_Product_e2e4.idc \
- vendor/isoftstone/idc/Vendor_1a86_Product_e5e3.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/Vendor_1a86_Product_e5e3.idc
还有就是对应的目录下面的mk:
- LOCAL_PATH:= $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_SRC_FILES:=imx8_time.c
- LOCAL_MODULE:=RTC_test
- include $(BUILD_EXECUTABLE)
注意:
接收方:
1. 先touch 1.txt 手动 如果报open错误
2. open file的方式 O_TRUNC | O_WRONLY ,如果改成仅仅O_TRUNC,1.txt里面会没东西
发送方:
3.发送字符,而不是发送结构体,循环里改成(类似的在main之前被注释掉的函数里有写):
memset(buf,0,1024);
sprintf(buf,"%d:%d:%d\n",tm.tm_hour,tm.tm_min,tm.tm_sec);
sendto(socketfd, buf, sizeof(buf), 0, NULL, 0);
这里如果不确保是发送字符而是发送结构体的话,那么不论收到的还是保存数据1.txt里面都会是乱码:
4.struct rtc_device rtc 这里如果报错应该是和rtc.h里面重复定义了
5.几个fd, 还有几个定义的fd,包括,listenfd,fd,rtcfd,file_fd不要搞混了,然后各个的判断如fd<0不要忘记写。
if(file_fd < 0)
{
perror("open file err");
return ;
}
发送里面这个不能忘记写,写在if(fd<0)前面
6.进去板子里跑应用程序的时候,imx8这边不要Push到/storage下面,这下面哪怕chmod 777 了也跑不了,会报permission denied,最后是去/data下面跑通的
接下来要把imx8收到的rtc时钟信息保存到自己的时间里面,目前的话,想的是通过date命令,然后看了date命令的 date --help是这样:
最后今天学到的:set nu可以显示代码的行号