Android 和 Garmin FR230(SDK 1.3.x)之间通过 BLE 的直接消息通信失败

Direct messaging communication failure over BLE between Android and Garmin FR230 (SDK 1.3.x)

各位 Garmin 开发人员,大家好,

我一直在尝试通过 BLE 在我的 Android 应用程序和我的 connectIQ 应用程序(在 Garmin Forerunner 230,SDK 版本 1.3.x 上)之间开发直接消息通信设置。这里的目标是 Android 应用程序正在收集一些数据,然后将其推送到手表应用程序。

按照 developer site 上的详细信息,我已经设法让它工作了,但是有很多丢弃的消息没有发送,手表接收到的值比正在接收的值少已发送。

在 Android,我在调试语句中得到这个状态 (ConnectIQ.IQMessageStatus) = FAILURE_DURING_TRANSFER。 '240' 是正在发送的数据。

D/GarminMessenger: onMessageStatus: Message: 240, device: Forerunner 230, FAILURE_DURING_TRANSFER

这是我在 garmin 上的应用程序代码:

SampleApp.mc

using Toybox.Application as App;
using Toybox.Communications as Comm;
using Toybox.WatchUi as Ui;
using Toybox.System as Sys;

var mailMethod;
var crashOnMessage = false;

var msg;

class SampleApp extends App.AppBase {

    function initialize() {
        AppBase.initialize();
        Sys.println("app-initialize()");

        msg = "0";

        mailMethod = method(:onMail);
        Comm.setMailboxListener(mailMethod);
        Sys.println("app-initialize(): mail box listener has been set");
    }

    // onStart() is called on application start up
    function onStart(state) {
        System.println("app-onStart()");
    }

    // Return the initial view of your application here
    function getInitialView() {
        Sys.println("app-getInitialView()");
        return [ new SampleAppView() ];
    }

    function onMail(mailIter) {
        var mail = mailIter.next();

        while(mail!=null) {
            Sys.println("app-onMail: received - "+mail);

            message = mail.toString();
            Ui.requestUpdate();
            mail = mailIter.next();
        }

        Comm.emptyMailbox();
    }

    // onStop() is called when your application is exiting
    function onStop(state) {
        System.println("app-onStop()");
    }   
}

class CommListener extends Comm.ConnectionListener {
    function initialize() {
        Comm.ConnectionListener.initialize();
        sys.println("commlistener-initialize");
    }

    function onComplete() {
        Sys.println("commlistener-onComplete: Transmit Complete");
    }

    function onError() {
        Sys.println("commlistener-onError: Transmit Failed");
    }
}

关于可能导致此问题的原因有什么想法吗?我正在 Android 端执行所有必要的检查,以验证 Garmin 手表是否已配对并连接(应用程序已打开)。

发生这种情况的一个原因是我试图每秒发送 1-2 个数据值(每个值都有一个 ConnectIQ.sendMessage()),所以 Garmin device/BLE 模块可能没有支持以这种速率通信吗?

提前感谢您提供解决方案和建议。

认为 Connect 消息传递系统刚刚进入某种损坏状态,然后没有消息通过。 您可以尝试在 onStart 方法中设置邮箱侦听器而不是初始化。

还有一种新方法可以使消息阅读更容易。它在很大程度上仍未记录,但我听说它将在下一个 SDK 版本中记录。但是,它已经在每个 ConnectIQ 手表上运行。 方法是:

Comm.registerForPhoneAppMessages(method(:onMsg));

您在回调方法中执行的操作:

function onMsg(msg) {
    handleIncomingMessage(msg.data.toString());
}

或类似的东西。输入对象 msg 是 class Toybox::Communications::Message 可能(这还没有记录)。

所以我在 Garmin 开发者论坛 here 上发布了一个类似的问题,并得到了我的问题的部分答案。从那里发布摘要。

我希望实现的是以下生活:

假设来自 Android 的消息是 1, 2, 3, 4, 5: 我想要 应用程序在收到消息时更新 UI,在 real-time 中像这样:

app-onMail: received - 1
//update the UI
app-onMail: received - 2
//update the UI
app-onMail: received - 3
//update the UI
app-onMail: received - 4
//update the UI
app-onMail: received - 5
//update the UI

相反,会发生这种情况

app-onMail: received - 1 
app-onMail: received - 2 
app-onMail: received - 3 
app-onMail: received - 4 
app-onMail: received - 5 
//update the UI 
//update the UI 
//update the UI 
//update the UI 
//update the UI

答案

The framework polls to see if there are new, unread mail messages. If there are any, it invokes the application onMail() callback which consumes each message from the queue, and repeatedly sets a flag that indicates the UI needs to update. After the call returns, the framework checks the flag to see if the UI needs to be updated, and if so it calls onUpdate() for the active view.

因此,如果我以 5 秒的间隔从 Android 发送消息,我只能显示每条消息。由于其消息轮询频率,我找不到以更高速率接收和显示数据的方法。

我的回复者建议维护一个邮件队列(或只是一个计数器),然后在抽取之间处理邮件,如下所示:

class MyApp extends App.AppBase
{
    hidden var _M_messages;
    hidden var _M_count;

    function initialize() {
        AppBase.initialize();
        _M_messages = new [10];
        _M_count = 0;
    }

    function getInitialView() {
        return [ new MyView() ];
    }

    function onStart(params) {
        Comm.setMailboxListener(self.method(:onMail));
    }

    function onStop(params) {
        Comm.setMailboxListener(null);
    }

    function onMail(mailIter) {

        var mail = mailIter.next();
        while (mail != null) {

            // only track up to 10 messages
            if (_M_count < 10) {
                _M_messages[_M_count] = mail;
                ++_M_count;
            }
            else {
                break;
            }

            mail = mailIter.next();
        }

        Comm.emptyMailbox();

        startProcessingMessages();
    }


    hidden function startProcessingMessages() {
        if (_M_timer == null) {
            _M_timer = new Timer.Timer();
            _M_timer.start(self.method(:processOneMessage), 250, true);
        }
    }

    hidden function stopProcessingMessages() {
        if (_M_timer != null) {
            _M_timer.stop();
            _M_timer = null;
        } 
    }

    function getMessageCount() {
        return _M_messages;
    }

    function processOneMessage() {
        if (_M_count != 0) {
            --_M_count;
            var mail = _M_messages[_M_count];
            _M_messages[_M_count] = null;

            // process the message here

           Ui.requestUpdate();

           if (_M_count == 0) {
               stopProcessingMessages();
           }
        }
    }
}

class MyView extends Ui.View
{
    hidden var _M_app;

    function initialize(app) {
        View.initialize();
        _M_app = app;
    }

    function onUpdate(dc) {

        var mailMessages = _M_app.getMessageCount();

        // draw the number of mail messages
    }
}