dependencies {
//串口
implementation 'com.github.licheedev:Android-SerialPort-API:2.0.0'
}
Project 中的 build.gradle 中的 allprojects 中添加以下 maven仓库
allprojects {
repositories {
maven { url "https://jitpack.io" }//maven仓库
}
}import android.serialport.SerialPort;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* 串口实处理类-jason
*/
public class SerialHandleUtils implements Runnable {
private static final String TAG = "串口处理类";
private String path = "";//串口地址
private SerialPort mSerialPort;//串口对象
private InputStream mInputStream;//串口的输入流对象
private BufferedInputStream mBuffInputStream;//用于监听硬件返回的信息
private OutputStream mOutputStream;//串口的输出流对象 用于发送指令
private SerialMonitor serialInter;//串口回调接口
private ScheduledFuture readTask;//串口读取任务
/**
* 添加串口回调
*
* @param serialInter
*/
public void addSerialInter(SerialMonitor serialInter) {
this.serialInter = serialInter;
}
/**
* 打开串口
*
* @param devicePath 串口地址(根据平板的说明说填写)
* @param baudrate 波特率(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
* @param isRead 是否持续监听串口返回的数据
* @return 是否打开成功
*/
public boolean open(String devicePath, int baudrate, boolean isRead) {
return open(devicePath, baudrate, 7, 1, 2, isRead);
}
/**
* 打开串口
*
* @param devicePath 串口地址(根据平板的说明说填写)
* @param baudrate 波特率(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
* @param dataBits 数据位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
* @param stopBits 停止位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
* @param parity 校验位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
* @param isRead 是否持续监听串口返回的数据
* @return 是否打开成功
*/
public boolean open(String devicePath, int baudrate, int dataBits, int stopBits, int parity, boolean isRead) {
boolean isSucc = false;
try {
if (mSerialPort != null) close();
File device = new File(devicePath);
mSerialPort = SerialPort // 串口对象
.newBuilder(device, baudrate) // 串口地址地址,波特率
.dataBits(dataBits) // 数据位,默认8;可选值为5~8
.stopBits(stopBits) // 停止位,默认1;1:1位停止位;2:2位停止位
.parity(parity) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
.build(); // 打开串口并返回
mInputStream = mSerialPort.getInputStream();
mBuffInputStream = new BufferedInputStream(mInputStream);
mOutputStream = mSerialPort.getOutputStream();
isSucc = true;
path = devicePath;
if (isRead) readData();//开启识别
} catch (Throwable tr) {
close();
isSucc = false;
} finally {
return isSucc;
}
}
// 读取数据
private void readData() {
if (readTask != null) {
readTask.cancel(true);
try {
Thread.sleep(160);
} catch (InterruptedException e) {
e.printStackTrace();
}
//此处睡眠:当取消任务时 线程池已经执行任务,无法取消,所以等待线程池的任务执行完毕
readTask = null;
}
readTask = SerialManage
.getInstance()
.getScheduledExecutor()//获取线程池
.scheduleAtFixedRate(this, 0, 150, TimeUnit.MILLISECONDS);//执行一个循环任务
}
@Override//每隔 150 毫秒会触发一次run
public void run() {
if (Thread.currentThread().isInterrupted()) return;
try {
int available = mBuffInputStream.available();
if (available == 0) return;
byte[] received = new byte[1024];
int size = mBuffInputStream.read(received);//读取以下串口是否有新的数据
if (size > 0 && serialInter != null) serialInter.readData(path, received, size);
} catch (IOException e) {
Log.e(TAG, "串口读取数据异常:" + e.toString());
}
}
/**
* 关闭串口
*/
public void close(){
try{
if (mInputStream != null) mInputStream.close();
}catch (Exception e){
Log.e(TAG,"串口输入流对象关闭异常:" +e.toString());
}
try{
if (mOutputStream != null) mOutputStream.close();
}catch (Exception e){
Log.e(TAG,"串口输出流对象关闭异常:" +e.toString());
}
try{
if (mSerialPort != null) mSerialPort.close();
mSerialPort = null;
}catch (Exception e){
Log.e(TAG,"串口对象关闭异常:" +e.toString());
}
}
/**
* 向串口发送指令
*/
public void send(final String msg) {
byte[] bytes = hexStr2bytes(msg);//字符转成byte数组
try {
mOutputStream.write(bytes);//通过输出流写入数据
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 把十六进制表示的字节数组字符串,转换成十六进制字节数组
*
* @param
* @return byte[]
*/
private byte[] hexStr2bytes(String hex) {
int len = (hex.length() / 2);
byte[] result = new byte[len];
char[] achar = hex.toUpperCase().toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (hexChar2byte(achar[pos]) << 4 | hexChar2byte(achar[pos + 1]));
}
return result;
}
/**
* 把16进制字符[0123456789abcde](含大小写)转成字节
* @param c
* @return
*/
private static int hexChar2byte(char c) {
switch (c) {
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
return -1;
}
}
}/**
* 串口回调
*/
public interface SerialMonitor {
/**
* 连接结果回调
* @param path 串口地址(当有多个串口需要统一处理时,可以用地址来区分)
* @param isSucc 连接是否成功
*/
void connectMsg(String path,boolean isSucc);
/**
* 读取到的数据回调
* @param path 串口地址(当有多个串口需要统一处理时,可以用地址来区分)
* @param bytes 读取到的数据
* @param size 数据长度
*/
void readData(String path,byte[] bytes,int size);
}import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity implements SerialMonitor {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SerialManage.getInstance().init(this);//串口初始化
SerialManage.getInstance().open();//打开串口
findViewById(R.id.send_but).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SerialManage.getInstance().send("Z");//发送指令 Z
}
});
}
@Override
public void connectMsg(String path, boolean isSucc) {
String msg = isSucc ? "成功" : "失败";
Log.e("串口连接回调", "串口 "+ path + " -连接" + msg);
}
@Override//若在串口开启的方法中 传入false 此处不会返回数据
public void readData(String path, byte[] bytes, int size) {
// Log.e("串口数据回调","串口 "+ path + " -获取数据" + bytes);
}
}import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity implements SerialMonitor {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SerialManage.getInstance().init(this);//串口初始化
SerialManage.getInstance().open();//打开串口
findViewById(R.id.send_but).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SerialManage.getInstance().send("Z");//发送指令 Z
}
});
}
@Override
public void connectMsg(String path, boolean isSucc) {
String msg = isSucc ? "成功" : "失败";
Log.e("串口连接回调", "串口 "+ path + " -连接" + msg);
}
@Override//若在串口开启的方法中 传入false 此处不会返回数据
public void readData(String path, byte[] bytes, int size) {
// Log.e("串口数据回调","串口 "+ path + " -获取数据" + bytes);
}
}public class DataConversionUtils {
/**
* 判断奇数或偶数,位运算,最后一位是1则为奇数,为0是偶数
* @param num
* @return
*/
public static int isOdd(int num) {
return num & 0x1;
}
/**
* 将int转成byte
* @param number
* @return
*/
public static byte intToByte(int number){
return hexToByte(intToHex(number));
}
/**
* 将int转成hex字符串
* @param number
* @return
*/
public static String intToHex(int number){
String st = Integer.toHexString(number).toUpperCase();
return String.format("%2s",st).replaceAll(" ","0");
}
/**
* 字节转十进制
* @param b
* @return
*/
public static int byteToDec(byte b){
String s = byteToHex(b);
return (int) hexToDec(s);
}
/**
* 字节数组转十进制
* @param bytes
* @return
*/
public static int bytesToDec(byte[] bytes){
String s = encodeHexString(bytes);
return (int) hexToDec(s);
}
/**
* Hex字符串转int
*
* @param inHex
* @return
*/
public static int hexToInt(String inHex) {
return Integer.parseInt(inHex, 16);
}
/**
* 字节转十六进制字符串
* @param num
* @return
*/
public static String byteToHex(byte num) {
char[] hexDigits = new char[2];
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
hexDigits[1] = Character.forDigit((num & 0xF), 16);
return new String(hexDigits).toUpperCase();
}
/**
* 十六进制转byte字节
* @param hexString
* @return
*/
public static byte hexToByte(String hexString) {
int firstDigit = toDigit(hexString.charAt(0));
int secondDigit = toDigit(hexString.charAt(1));
return (byte) ((firstDigit << 4) + secondDigit);
}
private static int toDigit(char hexChar) {
int digit = Character.digit(hexChar, 16);
if(digit == -1) {
throw new IllegalArgumentException(
"Invalid Hexadecimal Character: "+ hexChar);
}
return digit;
}
/**
* 字节数组转十六进制
* @param byteArray
* @return
*/
public static String encodeHexString(byte[] byteArray) {
StringBuffer hexStringBuffer = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
hexStringBuffer.append(byteToHex(byteArray[i]));
}
return hexStringBuffer.toString().toUpperCase();
}
/**
* 十六进制转字节数组
* @param hexString
* @return
*/
public static byte[] decodeHexString(String hexString) {
if (hexString.length() % 2 == 1) {
throw new IllegalArgumentException(
"Invalid hexadecimal String supplied.");
}
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
}
return bytes;
}
/**
* 十进制转十六进制
* @param dec
* @return
*/
public static String decToHex(int dec){
String hex = Integer.toHexString(dec);
if (hex.length() == 1) {
hex = '0' + hex;
}
return hex.toLowerCase();
}
/**
* 十六进制转十进制
* @param hex
* @return
*/
public static long hexToDec(String hex){
return Long.parseLong(hex, 16);
}
/**
* 十六进制转十进制,并对卡号补位
*/
public static String setCardNum(String cardNun){
String cardNo1= cardNun;
String cardNo=null;
if(cardNo1!=null){
Long cardNo2=Long.parseLong(cardNo1,16);
//cardNo=String.format("%015d", cardNo2);
cardNo = String.valueOf(cardNo2);
}
return cardNo;
}
}我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po