星闪聊天软件,正式发布,让Android手机体验星闪科技。 原创 精华

LinMeng林孟
发布于 2024-6-25 22:26
浏览
3收藏

我们的上篇文章点我访问

今天来写的这篇文章,是来告诉51CTO的小伙伴们,经过一整天的完善,我把聊天的功能做得很棒很棒了。

解决了之前开发时遇到的各种问题,这些后面我都会讲到。也同时,修复了不少串口输出的Bug。

作为一款星闪聊天软件,星闪NearLink,正是我们要凸显的一大特色。它是华为工程师们自立自强创造出的一大创新杰作,开创了我们中国原生的新一代近距离无线连接技术,从陪跑跟随全球脚步,到领跑超越蓝牙。

那么我们这款软件,也是在这个情况下,我认为的一款:足以让开发者和用户,都能接受,都能愿意参与使用体验开发的聊天APP,它的优点就是让任意设备(只要能和CH340芯片正常通讯)都能外挂一款星闪开发板,进行双向SLE通讯。

所以,在接下来的时间里,我将会慢慢的讲述我一个人,怎么敲出这款APP的每一行代码。我把这篇文章当成一个特别棒的教学资料,公开给大家,也是给我自己做的一个最近总结。

让我们来到C代码,我们使用小熊派厂商的星闪开发板,因为优点就是看重了他们对鸿蒙社区的贡献(在Gitee上,他们的项目,提交了不少,这一次星闪开发板的资料也是给力很多,上手简单)和这一次他们对星闪开发板的开源工作

代码地址:点我前往我的仓库

static void ssaps_server_write_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_write_cb_t *write_cb_para,
    errcode_t status)
{
    osal_printk("%s ssaps write request callback cbk server_id:%x, conn_id:%x, handle:%x, status:%x\r\n",
        SLE_UART_SERVER_LOG, server_id, conn_id, write_cb_para->handle, status);
    /* 
        osal_printk("\n");
        osal_printk("Let's start chatting, This is the content of the client: %x", write_cb_para->value);
    */
    osal_printk("\n Let's start chatting, This is the content of the client:");
    if ((write_cb_para->length > 0) && write_cb_para->value) {
        uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)write_cb_para->value, write_cb_para->length, 0);
    }
    osal_printk("\n");
}

我在小熊派的SLE_UART Demo上,添加了标注客户端服务端发送文本的标记,这很简单,因为我对文本处理的负担都放在了Android软件上。这里是服务端接收客户端的代码,下面是客户端接收服务端的代码。

void sle_uart_notification_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
    errcode_t status)
{
    unused(client_id);
    unused(conn_id);
    unused(status);
    //osal_printk("\n sle uart recived data : %s\r\n", data->data);
    //uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
    
    osal_printk("\n");
    //osal_printk("Let's start chatting, This is the content of the server: %s", data->data);
    osal_printk("\n Let's start chatting, This is the content of the server:");
    uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
    osal_printk("\n");
}

void sle_uart_indication_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
    errcode_t status)
{
    unused(client_id);
    unused(conn_id);
    unused(status);
    //osal_printk("\n sle uart recived data : %s\r\n", data->data);
    //uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
    
    osal_printk("\n");
    //osal_printk("Let's start chatting, This is the content of the server: %s", data->data);
    osal_printk("\n Let's start chatting, This is the content of the server:");
    uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
    osal_printk("\n");
}

C的代码,我就改动这么多。那么,C的开发工作结束后,我是第一时间启动了Android前端后端的开发。那个时候,我对软件的规划是:++先做出UI,再做出CH34X芯片通信,因为那时候我看到Github上有不少资料,但是后来我后悔了。最后就是做功能。++

就是这样的规划,让我后来开发时遇到了太多太多的麻烦,如下:

  • Github上开源的相关CH34X Java代码,质量参差不齐,不利于整体项目开源。
  • 沁恒厂商对相关的资料老旧,很多相关的代码我是通过海外平台Stackoverflow和相关开源文档翻译后才得到确切资料的。
  • Android上做聊天软件,本人还是第一次做,初版的代码有点杂乱无序,主函数里还写了不少无关注释,这让我上下翻阅代码浪费了很多时间。
  • 还有很多很多…

足够庆幸的是,我也是在最近俩天内把NLChat这款APP做出来了。

星闪聊天软件,正式发布,让Android手机体验星闪科技。-鸿蒙开发者社区

这是完善后的聊天页面,我在今天25号,成功的修好了相关代码的问题,这也是这几天开发的重点中的重点。我们不是做什么Demo,是真的要做一款文字通讯软件,核心就得是处理文本。

那么,接下来就是我今天对CH34xReadData该函数的大改后的情况:

private void CH34xReadData() {
        //先播报星闪软件情况,已经UART接入星闪网络,再好好的处理字符
        HhandlerI.sendEmptyMessage(10);
        StringBuffer stringBuffer = new StringBuffer();
        MainAPP.CH34X.setReadListener(bytes -> {
            //字节转文本
            String string = StringUtils.needProcess().bytesToString(bytes);
            Log.v(TAG, "长度:bytes.length="+ bytes.length + "\t内容:" + string);
            //进行文本处理
            String processedString = CH34xProcessingForReadData(string);
            stringBuffer.append(processedString);
            //处理完再打印到UI上
            runOnUiThread(() -> {
                NearLinkServerText.append(processedString);
                if (NearLinkServerText.length() > 2048) {
                    String str = NearLinkServerText.getText().toString().substring(NearLinkServerText.getText().length() - 1024, NearLinkServerText.getText().length());
                    NearLinkServerText.setText("");
                    NearLinkServerText.append(str);
                }
            });
        });
    }

    private StringBuilder buffer = new StringBuilder();
    @SuppressLint("SimpleDateFormat")
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
    private String CH34xProcessingForReadData(String string) {
        buffer.append(string);
        String result = buffer.toString();

        int endIndex = result.indexOf("\n");
        if (endIndex != -1) {
            String completeFirstData = result.substring(0, endIndex + 1);
            String completeSecondData = "";
            Log.v(TAG, "长度:completeFirstData.length="+ completeFirstData.length() + "\t内容:" + completeFirstData);
            buffer.delete(0, endIndex + 1);

            //去掉特定的前缀字符串,然后返回(聊天内容),只有当消息包含特定的前缀时才处理
            if (completeFirstData.contains(ChatUtils.getPrefixServer()) || completeFirstData.contains(ChatUtils.getPrefixClient())) {
                if (completeFirstData.startsWith(ChatUtils.getPrefixServer())) {
                    completeSecondData = completeFirstData.replace(ChatUtils.getPrefixServer(), "").trim();
                    Log.v(TAG, "长度:completeSecondData.length="+ completeSecondData.length() + "\t内容:" + completeSecondData);
                } else if (completeFirstData.startsWith(ChatUtils.getPrefixClient())) {
                    completeSecondData = completeFirstData.replace(ChatUtils.getPrefixClient(), "").trim();
                    Log.v(TAG, "长度:completeSecondData.length="+ completeSecondData.length() + "\t内容:" + completeSecondData);
                }
                //添加时间戳
                String timestamp = dateFormat.format(new java.util.Date());
                completeSecondData = timestamp + " - " + completeSecondData;

                //确保消息以换行符结尾
                if (!completeSecondData.endsWith("\n")) {
                    completeSecondData += "\n";
                }
                return completeSecondData;
            }
        } else {
            return "";
        }
        return "";
    }

其中一行MainAPP.CH34X.setReadListener(...)是我们的写进CH34X这个Lib里面的ReadThread,本身就是一个Thread线程。当收到了串口反馈的文本后,不管是什么文本,都会以bytes字节形式输出。

这下就很简单了,字节转文本,进行文本处理,处理完后再打印在UI上,这些工作写出来很简单,做起来花的时间真的很长,首先我在自己反编译后翻译的CH34X库里写的数据包为32,我还得需要做一个StringBuffer持续写入成一个完整字节数据,再做处理。++这个问题我是今天25号才排查出来的。++

处理的代码就是去掉后缀Enter后,就是该怎么去掉我们在C代码上面的那么长的标注呢?我的做法是这样的:我们用一个所谓的白名单制度,只要是如下的字符串接收进Android APP里,软件再开始处理去掉前缀,字符串是长这样的:

public class ChatUtils {
    //这里设置的是跟C代码相关的,白名单获取聊天文本,当这些文本出现在串口通讯里面的时候,提取这String后者即可,期间过滤掉前者和大量串口log。
    private static final String PREFIX_SERVER = " Let's start chatting, This is the content of the server:";
    private static final String PREFIX_CLIENT = " Let's start chatting, This is the content of the client:";

    //对方为星闪服务端
    public static String getPrefixServer() {
        return PREFIX_SERVER;
    }

    //对方为星闪客户端
    public static String getPrefixClient() {
        return PREFIX_CLIENT;
    }
}

这里用static静态了,直接写个getter函数是可以直接调用的,只要匹配上了,就可以把聊天句子前缀内容给去掉了,换成代码里安排好的时间戳,就可以打印在UI上了。

这俩天的工作,不仅仅这些,还有UI上我们也能在连接开发板前,设置好串口数据了哦

星闪聊天软件,正式发布,让Android手机体验星闪科技。-鸿蒙开发者社区

Java代码如下:

resources = getApplicationContext().getResources();
        UartSettingsBaud = resources.getStringArray(R.array.listBaud);
        UartSettingsData = resources.getStringArray(R.array.listData);
        UartSettingsStop = resources.getStringArray(R.array.listStop);
        UartSettingsParity = resources.getStringArray(R.array.listParity);
        UartSettingsParityII = resources.getStringArray(R.array.listParityNum);

        RadioButtonBaud4800 = findViewById(id.rbBaud4800);
        RadioButtonBaud4800.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
                if (isChecked) {
                    wchUartSettings.setBaudRate(Integer.parseInt(UartSettingsBaud[0]));
                    SnackBarToastForDebug("已设置波特率" + wchUartSettings.getBaudRate() + "!","设置成功",0,Snackbar.LENGTH_SHORT);
                } else {
                    if (CheckBoxUartWarn.isChecked())
                        Toast.makeText(MainActivity.this,"更改波特率中",Toast.LENGTH_SHORT).show();
                }
            }
        });
.......
    public WCHUartSettings() {}
    public static WCHUartSettings needGetData() { return getData.thing; }
    protected static class getData { private static final WCHUartSettings thing = new WCHUartSettings(); }

    public int getBaudRate() {
        return baudRate;
    }

    public void setBaudRate(int baudRate) {
        this.baudRate = baudRate;
    }

    public byte getDataBit() {
        return dataBit;
    }

    public void setDataBit(byte dataBit) {
        this.dataBit = dataBit;
    }

    public byte getStopBit() {
        return stopBit;
    }

    public void setStopBit(byte stopBit) {
        this.stopBit = stopBit;
    }

    public byte getParity() {
        return parity;
    }

    public void setParity(byte parity) {
        this.parity = parity;
    }

代码介绍的最后,我得来讲讲我反编译翻译后的CH34X仓库,CH34X由驱动库、线程读和安卓广播组成。驱动库的代码尤为重要,粗略如下:

public int resumeUsbList() {} //检查权限,初始化重启后等等情况都是用这个函数解决检查权限

public boolean uartInit() {} //设置CH34X芯片

public boolean setConfig(int baudRate, byte dataBits, byte stopBits, byte parity, byte flowControl) {}
//设置串口接口的波特率、数据位、停止位、奇偶校验位以及流控。

public int writeData(byte[] data, int dataLength) {} //发送数据

public int writeData(byte[] data, int dataLength, int timeOut) {} //也是发送数据,包括了timeOut超时检查

public void closeDevice() {} //关闭USB设备,第一次启动Android APP时和销毁程序时用得到

public void connectionDevice(UsbDevice usbDevice) {} //创建新的USB设备、USB接口、声明连接;启动接收(读)的线程

private int controlTransfer(int i, int i2, int i3) {} //配置使用USB的UART设置,该函数常被UartInit()调用

//尤其是这个controlTransfer函数,光是这个函数我翻阅了不少资料,代码里面都有注释引导链接前往。

最后的最后,也是一件利于大家的好事,我开启了Gitee仓库的地址点我前往,为了方便那些不便前往GitHub的开发者。

第一篇我们约定的大家,还记得嘛?

我估计我自己还会花时间对C的源码做修改,同时在安卓上一定要做好文本提炼工作后,用SQLite做本地数据库保存,确保不会丢失聊天数据的同时,还能写时间戳保存。

接下来的几天的开发工作,我们都会围绕这些去做了,确保功能越做越多,越来越好用。让更多人愿意接触星闪开发板,愿意支持我们的NLChat开发工作。

希望51CTO的大家,能多多支持一下我们,有条件的可以前往Github给我们多多Star,您们的支持是我坚持开发最大的动力。让我们下一篇文章再见。

Gitee的安卓仓库

Gitee的C代码仓库

Github的安卓仓库

Github的C代码仓库

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
5
收藏 3
回复
举报
3条回复
按时间正序
/
按时间倒序
mb667af73a10d17
mb667af73a10d17

很有用的文章,感谢作者开源。

2
回复
2024-6-26 01:00:24
红叶亦知秋
红叶亦知秋

不错不错,必须支持!

1
回复
2024-6-26 10:09:16
LinMeng林孟
LinMeng林孟 回复了 红叶亦知秋
不错不错,必须支持!

谢谢OvO


回复
2024-6-27 15:27:16
回复
    相关推荐