Android应用与硬件建立连接

2023-05-16

文章目录

    • 1、建立连接的原理
    • 2、 “信件”和“邮递员”
    • 3、对方可能未收到如何处理
    • 4、接收“回信”
    • 5、多次数据交互
    • 6. 小结

1、建立连接的原理

在实现软件与硬件交互的时候,首先需要了解该硬件的构造,运行流程等相关操作,熟读相关的文档,知道硬件开发商那边给出了哪些接口,分别对应我们项目中的那些模块等等

就拿我这个项目的硬件来说,供应商给出的连接流程如下图:
在这里插入图片描述

我们可以看到,整体流程并不复杂。执行操作的前提是App连接上硬件的WiFi,之后就是通过 UDP协议来发送指令。这里只大概介绍一下UDP协议,具体了解可以自行百度。

UDP协议 是OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务

举个例子,就比如送信,你写的一封信给你的朋友,你只需要将你朋友的名字、地址等信息填好,然后寄出去就可以了。而你的朋友在它的邮箱里可以收到它。你不需要一直等朋友收到信你才能走,朋友也不需要收到信才能离开。换句话来说,就是不需要发送方和接收方一直保持在线。

为什么称之为不可靠信息传输服务?因为你寄出去了之后你就无法监控它了,这封信有可能半路丢了啊,不小心被烧掉了啊之类的。你只负责发送,至于朋友能不能收到你就管不了了。

2、 “信件”和“邮递员”

UDP的底层也是使用了Socket套接字,所以我们这里用到了DatagramSocket类,你可以把它看成邮递员


	//创建 “邮递员” 13047为我们本机开放的端口,可以理解为寄件时填写的本人地址
	DatagramSocket sendSocket = new DatagramSocket(13047);
	

既然邮递员有了,接下来就是写信,DatagramPacket类就可以理解为信件


	//msgs 是需要发送的数据包,通过EncodingUtil.hexToByte转换为二进制数组
	byte[] data = EncodingUtil.hexToByte(msgs);
	//创建DatagramPacket对象,用来存放发送的数据,端口和ip
    DatagramPacket packet = new DatagramPacket(data,data.length);
    //指定广播的范围和端口(收件地址)
    //58121 硬件指定的接收端口
    packet.setPort(58121);
    //255.255.255.255  进行全网段广播,所有在本网域中的58121端口都会收到我发出去的信息
    packet.setAddress(InetAddress.getByName("255.255.255.255"));
    
    //使用DatagramSocket的send方法,发送数据包
    sendSocket.send(packet);
    //使用完流后应该关闭,这是一个好习惯
    sendSocket.close();

既然信发出去了,那我们就等待对方回应吧。但是UDP是个不可靠的“邮递员”,对方会不会有没有收到信件的可能?这肯定是会有的,那该怎么处理这种情况?

3、对方可能未收到如何处理

首先我去向硬件方咨询了一下,如果硬件收到了UDP广播,在1~2秒内就会有回应的。所以我们可以设定一个等待时间,如果超时了,就重新发送一次


	//计时器是否生效标志位
	private boolean isAuto = false;
	//创建CountDownTimer 对象,设置计时器
    private static CountDownTimer timerAuto;

	//创建一个计时器  CountDownTimer(总时长,每次执行间隔时长)
	//这里给了15s的计时,如果15s内未收到硬件的回应,就执行对应的操作
    timerAuto=new CountDownTimer(1000*15,1000) {
		@Override
		public void onTick(long millisUntilFinished) {
		
		}
		
		//当计时器走完总时长时执行
		@Override
		public void onFinish() {
		  cancel();//取消计时器
		  //关闭接收回应的监听
		  //关闭监听
          receiverListener.exit();
		  //创建线程,再次发送
	      new Thread(new Runnable() {
	          @Override
	          public void run() {
	              try {
	              	//执行发送UDP广播
	                  sendBroadcast();
	              } catch (IOException e) {
	                  e.printStackTrace();
	              }
	          }
	      }).start();		
		}
	};
	
	//如果未重新发送过,就启动计时器
	//如果已经重发过了,就不再次重发了,发了两次都没有收到,那应该是其他地方的问题了
	if(!isAuto){
        isAuto=true;//标志位状态变更
		timerAuto.start();//启动计时器
	}else{
		 // 如果多次重发都未回应,那么就可能有以下几种情况:
			//1. “信件”的问题,检查一下发送的端口号是否正确,本地开启的端口是不是被占用,发送的数据包格式是否正确等
			//2. “道路”的问题,App与硬件通信的前提是需要App连接硬件的Wifi,检查一下连接过程中设备与硬件WiFi是否一直保持正常连接,毕竟路都不通,邮递员也走不了。
			//3. “接收方”的问题,如果我们这边都没问题,那么就要考虑一下是不是硬件的问题,这个就需要和供应商那边去调解
			
		//提示:等待超时,请检查App是否与硬件WiFi保持连接...
	}
	

如果多次重发都未收到回应,那就要变更一下策略了,毕竟在某些硬性条件不满足的情况下,无论你发送多少次都是无效的。

4、接收“回信”

当硬件收到我们发送过去的指令后,就会进入第二步,硬件向App发送硬件备信息。那么该如何接收回应呢

使用Runnable开启一个线程服务用来监听硬件的回应

  /**
     * 开启监听
     */
    private static class SearchListener implements Runnable{

        MyApplication myApplication;//存放全局变量
        Activity activity;//页面activity
        DatagramSocket receiverSocket;//接收socket
        Integer index=0;//用来判断是第几次的数据交互,因为每次发送的数据都不一样
        String ssid;//App设置的SSID
        String pass;//App设置的热点密码
	}
	
	//实现Runnable内的方法
	@Override
    public void run() {
        
	}

接下来创建一个构造器给外部调用,并且将所需的参数传递进来

	//构造函数,开放给外部调用,同时传入需要的参数
    SearchListener(Activity activity,Integer index,String ssid,String pass){
        this.index = index;
        this.ssid = ssid;
        this.pass = pass;
        this.myApplication= (MyApplication) activity.getApplication();
    };

上面的操作都是为了给下一次发送的指令作准备工作,但是接收其实用不到这些。

接收这里同样使用的是DatagramSocket,写在实现的run方法中

按照硬件文档说明,硬件会向发送方的原端口回应信息,在上面我们发送的时候开启的本地端口是13047,所以这里同样使用13047端口来监听回应的指令


		@Override
        public void run() {
            Log.e("监听提示:","监听已启动...");
            try {
            	//建立 13047 端口的DatagramSocket对象
                receiverSocket = new DatagramSocket(13047);
                //接收数据缓冲区大小
                byte[] receiverData = new byte[1024];
                 //使用 DatagramPacket 对象设置接收对象参数
                DatagramPacket receiverPacket = new DatagramPacket(receiverData,receiverData.length);

                //使用DatagramSocket对象接收数据包
                //该方法会阻塞,直到接收到数据报文
                try {
                    receiverSocket.receive(receiverPacket);
                }catch(SocketTimeoutException e){
                    e.printStackTrace();
                }
                
	//使用receive方法来接收之后,线程会进入阻塞状态,所以在接收到回应之前,代码都不会往下执行 
//------------------------------------------------------------------------------------

                //拆解接收到的数据包
                //获得接收到的IP地址

                //数据缓冲区
                byte[] buffer = receiverPacket.getData();
                //将接受到的二进制数据转换为16进制字符串
                String datas = EncodingUtil.toHexString(buffer)
                //接收到回应后,就将计时器关闭
				timerAuto.cancel();
               

            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

到这里,我们就已经实现了接收硬件的“回信”,而且在之前我们已经写好了计时器,如果超时都未收到回应,那就关闭监听,再次发送指令。若多次发送都未收到回应,那就给用户相应的提示。

5、多次数据交互

既然目前App发送指令给硬件,硬件也能够收到并且回应,说明我们已经完成了一个完整的流程。按照最开始的那张流程图,可以将整个连接配置过程分为3次发送和2次接收。既然有多次类似的操作,那么代码就可以封装起来,方便复用

首先是发送的方法,需要传递SSID和密码等参数,所以封装成sendBroadcast()方法如下:


	/**
     * 发送指令
     * @param msg  初始指令
     * @param index  判断是第几次发送
     * @param ssid  热点的SSID
     * @param pass  热点的密码
     * @throws IOException
     */
	private static void sendBroadcast(String msg, int index, final String ssid, final String pass) throws IOException {
        DatagramSocket sendSocket = new DatagramSocket(13047);
        String MSG_STR = msg.replace(" ","");//先空格
        //生成校验位
        String CRC8_ITU = EncodingUtil.CRC8(EncodingUtil.hexToByte(MSG_STR));
        //组合成完整的指令
        MSG_STR = MSG_STR + CRC8_ITU.toUpperCase();

       
        byte[] data = EncodingUtil.hexToByte(msgs);
        //创建DatagramPacket对象,用来存放发送的数据,端口和ip
        DatagramPacket packet = new DatagramPacket(data,data.length);
        packet.setPort(58121);
        packet.setAddress(InetAddress.getByName("255.255.255.255"));

        //使用DatagramSocket的send方法,发送数据包
        sendSocket.send(packet);
        sendSocket.close();

		//如果不是第三次发送的指令,就开启监听,接收硬件的回应
        if(index!=3){
        	//创建接收监听对象
            receiverListener = new SearchListener(myActivity,index,ssid,pass);
            //开启监听线程
            new Thread(receiverListener).start();
        }else{
        	//如果是第三次发送,发送完后就可以不用接受回应了
        	//直接提示用户配置完成,打开手机热点
        }
    }

接收监听在上面就已经实现了,接下来我们就需要根据传递进来的index完成不同的操作


	//使用receive方法来接收之后,线程会进入阻塞状态,所以在接收到回应之前,代码都不会往下执行 
//------------------------------------------------------------------------------------

                //拆解接收到的数据包
                //获得接收到的IP地址

                //数据缓冲区
                byte[] buffer = receiverPacket.getData();
                //将接受到的二进制数据转换为16进制字符串
                String datas = EncodingUtil.toHexString(buffer)
                //接收到回应后,就将计时器关闭
				timerAuto.cancel();


				


				
				if(index==1){
					//如果是第一次发送指令,硬件应该会回应硬件有关的一些信息
					//那么我们可以通过这些信息来生成第二次发送的指令
					//对接收到的数据进行处理,得到硬件版本、IP、端口等所需要的参数
				    //  -----  数据处理  略 ---------
				    
				    String Msg = "";//生成的第二次初始指令

					//调用发送指令的方法
                    exit();//关闭监听的socket,以免出现端口号被占用的问题
                    //调用发送指令的方法,这次的index为2
                    sendBroadcast(Msg,2,ssid,pass);
                    
                  
				}else if(index==2){
					//  -----  数据处理  略 ---------
				
					exit();//关闭监听的socket,以免出现端口号被占用的问题
					//生成第三次发送指令
					String Msg = "";//生成的第二次初始指令
					//调用发送指令的方法,这次的index为3
					sendBroadcast(Msg ,3,ssid,pass);
				}


我们来看看整体的代码执行流程
在这里插入图片描述

6. 小结

在与硬件的对接开发时,很多没有接触过这方面的同学可能会感到害怕和不知所措,毕竟我们学习的是软件技术专业,很少跟硬件打交道。但是其实这一路流程走下来,用到的技术点大多都是我们所熟知的,比如socket、UDP广播、计时器等等。

DatagramSocket
Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。

最重要的是在开发之前,一定要熟读相关的硬件文档,多多了解硬件的操作流程、开放接口等相关的知识。将硬件当做是一个工具,发送指令是为了告诉它我们需要什么,但是它不能听懂我们日常这种对话,所以处理硬件和使用者关系,就是我们开发者的职责所在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android应用与硬件建立连接 的相关文章

  • FreeRTOS消息队列详解第一讲(全网最全)——消息队列概述

    一 队列简介 队列是为了任务与任务 任务与中断之间的通信而准备的 xff0c 可以在任务与任务 任务与中断之间传递消息 xff0c 队列中可以存储有限的 大小固定的数据项目 任务与任务 任务与中断之间要交流的数据保存在队列中 xff0c 叫
  • FreeRTOS消息队列详解第三讲(全网最全)——队列发送消息

    一 队列发送消息函数简介 创建好队列以后就可以向队列发送消息了 xff0c FreeRTOS提供了8个向队列发送消息的API函数 如下表所示 xff1a 1 函数xQueueSend xQueueSendToBack 和xQueueSend
  • FreeRTOS信号量详解第二讲(全网最全)——二值信号量

    一 二值信号量简介 二值信号量通常用于互斥访问或同步 xff0c 二值信号量和互斥信号量非常类似 xff0c 但是还是有一些细微的差别 xff0c 互斥信号量拥有优先级继承机制 xff0c 二值信号量没有优先级继承 因此二值信号另更适合用于
  • FreeRTOS——优先级翻转

    一 优先级翻转 在使用二值信号量的时候会遇到很常见的一个问题 优先级翻转 xff0c 优先级翻转在可剥夺内核中是非常常见的 xff0c 在实时系统中不允许出现这种现象 xff0c 这样会破坏任务的预期顺序 xff0c 可能会导致严重的后果
  • FreeRTOS信号量详解第四讲(全网最全)——互斥信号量

    一 互斥信号量简介 互斥信号量其实就是一个拥有优先级继承的二值信号量 xff0c 在同步的应用中 xff08 任务与任务或中断与任务之间的同步 xff09 二值信号量最适合 互斥信号量适合用于那些需要互斥访问的应用中 在互斥访问中互斥信号量
  • Altium designer AD原理图导入word文档、pdf,生成矢量图的方法;

    文章目录 参数选择 schematic 取消GDI 43 渲染文本 43 gt 减少渲染然后在复制到VISIO里面 xff0c 取消组合 gt 变成矢量图将矢量图粘贴在word 中或者再生成pdf 就不会糊了 参数选择 schematic
  • ROS2的基础概念

    前言 记录ROS2学习的各项核心概念 xff0c 便于后续复习 一 工作空间workshop 1 什么是工作空间 在ROS机器人开发中 xff0c 工作空间是一个存放项目开发相关文件的文件夹 xff0c 各种编写的代码 参数 脚本等文件 x
  • ubuntu多个系统之间文件局域网共享

    前言 xff1a 博主需要在多台主机上进行数据传输 xff0c 由于数据量比较大所以 xff0c 使用移动介质进行传输极为不方便 xff0c 并且也不没有更多的资源在两台主机都进行备份 下面的方式 xff0c 是博主在测试大量的网络上的帖子
  • idea如何清理缓存

    今天运行项目突然报错 检查半天 发现代码没问题 但就是报错 好气啊 最后解决办法就是把以前的缓存清理掉 问题解决 idea清理缓存的方法 File gt Invalidate Caches Restart
  • VNC登录失败:Authentication Failure

    遇到问题 xff1a 解决 xff1a 返回MobaXter xff0c 登录服务器 重置密码 回到VNC Viwer xff0c 重新连接
  • Haar特征

    一 Haar特征 特征是计算机视觉领域一种常用的特征描述算子 xff0c 特征 xff0c 描述图像的特征 xff0c 多用于人脸检测 行人检测 xff0c 等目标检测 xff0c Haar like特征模板内只有白色和黑色两种矩形 xff
  • 在线免费生成IntelliJ IDEA 15.0注册码

    http idea iteblog com key PHP
  • UCOSⅢ简介

    UCOS 简介 简述一 裸机系统与多任务系统二 UCOS 的重要特性三 UCOS 的组成 简述 UCOS xff08 UCOS的第三代内核 xff09 是一个可裁剪 可固化 可剥夺的多任务系统 xff0c 具有高度可移植性 xff0c 没有
  • 树莓派无屏幕无网线远程桌面连接配置方法

    要进行远程连接 xff0c 首先需要让树莓派连上网 xff0c 一种方法是使用网线 xff0c 另一种方法是使用WiFi 本文介绍后者 1树莓派WiFi的配置 没有网线的情况下 xff0c 要远程访问则只能通过WiFi 而由于没有屏幕 xf
  • 【C#可视化工具开发】(Visual Studio2017)利用echarts——1.界面设计

    C 可视化工具开发 近期在做一个可视化工具 xff0c 有关于指标对标相关内容 xff0c 用自己几乎没学到的Visual Studio 2017疯狂开发 xff08 碰壁 xff09 xff0c 由于总体的可视化工具还没做完 xff0c
  • 使用精灵标注助手生成json文件

    使用精灵助手教程 本文主要介绍如何使用精灵标注助手生成json文件 下载精灵标注助手 下载链接 xff1a http www jinglingbiaozhu com 选择windows版本进行下载 安装方式很简单 xff0c 就是一直nex
  • 关于Nginx配置文件在推流取流时的对应模块作用

    关于Nginx配置文件在推流取流时的对应模块作用 前言 xff1a 前提知识1 xff09 xff1a 取流地址只是我们从用于管理路面监控视频的DVR NVR的IP地址 xff0c 这里只需要知道该地址即可 重点是讲述推流和拉流nginx
  • go语言实战-----30-----token机制微信公众号签名验证的方法、XML解析,CDATA解析、交换协议、接收消息协议、被动回复消息协议、正则表达式

    一 token机制微信公众号签名验证的方法 1 token机制 token机制就是使用一个token 通常是一个字符串 xff0c 长度没有特别限制 xff0c 一般是10字节或者16字节 xff0c 然后按照一定的算法生成签名 xff0c
  • python下划线的5种类型

    python中5中下划线 学习的原文章1链接 学习的原文章2 双前导下划线解释 链接 1 单前导下划线 以单个下划线开头的变量或方法仅供内部使用 xff0c 有私有声明的作用 xff0c 但这并不是python语法的强制规定 xff0c 而
  • JAVA课后习题(一)——我是歌手

    大家好 xff01 我是小黄 xff0c 很高兴又跟大家见面啦 xff01 今天更新的是 xff1a JAVA程序设计课后习题 我是歌手往期检索 xff1a 程序设计学习笔记 目录 创建时间 xff1a 2020年10月23日 软件版本 x

随机推荐

  • 解决git时出现error: src refspec master does not match any问题

    问题复现 xff1a 今天在使用gitee创建仓库后上传写好的代码时报错 在远程关联仓库后无法正常推送 键入下图代码时报错error src refspec master does not match any xxx 解决方法 xff1a
  • 如何购买云服务器----以华为云服务器为例

    进入华为云官网 https activity huaweicloud com 登入自己注册的账户 进入控制台 点击界面里我的资源 弹性云服务器ECS 点击右上角 购买弹性云服务器 按照自己的需求选择 xff0c 重点注意 xff1a 计费方
  • Java编写MapReduce的步骤

    Mapper 自定义类继承Mapper类重写自定义类中的map方法 xff0c 在该方法中将K1和V1转为K2和V2将生成的K2和V2写入上下文中 二 Reduce 自定义类继承Reduce类重写Reducer中的reduce方法 xff0
  • PX4入门及开发指南

    PX4入门及开发指南 用户手册开发者手册 用户手册 https docs px4 cc master zh index html 开发者手册 https dev px4 cc master zh index html
  • 树莓派编译工作空间卡死

    树莓派编译程序时遇到卡死 1 树莓派安装的Ubuntu mate 16 04 系统默认设置的swap交换空间不够 xff0c 而编译某些文件的时候需要较大的交换空间 xff0c 树莓派的交换空间被用满所以树莓派看起来好像是死机了的样子 xf
  • 超好用但是很多人不知道的的串口(网络)调试助手推荐

    小众但是超好用的串口 xff08 网络 xff09 调试助手 前言O ComToll xff08 串口 xff09 格西烽火串口网络调试助手伏特加串口 xff08 网络 xff09 调试助手windows自带的串口调试助手总结 前言 这里的
  • STM32上可用的的SM 2 3 4国密算法

    可在STM32上使用的国密算法 SM 2 3 4 SM2SM3SM4 下面直接给出代码 xff0c 有问题可评论 xff0c 自己改动的 xff0c 测试不到的地方可能有bug xff0c 欢迎指正 SM2 由于SM2算法牵扯到一些较为复杂
  • Stm32下环境传感器-Stlm75-hts221-spg30(Hal)

    Stm32下环境传感器 Stlm75 hts221 spg30 xff08 Hal xff09 简介IIC驱动接口Stlm75hts221Spg30 简介 Stlm75与Hts221都是ST的传感器 xff0c 有官方例程 xff0c 我只
  • vscode makefile编译方法实例

    c出来 o 使用 o出来 bin NB二人组走天下 xff0c 目标 xff1a 依赖 xff0c 下一行tab 加命令 感觉时比较块上手的教程 xff0c 手写AI c语言中文网的makefile c语言中文网的就是按部就班 xff0c
  • 树莓派(三):将你的树莓派进行镜像备份

    0 前言 就像备份电脑一样 xff0c 你一定不想树莓派出错后重新配置树莓派 xff0c 将你的树莓派进行备份 1 建立img镜像文件 随便找一个地方 xff0c 新建一个文本文档 xff0c 命名为 你喜欢的名字 img 这时候就会生成一
  • 接口的理解、接口匿名实现类的创建

    接口的概述 xff1a 一方面 xff0c 有时必须从几个类中派生出一个子类 xff0c 继承它们所有的属性和方法 但是 xff0c Java不支持多重继承 xff0c 有了接口 xff0c 就可以得到多重继承的效果 另一方面 xff0c
  • 关于大疆经纬M100进行二次开发视觉跟踪和视觉SLAM的求助

    本人第一次接触大疆的二次开发 xff0c 现在的需求是使用M100进行二次开发能够实现视觉跟踪目标 xff0c 并能够实现视觉SLAM xff0c 但是我没有接触过二次开发 xff0c 希望各位有过经验的大佬能够不吝留言给我说一下具体实现的
  • 定义一个接口CanFly,描述会飞的方法public void fly();

    1 使用类与接口的知识完成如下要求 xff1a xff08 1 xff09 定义一个接口CanFly xff0c 描述会飞的方法public void fly xff08 2 xff09 分别定义类飞机和鸟 xff0c 实现CanFly接口
  • 在Keil4中新建51单片机工程模板详细步骤

    本文主要介绍51单片机学习和开发中的第一步 新建工程模板 对于刚开始学单片机的同学 xff0c 首先要在电脑上装好MDK4软件和CH340驱动 xff0c 然后也要有一个单片机烧录软件 xff08 一般买回来的单片机附带的资料里都会有这三个
  • Java笔试常用库函数

    字符串转数组 String s span class token operator 61 span span class token string 34 13 34 span span class token punctuation spa
  • Pytorch极简入门教程(十六)——DenseNet提取特征

    Pytorch之DenseNet提取特征 导入必要的模块 span class token keyword import span torch span class token keyword from span torch span cl
  • 1. 创建一个功能包(package)

    一 ros所有的进程都需要在工作空间下进行 首先 xff0c 在 home文件夹 任何目录都可以 下创建一个工作空间 xff1a source span class token operator span opt span class to
  • 谷粒学院知识点总结

    文章目录 前言一 项目功能点1 后台管理系统功能2 前台系统功能3 总结项目技术点 二 项目问题三 项目描述1 总体介绍2 项目功能模块 amp 主要深入的模块3 项目涉及技术 前言 谷粒学院知识点总结 xff0c 准备实习面试 一 项目功
  • Win11家庭版U盘Pe安装

    目录 1 准备材料 2 安装 3 开机 4 需要安装的软件 5 封装 6 发现问题 未解决 1 准备材料 1 win11下载 MSDN 迅雷地址链接 2 驱动总裁 U盘魔术师 地址链接 2 安装 1 做好启动盘后 开机进pe 3 开机 准备
  • Android应用与硬件建立连接

    文章目录 1 建立连接的原理2 信件 和 邮递员 3 对方可能未收到如何处理4 接收 回信 5 多次数据交互6 小结 1 建立连接的原理 在实现软件与硬件交互的时候 xff0c 首先需要了解该硬件的构造 xff0c 运行流程等相关操作 xf