安卓USB硬件通信,监控电池的电量信息

安卓USB硬件通信,监控电池的电量信息

1.新建一个类来获取设备信息和匹配设备

public class UartVCP {
    private final String TAG = "UartVCP";
    UsbDevice device = null;
    int stm32VID = 0x0483, stm32PID = 0x5740;
    private UsbSerialPort port;

    public void InitUartVCP(UsbManager manager){
        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        Log.e(TAG, "get device list  = " + deviceList.size());
        //遍历当前的设备列表
        for (UsbDevice usbDevice : deviceList.values()) {
            device = usbDevice;
            Log.d(TAG, "vid: " + device.getVendorId() + "\t pid: " + device.getProductId());
            if (device.getVendorId() == stm32VID && device.getProductId() == stm32PID) {
                break;
            }
        }
        // 判断设备的ID
        if(device!=null && device.getVendorId()==stm32VID && device.getProductId()==stm32PID){
            getUsbInfo(device);
        }
        else{
            Log.d(TAG,"Don't find desired device.");
        }

        // Find all available drivers from attached devices.
        // 从链接的设备种查找所有可用的usb串行驱动程序,并尝试与指定的设备链接,
        List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
        //通过USB序列号检测器获取当前链接的所有USB串行驱动程序列表
        for (final UsbSerialDriver driver : availableDrivers) {
            // 对于每个驱动程序,检查是否与目标设备匹配,如果匹配则进行下一步操作
            if(driver.getDevice().equals(device)){
                //获取端口列表的第一个端口
                port = driver.getPorts().get(0);
                UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
                if (connection == null) {
                    //无法打开连接,可能需要请求权限
                    // add UsbManager.requestPermission(driver.getDevice(), ..) handling here
                    return;
                }
                try {
                    //使用打开的连接,打开端口
                    port.open(connection);
                    //设置端口的参数(波特率,数据位,停止位,校验码)
                    port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
    //发生数据
    public void sendData(byte[] data) {
        try {
            Log.d(TAG, "data = " + bytesToHexString(data));
            if (null != port){
                port.write(data, 100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //读取数据
    public int readData(byte[] response) {
        int len = 0;
        try {
            if (null != port){
                len = port.read(response, 100);
            }
            Log.d(TAG, "len = " + len + "  response = " + bytesToHexString(Arrays.copyOfRange(response, 0, len)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return len;
    }

    //将字节数组转换成十六进制的字符串
    public String bytesToHexString(byte[] bArr) {
        StringBuilder sb = new StringBuilder(bArr.length);
        String sTmp;

        for (byte b : bArr) {
            sTmp = Integer.toHexString(0xFF & b);
            if (sTmp.length() < 2)
                sb.append(0);
            sb.append(sTmp.toUpperCase());
        }

        return sb.toString();
    }

    private void getUsbInfo(UsbDevice usbDevice){
        StringBuilder sb = new StringBuilder();
        if(Build.VERSION.SDK_INT >= 23){
            sb.append(String.format("VID:0x%04X  PID:0x%04X  ManuFN:%s  PN:%s V:%s; DeviceName:%s",
                    usbDevice.getVendorId(),
                    usbDevice.getProductId(),
                    usbDevice.getManufacturerName(),
                    usbDevice.getProductName(),
                    usbDevice.getVersion(),
                    usbDevice.getDeviceName()
            ));
        }
        else {
            sb.append(String.format("VID:%04X  PID:%04X  ManuFN:%s  PN:%s",
                    usbDevice.getVendorId(),
                    usbDevice.getProductId(),
                    usbDevice.getManufacturerName(),
                    usbDevice.getProductName()
            ));
        }
        Log.d(TAG, "Find my STM32 USB Serial Device ~ " + sb.toString());
    }
}

2.在activity中使用

 //热插拔,如果有的话就去回调下边的代码,监听在哪里就在哪里回调
        UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        RCApplication.uartVCP.InitUartVCP(manager);

        // 广播监听热插拔
        UsbBroadcastReceiver();


 byte[] data = RequestIPC.batteryRequest();
        RCApplication.uartVCP.sendData(data);
        byte[] response = new byte[100];
        int len = RCApplication.uartVCP.readData(response);
        RCApplication.replyIPC.ipc_put_rx_byte(response, len);

3.定义数据处理基类

public abstract class HandlerInit {
    public HeaderV1 header;//存储数据包头信息
    public short crc16;

    public HandlerInit() {
        header = new HeaderV1();
        //帧的起始标志
        header.sof = Unpack.START_OF_FRAME_BYTE;
        //校验和
        header.checksum = (byte)(header.sof + header.ver_len);
        //帧类型 设置为命令帧类型
        header.status = Unpack.FRAME_TYPE_CMD;
        //发送方标识,设置为IPC设备标识
        header.sender = Unpack.DEVICE_IPC << 3 | Unpack.INDEX_IPC;

        /* 扩展修改点二: 上面的已固定不用更改,从这里开始,接收方可能会不同,需要根据命令调整 */
        header.receiver = Unpack.DEVICE_MCU << 3 | Unpack.INDEX_MCU;
        /* 命令对应指令集 */
        header.cmd_set = Unpack.IPC_CMD_SET;
    }

    /**
     * 用于处理数据,并填充头部信息
     * @param struct 数据结构数组,用于存储数据
     * @param cmdLength 命令长度
     * @param cmdID 命令ID
     */
    public void handlerProcess(byte[] struct, int cmdLength, byte cmdID) {
        header.ver_len = (short)(Unpack.FRAME_PROTOCOL_V1 << 10 | cmdLength);
        /* 具体的指令ID */
        header.cmd_id = cmdID;
        HeaderV1.headerTransfer(header, struct);
    }
}

4.定义请求电池数据类

public static class BatteryRequest extends HandlerInit {

    private final int thisLength = getMyLength(getClass());
    private byte[] struct = new byte[thisLength];

    public byte[] setRequest(){
        handlerProcess(struct, thisLength, Unpack.BATTERY_REQUEST_CMD);
        String TAG = "BatteryRequest";
        Log.d(TAG, "length = " + thisLength);
        CRC16.formatFrameBuffer(struct);
        return  struct;
    }
}
public static byte[] batteryRequest() {
    BatteryRequest request = new BatteryRequest();
    return request.setRequest();
}

5.根据数据恢复解析电池数据

public class ReplyIPC {
    final byte SOF_DETECTED = 0;                /* 起始标志检测 */
    final byte HEADER_DETECTED_1 = 1;           /* 帧头检测 */
    final byte HEADER_DETECTED_2 = 2;           /* 帧头检测 */
    final byte HEADER_DETECTED_3 = 3;           /* 帧头检测 */
    final byte DATA_RECEIVED = 4;               /* 数据接收 */

    static byte unpack_step = 0;
    static int head_index = 0;
    static int tail_index = 0;
    static byte[] receiveBuffer = new byte[256];
    static byte[] unpack_buf = new byte[100];
    static int unpack_buf_idx = 0;
    static int unpack_len = 0;

    public BatteryReply batteryReply = new BatteryReply();

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    //将接收到的字节数据存储到接收缓冲区
    public void ipc_put_rx_byte(byte[] data, int len) {
        lock.writeLock().lock();
        for (int i=0; i<len; i++) {
            receiveBuffer[head_index] = data[i];
            head_index = (head_index + 1) % 256;
        }
        lock.writeLock().unlock();
    }

    //从接收缓冲区读取一个字节的数据
    public short ipc_get_rx_byte() {
        short data = 0;
        if(tail_index != head_index)
        {
            lock.readLock().lock();
            data = receiveBuffer[tail_index];
            tail_index = (tail_index + 1) % 256;
            lock.readLock().unlock();
            return data;
        }else {
            return 0x1fff;
        }
    }

    public static int byteToInt(byte b) {
        //Java 总是把 byte 当做有符处理;我们可以通过将其和 0xFF 进行二进制与得到它的无符值
        return b & 0xFF;
    }

    public void getFullData() {
        short data = ipc_get_rx_byte();
        if (data == 0x1fff)
            return;

        switch (unpack_step){
            //检测帧的起始标志
            case SOF_DETECTED:
                if (data == Unpack.START_OF_FRAME_BYTE) {
                    // 将缓冲区的索引置为0,并将起始标志存储到缓冲区域。然后更新解析步骤
                    unpack_buf_idx = 0;
                    unpack_buf[unpack_buf_idx] = (byte)data;

                    unpack_buf_idx ++;
                    unpack_step = HEADER_DETECTED_1;
                }
                break;
                //
            case HEADER_DETECTED_1:
                //将接收到的数据存储到解析缓冲区中,并将解析长度设置为接收到的数值,然后更新解析步骤
                unpack_buf[unpack_buf_idx] = (byte)data;
                unpack_len = data;

                unpack_step = HEADER_DETECTED_2;
                unpack_buf_idx++;
                break;

            case HEADER_DETECTED_2:
                // 将解析到的数据存储到解析缓冲区中,并根据收到的数据更新解析长度,如果大于100表示数据异常需要重新开始解析,否则更新解析步骤
                unpack_buf[unpack_buf_idx] = (byte)data;
                unpack_len |= (((unpack_buf[unpack_buf_idx]) & 0x03) << 8);
                if((unpack_len) > 100)
                {
                    unpack_step = SOF_DETECTED;
                    unpack_buf_idx = 0;
                }
                else
                {
                    unpack_step = HEADER_DETECTED_3;
                    unpack_buf_idx++;
                }
                break;

            case HEADER_DETECTED_3:
                // 将接收到的数据存储到解析缓冲区中,并检查头校验和是否正确,如不正确表示数据异常重新解析,正常更新解析步骤
                unpack_buf[unpack_buf_idx] = (byte)data;

                if((unpack_buf[3]) != ((unpack_buf[0]) + (unpack_buf[1]) + (unpack_buf[2])))
                {
                    unpack_step = SOF_DETECTED;
                    unpack_buf_idx = 0;
                } else {
                    unpack_step = DATA_RECEIVED;
                    unpack_buf_idx++;
                }
                break;

            case DATA_RECEIVED:
                // 将接收到的数据存储到解析缓冲区中,直到接收到的数据长度达到解析长度为止,然后检查校验和是否正确,正确调用方法处理数据
                if((unpack_buf_idx) < (unpack_len))
                {
                    unpack_buf[unpack_buf_idx] = (byte)data;
                    unpack_buf_idx++;
                }
                else if((unpack_buf_idx) > (unpack_len))
                {
                    unpack_step = SOF_DETECTED;
                    unpack_buf_idx = 0;
                }

                if (unpack_buf_idx == unpack_len)
                {
                    unpack_step = SOF_DETECTED;
                    int crc16 = CRC16.calc_crc16(unpack_buf, unpack_len - 2);
                    if (crc16 == (((unpack_buf[unpack_len - 1] << 8) | (unpack_buf[unpack_len - 2] & 0x00FF)) & 0xFFFF))
                    {
                        frame_received_handler_v1(unpack_buf);
                    }
                }
                break;
            default:
        }
    }

    private void frame_received_handler_v1(byte[] buf)
    {
        // 检查数据的第11个字节
        switch (buf[10]){
            case Unpack.BATTERY_REPLY_CMD:
                BatteryReply.current = (buf[12] << 8) | buf[11];
                BatteryReply.capacity_percent = buf[13];
                EventBus.getDefault().post(batteryReply);
                break;
        }
    }

    public static class BatteryReply {
        private static int current;  // unit:10mA
        private static short capacity_percent; // unit:%
        private static byte temperature;    // unit:degree centigrade
        private static int rated_capacitance; // unit:10mAh
        private static int surplus_capacitance; //unit:10mAh

        public int getCurrent(){
            return current;
        }

        public short getCapacity_percent(){
            return capacity_percent;
        }
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值