基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版

本文在前一篇基础上,详细介绍以CrossApp跨平台框架为基础,利用mosquito库和easySQLite库设计实现了基于MQTT协议的android版步进电机控制客户端。

一、开发环境的准备

编译环境为CrossApp平台提供的一键部署windows下android开发环境的工具包:
下载地址:
http://pan.baidu.com/s/1qW6ql32#dir/path=%2FCrossApp-Ide

工具包的安装在此省略。参考文章:
https://www.oschina.net/question/1271569_160671

一步步按照向导设置好自己的软件环境。我安装的是x64版。

二、工程的构建和基本设置

安装好后,运行C:\CrossApp\eclipse下的eclipse.exe

参考:http://blog.csdn.net/j2066/article/details/47624109

菜单->file->new->other
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第1张图片

然后next,选对相应的android工程:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第2张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第3张图片

导入成功后看到:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第4张图片

看到前面左下角有个红色的叉,这是因为框架代码没有导入进来。
接着,按照前面的方法导入CrossApp框架代码工程:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第5张图片

然后看到有错误提示:

[2017-10-02 20:09:21 - StepMotorController] Unable to resolve target 'android-20'
[2017-10-02 20:14:47 - libCrossApp] Unable to resolve target 'android-20'
[2017-10-02 20:14:49 - libCrossApp] Unable to resolve target 'android-20'

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第6张图片

需要修改libCrossApp的属性。
对着libCrossApp点右键,选Properties(属性):
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第7张图片

在Project Build Target中选Android 4.4.2:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第8张图片

对于StepMotorController项目也一样设置这个地方:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第9张图片

接着,我们需要修改一下StepMotorController项目下的make文件:
双击项目下的jni下的Android.mk文件:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第10张图片

需要修改这个地方:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第11张图片

为去掉注释符号:

$(call import-add-path, $(LOCAL_PATH)/../../../..)
$(call import-add-path, $(LOCAL_PATH)/../../../../CrossApp/the_third_party/)

先编译一下,右击项目,Run As->Android Application:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第12张图片

看到命令行有个错误:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第13张图片

这个错误是本项目的NDK构建环境android-ndk-r9路径设置有问题造成的:
右键点StepMotorController属性(Properties)->c/c++ Build->Environment->NDK ROOT:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第14张图片

双击这一行,把NDK ROOT设置为自己的路径,我们装包默认的是C:\CrossApp\android-ndk-r9d:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第15张图片

点OK:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第16张图片

还有一个地方需要修改:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第17张图片

修改为我们安装的目录:
C:\CrossApp\android-ndk-r9d\ndk-build.cmd

点OK,编译一下,看到一条错误:

jni/../../Classes/easySQLite/SqlCommon.h:136:22: error: format not a string literal and no format arguments [-Werror=format-security]

参考网上文章,原因是:

  android-ndk-r9与Eclipse的版本不兼容问题

解决方法:

  在对应项目的proj.android/jni/Application.mk添加一句话

  APP_CFLAGS += -Wno-error=format-security

  意思就是无视这个error
  
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第18张图片

再次编译,又出来错误:

jni/../../Classes/MenuViewController.cpp:105:15: error: converting to execution character set: Illegal byte sequence

这个错误原因是MenuViewController.cpp这个文件的文本格式是ANSI,因为不是支持unicode的格式,所以,不支持中文编码。
解决这个问题的方法是,用记事本打开这个文件另存为UTF-8格式:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第19张图片

编译一下,又出现错误:

jni/../../Classes/easySQLite/SqlCommon.cpp: In member function 'sql::string sql::time::format(const char*)':
jni/../../Classes/easySQLite/SqlCommon.cpp:70:38: error: 'localtime_s' was not declared in this scope
   if (localtime_s(&localtime, &_value) == 0)
                                      ^
jni/../../Classes/easySQLite/SqlCommon.cpp: In function 'sql::string sql::intToStr(int)':
jni/../../Classes/easySQLite/SqlCommon.cpp:116:43: error: '_itoa_s' was not declared in this scope
  _itoa_s(value, buffer, sizeof(buffer), 10);
                                           ^
jni/../../Classes/easySQLite/SqlCommon.cpp: In function 'sql::string sql::intToStr(sql::integer)':
jni/../../Classes/easySQLite/SqlCommon.cpp:123:45: error: '_i64toa_s' was not declared in this scope
  _i64toa_s(value, buffer, sizeof(buffer), 10);
                                             ^
make.exe: *** [obj/local/armeabi/objs/CrossApp_cpp_shared/__/__/Classes/easySQLite/SqlCommon.o] Error 1

这些错误的原因是我们目前使用的easySQLite库版本太老了,g++编译器(ndk用的是4.8)对这些函数不支持,解决方法是下载一个更新一点的版本来替换原库。这个版本是cocos-2dx引擎提供的:
https://github.com/gelldur/easysqlite

下载下来,把easysqlite-master.zip\easysqlite-master\easySQLite中所有原代码替换原库中的对应文件,然后重新编译。
然后出现一堆错误:

jni/../../Classes/MQTT/mosquittopp.cpp:123: error: undefined reference to 'mosquitto_destroy'
jni/../../Classes/MQTT/mosquittopp.cpp:76: error: undefined reference to 'mosquitto_lib_init'
jni/../../Classes/MQTT/mosquittopp.cpp:81: error: undefined reference to 'mosquitto_lib_cleanup'
jni/../../Classes/MQTT/mosquittopp.cpp:86: error: undefined reference to 'mosquitto_strerror'
jni/../../Classes/MQTT/mosquittopp.cpp:91: error: undefined reference to 'mosquitto_connack_string'
jni/../../Classes/MQTT/mosquittopp.cpp:96: error: undefined reference to 'mosquitto_sub_topic_tokenise'
jni/../../Classes/MQTT/mosquittopp.cpp:101: error: undefined reference to 'mosquitto_sub_topic_tokens_free'
jni/../../Classes/MQTT/mosquittopp.cpp:106: error: undefined reference to 'mosquitto_topic_matches_sub'
jni/../../Classes/MQTT/mosquittopp.cpp:111: error: undefined reference to 'mosquitto_new'
jni/../../Classes/MQTT/mosquittopp.cpp:112: error: undefined reference to 'mosquitto_connect_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:113: error: undefined reference to 'mosquitto_disconnect_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:114: error: undefined reference to 'mosquitto_publish_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:115: error: undefined reference to 'mosquitto_message_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:116: error: undefined reference to 'mosquitto_subscribe_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:117: error: undefined reference to 'mosquitto_unsubscribe_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:118: error: undefined reference to 'mosquitto_log_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:129: error: undefined reference to 'mosquitto_reinitialise'
jni/../../Classes/MQTT/mosquittopp.cpp:131: error: undefined reference to 'mosquitto_connect_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:132: error: undefined reference to 'mosquitto_disconnect_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:133: error: undefined reference to 'mosquitto_publish_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:134: error: undefined reference to 'mosquitto_message_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:135: error: undefined reference to 'mosquitto_subscribe_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:136: error: undefined reference to 'mosquitto_unsubscribe_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:137: error: undefined reference to 'mosquitto_log_callback_set'
jni/../../Classes/MQTT/mosquittopp.cpp:144: error: undefined reference to 'mosquitto_connect'
jni/../../Classes/MQTT/mosquittopp.cpp:149: error: undefined reference to 'mosquitto_connect_bind'
jni/../../Classes/MQTT/mosquittopp.cpp:154: error: undefined reference to 'mosquitto_connect_async'
jni/../../Classes/MQTT/mosquittopp.cpp:159: error: undefined reference to 'mosquitto_connect_bind_async'
jni/../../Classes/MQTT/mosquittopp.cpp:164: error: undefined reference to 'mosquitto_reconnect'
jni/../../Classes/MQTT/mosquittopp.cpp:169: error: undefined reference to 'mosquitto_reconnect_async'
jni/../../Classes/MQTT/mosquittopp.cpp:174: error: undefined reference to 'mosquitto_disconnect'
jni/../../Classes/MQTT/mosquittopp.cpp:179: error: undefined reference to 'mosquitto_socket'
jni/../../Classes/MQTT/mosquittopp.cpp:184: error: undefined reference to 'mosquitto_will_set'
jni/../../Classes/MQTT/mosquittopp.cpp:189: error: undefined reference to 'mosquitto_will_clear'
jni/../../Classes/MQTT/mosquittopp.cpp:194: error: undefined reference to 'mosquitto_username_pw_set'
jni/../../Classes/MQTT/mosquittopp.cpp:199: error: undefined reference to 'mosquitto_publish'
jni/../../Classes/MQTT/mosquittopp.cpp:204: error: undefined reference to 'mosquitto_reconnect_delay_set'
jni/../../Classes/MQTT/mosquittopp.cpp:209: error: undefined reference to 'mosquitto_max_inflight_messages_set'
jni/../../Classes/MQTT/mosquittopp.cpp:214: error: undefined reference to 'mosquitto_message_retry_set'
jni/../../Classes/MQTT/mosquittopp.cpp:219: error: undefined reference to 'mosquitto_subscribe'
jni/../../Classes/MQTT/mosquittopp.cpp:224: error: undefined reference to 'mosquitto_unsubscribe'
jni/../../Classes/MQTT/mosquittopp.cpp:229: error: undefined reference to 'mosquitto_loop'
jni/../../Classes/MQTT/mosquittopp.cpp:234: error: undefined reference to 'mosquitto_loop_misc'
jni/../../Classes/MQTT/mosquittopp.cpp:239: error: undefined reference to 'mosquitto_loop_read'
jni/../../Classes/MQTT/mosquittopp.cpp:244: error: undefined reference to 'mosquitto_loop_write'
jni/../../Classes/MQTT/mosquittopp.cpp:249: error: undefined reference to 'mosquitto_loop_forever'
jni/../../Classes/MQTT/mosquittopp.cpp:254: error: undefined reference to 'mosquitto_loop_start'
jni/../../Classes/MQTT/mosquittopp.cpp:259: error: undefined reference to 'mosquitto_loop_stop'
jni/../../Classes/MQTT/mosquittopp.cpp:264: error: undefined reference to 'mosquitto_want_write'
jni/../../Classes/MQTT/mosquittopp.cpp:269: error: undefined reference to 'mosquitto_opts_set'
jni/../../Classes/MQTT/mosquittopp.cpp:274: error: undefined reference to 'mosquitto_threaded_set'
jni/../../Classes/MQTT/mosquittopp.cpp:279: error: undefined reference to 'mosquitto_user_data_set'
jni/../../Classes/MQTT/mosquittopp.cpp:294: error: undefined reference to 'mosquitto_tls_set'
jni/../../Classes/MQTT/mosquittopp.cpp:299: error: undefined reference to 'mosquitto_tls_opts_set'
jni/../../Classes/MQTT/mosquittopp.cpp:304: error: undefined reference to 'mosquitto_tls_insecure_set'
jni/../../Classes/MQTT/mosquittopp.cpp:309: error: undefined reference to 'mosquitto_tls_psk_set'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [obj/local/armeabi/libCrossApp_cpp.so] Error 1

这些错误原因,是没有把mosquitto的源代码编译进去,为什么没有编译进去呢?这需要看makefile是怎么写的。看android.mk中有这么 一行:

MY_FILES_SUFFIX := %.cpp

这是指定文件后缀为.cpp,也就是只搜索项目中的cpp文件,而不搜集c文件,在它后面加上%.c以支持编译c文件:

MY_FILES_SUFFIX := %.cpp %.c

再编译可以看到mosquitto源代码已经编译进去了,但看到一堆错误:

C:/CrossApp/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld.exe: error: ./obj/local/armeabi/libCrossApp.a(sqlite3.o): multiple definition of 'sqlite3_compileoption_get'
C:/CrossApp/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld.exe: ./obj/local/armeabi/objs/CrossApp_cpp_shared/__/__/Classes/easySQLite/sqlite3.o: previous definition here

......


C:/CrossApp/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld.exe: ./obj/local/armeabi/objs/CrossApp_cpp_shared/__/__/Classes/easySQLite/sqlite3.o: previous definition here
jni/../../Classes/MQTT/mosquitto.c:282: error: undefined reference to 'pthread_cancel'
jni/../../Classes/MQTT/thread_mosq.c:66: error: undefined reference to 'pthread_cancel'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [obj/local/armeabi/libCrossApp_cpp.so] Error 1

这一堆的错误,主要是有两个:
1、sqlite3这个目标文件已经在CrossApp链接过了,所以,这里提示重复定义;
2、mosquitto.c、thread_mosq.c所使用的pthread_cancel这个poxis函数,在android的ndk平台不支持。

对于第一个错误,需要修改android.mk,在编译时,过滤掉sqlite3.c文件。把

LOCAL_SRC_FILES  := $(MY_SRC_LIST)

修改为:

LOCAL_SRC_FILES  := $(filter-out %/sqlite3.c,$(MY_SRC_LIST)) #don't compile sqlite3.c ,becase it has been contained in the CrossApp core lib . #$(MY_SRC_LIST)

意思是从MY_SRC_LIST所包含的文件中过滤掉所有的sqlite3.c文件,当然实际上只有一个。
重新编译链接,可以看到剩下二个错误:

jni/../../Classes/MQTT/mosquitto.c:282: error: undefined reference to 'pthread_cancel'
jni/../../Classes/MQTT/thread_mosq.c:66: error: undefined reference to 'pthread_cancel'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [obj/local/armeabi/libCrossApp_cpp.so] Error 1

需要修改mosquitto.c、thread_mosq.c。

对于这一部分,参考网上的解决方案,使用了pthread_kill来代替pthread_cancel,至于有没有什么不妥,就可能不好说了。目前先这样解决。
nano-CrossApp\projects\StepMotorController\Classes\MQTT\mosquitto.c中的
void _mosquitto_destroy(struct mosquitto *mosq)函数修改部分如下:
这里写图片描述
红色的部分是需要添加的。

#include "platform/CCPlatformConfig.h"

void _mosquitto_destroy(struct mosquitto *mosq)
{
    struct _mosquitto_packet *packet;
    if(!mosq) return;

#ifdef WITH_THREADING
    if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        //if ( (ESRCH= = pthread_kill(mosq->thread_id, SIGUSR1))) 
        //{ 
        //  printf("Error cancelling thread %d, error = %d (%s)", pthread_id, status, strerror status));
        //} 

        if(pthread_kill(mosq->thread_id, 0)!= ESRCH)
        {
            //printf("thread %d exists!\n", pid);
            pthread_kill(mosq->thread_id, SIGQUIT);
            //printf("after kill\n");
        }       
#else 
    pthread_cancel(mosq->thread_id);

#endif
        pthread_join(mosq->thread_id, NULL);
        mosq->threaded = mosq_ts_none;
    }

    if(mosq->id){
        /* If mosq->id is not NULL then the client has already been initialised
         * and so the mutexes need destroying. If mosq->id is NULL, the mutexes
         * haven't been initialised. */
        pthread_mutex_destroy(&mosq->callback_mutex);
        pthread_mutex_destroy(&mosq->log_callback_mutex);
        pthread_mutex_destroy(&mosq->state_mutex);
        pthread_mutex_destroy(&mosq->out_packet_mutex);
        pthread_mutex_destroy(&mosq->current_out_packet_mutex);
        pthread_mutex_destroy(&mosq->msgtime_mutex);
        pthread_mutex_destroy(&mosq->in_message_mutex);
        pthread_mutex_destroy(&mosq->out_message_mutex);
        pthread_mutex_destroy(&mosq->mid_mutex);
    }
#endif
    if(mosq->sock != INVALID_SOCKET){
        _mosquitto_socket_close(mosq);
    }
    _mosquitto_message_cleanup_all(mosq);
    _mosquitto_will_clear(mosq);
#ifdef WITH_TLS
    if(mosq->ssl){
        SSL_free(mosq->ssl);
    }
    if(mosq->ssl_ctx){
        SSL_CTX_free(mosq->ssl_ctx);
    }
    if(mosq->tls_cafile) _mosquitto_free(mosq->tls_cafile);
    if(mosq->tls_capath) _mosquitto_free(mosq->tls_capath);
    if(mosq->tls_certfile) _mosquitto_free(mosq->tls_certfile);
    if(mosq->tls_keyfile) _mosquitto_free(mosq->tls_keyfile);
    if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL;
    if(mosq->tls_version) _mosquitto_free(mosq->tls_version);
    if(mosq->tls_ciphers) _mosquitto_free(mosq->tls_ciphers);
    if(mosq->tls_psk) _mosquitto_free(mosq->tls_psk);
    if(mosq->tls_psk_identity) _mosquitto_free(mosq->tls_psk_identity);
#endif

    if(mosq->address){
        _mosquitto_free(mosq->address);
        mosq->address = NULL;
    }
    if(mosq->id){
        _mosquitto_free(mosq->id);
        mosq->id = NULL;
    }
    if(mosq->username){
        _mosquitto_free(mosq->username);
        mosq->username = NULL;
    }
    if(mosq->password){
        _mosquitto_free(mosq->password);
        mosq->password = NULL;
    }
    if(mosq->host){
        _mosquitto_free(mosq->host);
        mosq->host = NULL;
    }
    if(mosq->bind_address){
        _mosquitto_free(mosq->bind_address);
        mosq->bind_address = NULL;
    }

    /* Out packet cleanup */
    if(mosq->out_packet && !mosq->current_out_packet){
        mosq->current_out_packet = mosq->out_packet;
        mosq->out_packet = mosq->out_packet->next;
    }
    while(mosq->current_out_packet){
        packet = mosq->current_out_packet;
        /* Free data and reset values */
        mosq->current_out_packet = mosq->out_packet;
        if(mosq->out_packet){
            mosq->out_packet = mosq->out_packet->next;
        }

        _mosquitto_packet_cleanup(packet);
        _mosquitto_free(packet);
    }

    _mosquitto_packet_cleanup(&mosq->in_packet);
    if(mosq->sockpairR != INVALID_SOCKET){
        COMPAT_CLOSE(mosq->sockpairR);
        mosq->sockpairR = INVALID_SOCKET;
    }
    if(mosq->sockpairW != INVALID_SOCKET){
        COMPAT_CLOSE(mosq->sockpairW);
        mosq->sockpairW = INVALID_SOCKET;
    }
}

第二个、
对于nano-CrossApp\projects\StepMotorController\Classes\MQTT\thread_mosq.c中的
int mosquitto_loop_stop(struct mosquitto *mosq, bool force)函数修改如下:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第20张图片

#include 
#include "platform/CCPlatformConfig.h"

int mosquitto_loop_stop(struct mosquitto *mosq, bool force)
{
#ifdef WITH_THREADING
#  ifndef WITH_BROKER
    char sockpair_data = 0;
#  endif

    if(!mosq || mosq->threaded != mosq_ts_self) return MOSQ_ERR_INVAL;


    /* Write a single byte to sockpairW (connected to sockpairR) to break out
     * of select() if in threaded mode. */
    if(mosq->sockpairW != INVALID_SOCKET){
#ifndef WIN32
        if(write(mosq->sockpairW, &sockpair_data, 1)){
        }
#else
        send(mosq->sockpairW, &sockpair_data, 1, 0);
#endif
    }

    if(force){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        //if ( (ESRCH= = pthread_kill(mosq->thread_id, SIGUSR1))) 
        //{ 
        //  printf("Error cancelling thread %d, error = %d (%s)", pthread_id, status, strerror status));
        //} 

        if(pthread_kill(mosq->thread_id, 0)!= ESRCH)
        {
            //printf("thread %d exists!\n", pid);
            pthread_kill(mosq->thread_id, SIGQUIT);
            //printf("after kill\n");
        }       
#else 
    pthread_cancel(mosq->thread_id);

#endif
    }
    pthread_join(mosq->thread_id, NULL);
    mosq->thread_id = pthread_self();
    mosq->threaded = mosq_ts_none;

    return MOSQ_ERR_SUCCESS;
#else
    return MOSQ_ERR_NOT_SUPPORTED;
#endif
}

修改之后,重新编译链接,ok。

三、验证一下android版对MQTT broker的连接功能

然后接上手机(安卓系统,我的版本是4.4.4):
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第21张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第22张图片

这里是还没对broker的参数进行设置,需要设置一下server ip,一般情况下,可以使用wifi在同一个局域网下连接服务器了。但是因为我使用的wifi是在台式机接的360随身wifi,因此,没别的办法,只能从外网来连接我台式机了。
所以,需要在路由上做ip映射。

我的路由是水星MAC1200R,进入路由设置界面,点右上角的高级设置,然后点开左边菜单高级用户,点虚拟服务器,看到如下界面:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第23张图片

然后点那个加号添加:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第24张图片

在常用服务器中选SOCK,外部端口和内部端口都填1883,ip地址填要映射到的台式机IP,我的是10.0.0.108,协议类型可以默认,为ALL,填完之后,点最右边保存。
这样就ok了。

下面查看一下公网IP,点右上角常用设置,然后左边菜单点上网设置,可以看到IP地址:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第25张图片

这个IP地址:123.xxx.xxx.xxx就是我们宽带的公网IP,也就是我们需要在手机号上填写的IP地址。这样,当我们连该IP的时候,路由就把该连接映射到我台式机上了。
下面系列图片是在手机上的操作:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第26张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第27张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第28张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第29张图片

可以看到这里出现了bug!

继续:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第30张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第31张图片

但保存之后,返回主界面,又出现了bug:连接的时候,没有使用新设置的IP地址。

以上第一个bug是布局格式选得不合适。

关于CrossApp布局格式的参数的意义请参考:
https://www.w3cschool.cn/crossapp/rv2g1pw1.html

对布局的设置在void SettingsViewController::viewDidLoad()函数中,经过测试,用比例的方式来布局,相关参数适合设置(我测试的手机是三星i9100 galaxy s2,主屏分辨率:800x480像素)如下:

void SettingsViewController::viewDidLoad()
{
    CAImageView* view1 = CAImageView::createWithImage(CAImage::create("image/motor_control_view.jpg"));
    view1->setLayout(DLayoutFill);
    this->getView()->addSubview(view1);


    CALabel* label = CALabel::create();
    label->setColor(ccc4(51, 204, 255, 255));
    label->setText( UTF8( "网络参数设置"));
    label->setFontSize(36);
    label->setTextAlignment(CATextAlignmentLeft);
    label->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);
    label->setLayout(DLayout(DHorizontalLayout_W_C(240, 0.5), DVerticalLayout_H_C(40, 0.12)));
    this->getView()->addSubview(label);

    std::string ctn;
    m_textField_IP = CATextField::createWithLayout(DLayout(DHorizontalLayout_W_C(400, 0.5), DVerticalLayout_H_C(70, 0.30)));
    m_textField_IP->setTag(200);
    //PlaceHolder文本内容
    ctn = "IP: " +m_NetworkInfo.getIP();
    m_textField_IP->setPlaceHolderText(ctn);
    //键盘类型
    m_textField_IP->setKeyboardType(CATextField::Default);
    //TextField的对齐方式
    m_textField_IP->setTextFieldAlign(CATextField::Left);
    m_textField_IP->setDelegate(this);
    this->getView()->addSubview(m_textField_IP);

    m_textField_Port = CATextField::createWithLayout(DLayout(DHorizontalLayout_W_C(400, 0.5), DVerticalLayout_H_C(70, 0.50)));
    m_textField_Port->setTag(201);
    //PlaceHolder文本内容
    char str[256];
    sprintf(str, "Port: %d", m_NetworkInfo.getPort());
    ctn = std::string(str);
    m_textField_Port->setPlaceHolderText(ctn);
    //键盘类型
    m_textField_Port->setKeyboardType(CATextField::Default);
    //TextField的对齐方式
    m_textField_Port->setTextFieldAlign(CATextField::Left);
    m_textField_Port->setDelegate(this);
    this->getView()->addSubview(m_textField_Port);


    //初始化viewList
    m_SaveBtn = CAButton::create(CAButtonTypeRoundedRect);
    m_SaveBtn->setLayout(DLayout(DHorizontalLayout_W_C(240, 0.5), DVerticalLayout_T_H(600, 100)));
    m_SaveBtn->setTag(203);
    m_SaveBtn->setTitleFontSize(36);
    m_SaveBtn->setTitleForState(CAControlStateAll, UTF8("保存参数"));
    m_SaveBtn->addTarget(this, CAControl_selector(SettingsViewController::alertButtonCallBack), CAControlEventTouchUpInSide);
    this->getView()->addSubview(m_SaveBtn);

}

修改之后,运行效果:
基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第32张图片

对于第二个bug,在
void StepMotorControlView::viewDidDisappear()函数最后,加入

    if (m_MQTTInstance)
    {
        delete m_MQTTInstance;
        m_MQTTInstance = NULL;
    }

改后代码:

void StepMotorControlView::viewDidDisappear()
{
    if (m_MQTTInstance && m_MQTTInstance->IsHardwareStarted())
    {
        m_StepMotorHardware.setActionSate(0);
        SendActionMessage(m_StepMotorHardware.getIDX(), m_StepMotorHardware.getActionState(),m_StepMotorHardware.getDirection(),m_StepMotorHardware.getVelocity());
        m_MQTTInstance->StopHardware();
    }

    if (m_MQTTInstance)
    {
        delete m_MQTTInstance;
        m_MQTTInstance = NULL;
    }
}

最后的连接效果:

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第33张图片

四、联合开发板做测试

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第34张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第35张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第36张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第37张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第38张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第39张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第40张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第41张图片

基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版_第42张图片

完整源代码:
StepMotorController_2017.10.03_VS2013 Android.rar

需要说明一下的是,这个版本因为兼容android做了一些修改,而修改后的代码也在VS2013上编译运行过,是可以的,因此,这一版支持了两个平台。

你可能感兴趣的:(物联网与MQTT,CrossApp,android,CrossApp,easySQLite,mosquitto,物联网)