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

来源:互联网 发布:java class method 编辑:程序博客网 时间:2024/05/22 09:42

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

编译环境为VS2013,使用的语言主要是C++。

一、前期准备

本文所使用的跨平台界面库:
CrossApp官网:
http://crossapp.9miao.com/

CrossApp版本 1.5.4
下载地址:
https://github.com/babyliynfg/nano-CrossApp

本文使用的两个第三方库:
1、mosquitto,下载地址:
mosquitto-1.4.9
源码:http://www.eclipse.org/downloads/download.php?file=/mosquitto/source/mosquitto-1.4.9.tar.gz

2、easySQLite

官网地址:
https://code.google.com/archive/p/easysqlite/downloads

下载地址:
https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/easysqlite/easySQLite_v10.zip

本文将分三个部分来实现:
1、工程创建和界面的大致设计规划;
2、数据库的操作;
3、MQTT协议栈和功能实现。

以下是具体内容:

二、工程创建和界面的大致设计规划

解压之后:
这里写图片描述

双击project-creator.exe:
这里写图片描述
工程名填:StepMotorController
package Name那里中间填公司名,本项目随便填了一个MyCompany,最右边填App名字,本项目填StepMotorController
然后点击Create Project Now。
跳出一个对话框来,点确定,然后看到:
这里写图片描述
然后关闭。
看到nano-CrossApp目录下出现一个projects文件夹,这个就是我们项目存放的目录,进去之后看到StepMotorController文件夹,里面就是我们的项目了。

我们先做Windows上的版本,然后再进一步兼容其他平台。

先把框架建起来:

然后双击nano-CrossApp\projects\StepMotorController\proj.win32下的StepMotorController.sln,打开vs工程,把StepMotorController设置为启动项,在debug版编译一下,运行调试,看到:
这里写图片描述

参考CrossApp官方的test代码(在nano-CrossApp\samples\Test目录下),

从test项目下拷贝RootWindow.h、RootWindow.cpp、MenuViewController.h、MenuViewController.cpp

我们添加四个文件:StepMotorControlView.h、StepMotorControlView.cpp、SettingsViewController.h、SettingsViewController.cpp

具体内容如下:
RootWindow.h

#ifndef __HelloCpp__RootWindow__#define __HelloCpp__RootWindow__#include <iostream>#include "CrossApp.h"class RootWindow: public CAWindow, public CAKeypadDelegate{public:    static RootWindow* getInstance();    RootWindow();    virtual ~RootWindow();    virtual bool init();    virtual void draw();    CC_SYNTHESIZE_READONLY(CANavigationController*, m_pRootNavigationController, RootNavigationController);    CC_SYNTHESIZE_READONLY(CADrawerController*, m_pRootDrawerController, DrawerController);    void initUIView();    virtual void keyBackClicked();    void buttonCallBack(CAControl* btn,DPoint point);};#endif /* defined(__HelloCpp__ViewController__) */

RootWindow.cpp:

#include "RootWindow.h"#include "MenuViewController.h"#include "StepMotorControlView.h"#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)#include <jni.h>#include "platform/android/jni/JniHelper.h"#endifstatic RootWindow* _window = NULL;RootWindow* RootWindow::getInstance(){    if (_window == NULL)    {        _window = new RootWindow();        _window->init();        _window->autorelease();    }    return _window;}RootWindow::RootWindow():m_pRootNavigationController(NULL),m_pRootDrawerController(NULL){    CAApplication::getApplication()->getKeypadDispatcher()->addDelegate(this);}RootWindow::~RootWindow(){    CAApplication::getApplication()->getKeypadDispatcher()->removeDelegate(this);    if (m_pRootNavigationController)        m_pRootNavigationController->release();}bool RootWindow::init(){    if (!CAWindow::init())    {        return false;    }    CAApplication::getApplication()->setNotificationView(CAView::createWithFrame(this->getBounds(), CAColor_green));    this->initUIView();    MenuViewController* _menuview = MenuViewController::create();    CADrawerController* drawer = new CADrawerController();    drawer->initWithController(_menuview, m_pRootNavigationController);    drawer->setBackgroundImage(CAImage::create("image/bg.jpg"));    drawer->setEffect3D(true);    this->setRootViewController(drawer);    drawer->autorelease();    m_pRootDrawerController = drawer;    CAApplication::getApplication()->setNotificationView(NULL);    return true;}void RootWindow::draw(){}void RootWindow::initUIView(){    do    {        CAViewController* viewController = m_pRootNavigationController ? m_pRootNavigationController->getViewControllerAtIndex(0) : NULL;        CC_BREAK_IF(dynamic_cast<StepMotorControlView*>(viewController));        StepMotorControlView* tabBarController = new StepMotorControlView();        tabBarController->init();        tabBarController->autorelease();        CANavigationBarItem* temp_nav = CANavigationBarItem::create(UTF8("控制器面板"));        CABarButtonItem* item = CABarButtonItem::create("", CAImage::create("image/ic_category_list.png"), NULL);        item->setTarget(this, CAControl_selector(RootWindow::buttonCallBack));        temp_nav->addLeftButtonItem(item);        tabBarController->setNavigationBarItem(temp_nav);        if (m_pRootNavigationController)        {            m_pRootNavigationController->replaceViewController(tabBarController, false);        }        else        {            m_pRootNavigationController = new CANavigationController();            m_pRootNavigationController->initWithRootViewController(tabBarController);            m_pRootNavigationController->setNavigationBarBackgroundImage(CAImage::create("image/navbg.jpg"));        }    } while (0);    if (m_pRootDrawerController)    {        m_pRootDrawerController->hideLeftViewController(true);    }    CAApplication::getApplication()->setStatusBarStyle(CAStatusBarStyleLightContent);}void RootWindow::buttonCallBack(CAControl* btn,DPoint point){    this->getDrawerController()->showLeftViewController(true);}void RootWindow::keyBackClicked(){    CC_RETURN_IF(CAAlertView::hideWithDisplayed());    if (this->getModalViewController())    {        this->dismissModalViewController(true);    }    else if (this->getDrawerController()->isShowLeftViewController())    {        this->getDrawerController()->hideLeftViewController(true);    }    else if (this->getRootNavigationController()->getViewControllerCount() > 1)    {        this->getRootNavigationController()->popViewControllerAnimated(true);    }    else    {        CAApplication::getApplication()->end();    }}

MenuViewController.h:

////  MenuViewController.h//  Test////  Created by renhongguang on 15/4/3.////#ifndef __Test__MenuViewController__#define __Test__MenuViewController__#include "RootWindow.h"class MenuViewController : public CAViewController, CATableViewDelegate,CATableViewDataSource{public:    MenuViewController();    virtual ~MenuViewController();    CREATE_FUNC(MenuViewController);protected:    void viewDidLoad();    void viewDidUnload();    void changeStatusBarOrientation(CAObject* obj);public:    virtual void tableViewDidSelectRowAtIndexPath(CATableView* table, unsigned int section, unsigned int row);    virtual CATableViewCell* tableCellAtIndex(CATableView* table, const DSize& cellSize, unsigned int section, unsigned int row);    virtual unsigned int numberOfRowsInSection(CATableView *table, unsigned int section);    virtual unsigned int numberOfSections(CATableView *table);    virtual unsigned int tableViewHeightForRowAtIndexPath(CATableView* table, unsigned int section, unsigned int row);private:    CATableView* tableView;    CAImageView* m_pLogo;};#endif /* defined(__Test__MenuViewController__) */

MenuViewController.cpp:

////  MenuViewController.cpp//  Test////  Created by renhongguang on 15/4/3.////#include "MenuViewController.h"#include "SettingsViewController.h"MenuViewController::MenuViewController(){    CANotificationCenter::sharedNotificationCenter()->addObserver(this, callfuncO_selector(MenuViewController::changeStatusBarOrientation), CAApplicationDidChangeStatusBarOrientationNotification, NULL);}MenuViewController::~MenuViewController(){    CANotificationCenter::sharedNotificationCenter()->removeObserver(this, CAApplicationDidChangeStatusBarOrientationNotification);}void MenuViewController::viewDidLoad(){    this->getView()->setColor(CAColor_clear);    DLayout tableViewLayout;    DLayout logoLayout;    const CAInterfaceOrientation& orientation = CAApplication::getApplication()->getStatusBarOrientation();    if (orientation == CAInterfaceOrientationLandscape)    {        tableViewLayout = DLayout(DHorizontalLayoutFill, DVerticalLayout_B_H(0, 400));        logoLayout = DLayout(DHorizontalLayout_W_C(261, 0.5), DVerticalLayout_T_H(120, 258));    }    else    {        tableViewLayout = DLayout(DHorizontalLayoutFill, DVerticalLayout_T_B(450, 0));        logoLayout = DLayout(DHorizontalLayout_W_C(261, 0.5), DVerticalLayout_T_H(120, 258));    }    tableView = CATableView::createWithLayout(DLayoutFill);    tableView->setLayout(tableViewLayout);    tableView->setAllowsSelection(true);    tableView->setTableViewDelegate(this);    tableView->setTableViewDataSource(this);    tableView->setBackgroundColor(CAColor_clear);    tableView->setSeparatorColor(ccc4(166, 166, 166,100));    tableView->setShowsScrollIndicators(false);    tableView->setScrollEnabled(false);    this->getView()->addSubview(tableView);    m_pLogo = CAImageView::createWithImage(CAImage::create("image/logo.png"));    m_pLogo->setLayout(logoLayout);    this->getView()->addSubview(m_pLogo);}void MenuViewController::viewDidUnload(){}void MenuViewController::changeStatusBarOrientation(CAObject* obj){    const CAInterfaceOrientation& orientation = CAApplication::getApplication()->getStatusBarOrientation();    DLayout tableViewLayout;    DLayout logoLayout;    if (orientation == CAInterfaceOrientationLandscape)    {        tableViewLayout = DLayout(DHorizontalLayoutFill, DVerticalLayout_B_H(0, 400));        logoLayout = DLayout(DHorizontalLayout_W_C(261, 0.5), DVerticalLayout_T_H(120, 258));    }    else    {        tableViewLayout = DLayout(DHorizontalLayoutFill, DVerticalLayout_T_B(450, 0));        logoLayout = DLayout(DHorizontalLayout_W_C(261, 0.5), DVerticalLayout_T_H(120, 258));    }    tableView->setLayout(tableViewLayout);    m_pLogo->setLayout(logoLayout);}void MenuViewController::tableViewDidSelectRowAtIndexPath(CATableView* table, unsigned int section, unsigned int row){    RootWindow::getInstance()->dismissModalViewController(true);    if (row == 0)    {        RootWindow::getInstance()->initUIView();    }    else if (row == 1)    {        CAViewController* _settingsViewController = new SettingsViewController();        _settingsViewController->init();        _settingsViewController->setTitle(" ");        _settingsViewController->autorelease();        RootWindow::getInstance()->getDrawerController()->hideLeftViewController(true);        RootWindow::getInstance()->getRootNavigationController()->pushViewController(_settingsViewController, true);    }}#define _T(x) L##x#define CHAR    wchar_tstatic const CHAR* menuList[2] ={    _T("控制器面板"),  _T("服务器设置")//,_T("应用展示"), _T("CrossApp官网"),};CATableViewCell* MenuViewController::tableCellAtIndex(CATableView* table, const DSize& cellSize, unsigned int section, unsigned int row){    CATableViewCell* cell = table->dequeueReusableCellWithIdentifier("CrossApp");    if (cell == NULL)    {        cell = CATableViewCell::create("CrossApp");        cell->setBackgroundView(NULL);        CALabel* test = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_R(50, 0), DVerticalLayoutFill));        test->setTextAlignment(CATextAlignmentLeft);        test->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);        test->setFontSize(32);        test->setColor(CAColor_white);        test->setTag(100);        cell->addSubview(test);        CAImageView* arrow = CAImageView::createWithLayout(DLayout(DHorizontalLayout_R_W(0, 64), DVerticalLayout_T_H(20, 64)));        arrow->setTag(101);        cell->addSubview(arrow);    }    CALabel* test = (CALabel*)cell->getSubviewByTag(100);    test->setText(unicode_to_utf8(menuList[row]));// menuList[row]);    CAImageView* arrow = (CAImageView*)cell->getSubviewByTag(101);    arrow->setImage(CAImage::create("source_material/cell_btn_right.png"));    return cell;}//菜单选项数目unsigned int MenuViewController::numberOfRowsInSection(CATableView *table, unsigned int section){    return 2;}unsigned int MenuViewController::numberOfSections(CATableView *table){    return 1;}unsigned int MenuViewController::tableViewHeightForRowAtIndexPath(CATableView* table, unsigned int section, unsigned int row){    return 100;}

SettingsViewController.h:

#ifndef __SettingsViewController_h__#define __SettingsViewController_h__#include "CrossApp.h"USING_NS_CC;class SettingsViewController : public CAViewController,public CATextFieldDelegate{public:    SettingsViewController();    virtual ~SettingsViewController();    void viewDidLoad();    void viewDidUnload();public:    CAWebView* p_webView;protected:    virtual bool textFieldShouldBeginEditing(CATextField* sender);    //If the sender doesn't want to detach from the IME, return true;    virtual bool textFieldShouldEndEditing(CATextField* sender);    //    virtual void textFieldShouldReturn(CATextField* sender);    virtual void keyBoardHeight(CATextField* sender, int height);    //Warning!!! Warning!!! Warning!!!  This method is not on the OpenGL thread.    virtual bool textFieldShouldChangeCharacters(CATextField* sender,                                                 unsigned int location,                                                 unsigned int lenght,                                                 const std::string& changedText);    void alertButtonCallBack(CAControl* btn,DPoint point);private:    CATextField* m_textField_IP;    CATextField* m_textField_Port;    CATextField* m_textField_Username;    CATextField* m_textField_Password;    CAButton* m_SaveBtn;    std::string m_strIPInput;    std::string m_strPortInput;};#endif /* defined(__SettingsViewController__) */

SettingsViewController.cpp:

#include "SettingsViewController.h"SettingsViewController::SettingsViewController(){}SettingsViewController::~SettingsViewController(){    this->getView()->removeSubview(p_webView);    p_webView = NULL;}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_L_R(100, 100), DVerticalLayout_T_H(250, 100)));    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_L_R(100, 100), DVerticalLayout_T_H(400, 100)));    m_textField_Port->setTag(201);    //PlaceHolder文本内容    char str[256];    sprintf(str,"Port:1883");    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_H_C(54, 0.65)));    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);}void SettingsViewController::viewDidUnload(){}bool SettingsViewController::textFieldShouldBeginEditing(CATextField* sender){    return true;}//If the sender doesn't want to detach from the IME, return true;bool SettingsViewController::textFieldShouldEndEditing(CATextField* sender){    if(sender == m_textField_IP)    {        m_strIPInput = sender->getText();    }    else if(sender == m_textField_Port)    {        m_strPortInput = sender->getText();    }    else if(sender == m_textField_Username)    {    }    else if(sender == m_textField_Password)    {    }    return true;}//void SettingsViewController::textFieldShouldReturn(CATextField* sender){}void SettingsViewController::keyBoardHeight(CATextField* sender, int height){}//Warning!!! Warning!!! Warning!!!  This method is not on the OpenGL thread.bool SettingsViewController::textFieldShouldChangeCharacters(CATextField* sender,                                             unsigned int location,                                             unsigned int lenght,                                                    const std::string& changedText){    return true;}void SettingsViewController::alertButtonCallBack(CAControl* btn,DPoint point){    int tag = btn->getTag();    switch (tag) {        case 203:        {            CAAlertView* alertView = CAAlertView::createWithText(UTF8( "提示"),UTF8(  "保存成功!"),UTF8( "关闭"),NULL);            alertView->show();            break;        }                    default:            break;    }}

StepMotorControlView.h:

#ifndef __StepMotorControlView_h__#define __StepMotorControlView_h__#include <iostream>#include "CrossApp.h"#include "CrossAppExt.h"USING_NS_CC;class StepMotorControlView : public CAViewController{public:    StepMotorControlView();    virtual ~StepMotorControlView();protected:    void viewDidLoad();    void viewDidUnload();private:    void SliderValueChange(CAControl* btn, DPoint point);    CALabel* m_VelocityValue;    CASlider* m_Slider;      void switchStateChange(CAControl* btn, DPoint point);    CASwitch* m_RunSwitch;    CASwitch* m_DirectionSwitch;public:    void SendFCSMessage(const std::string& strFCSMsg);//FilmCenterSettings message    void SendMessage(const char *pszFormat,...);    void SendDirMessage(int idx, int direction);    void SendLoopMessage(int idx, int loop);    void SendRecMessage(int idx, int recording);    void SendStepsMessage(int idx, int recording);    void SendActionMessage(int idx, int action,int direction,int velocity);    void SendVelocityMessage(int idx, int velocity);private:};#endif /* defined(__HelloCpp__ViewController__) */

StepMotorControlView.cpp:

#include "StepMotorControlView.h"#include "platform/CACommon.h"#define FontColor ccc4(51,204,255,255) //ccc4(255,255,255,255)StepMotorControlView::StepMotorControlView()    :m_Slider(NULL){}StepMotorControlView::~StepMotorControlView(){    CADrawerController* drawer = (CADrawerController*)CAApplication::getApplication()->getRootWindow()->getRootViewController();    drawer->setTouchMoved(true);}void StepMotorControlView::viewDidLoad(){    CAImageView* view1 = CAImageView::createWithImage(CAImage::create("image/motor_control_view.jpg"));    view1->setLayout(DLayoutFill);    this->getView()->addSubview(view1);    int var=0;    CALabel* labelDirectionSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(100, 40)));    labelDirectionSwitch->setColor(FontColor);    labelDirectionSwitch->setText(UTF8("方向开关"));    labelDirectionSwitch->setFontSize(30);    labelDirectionSwitch->setTextAlignment(CATextAlignmentCenter);    labelDirectionSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelDirectionSwitch);    m_DirectionSwitch =  CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(100, 20)));    m_DirectionSwitch->setTag(102);    m_DirectionSwitch->setIsOn(var==0?false:true, false);    m_DirectionSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_DirectionSwitch);    //CAView* view1 = CAView::createWithLayout(DLayoutFill);    //view1->setColor(CAColor_gray);    m_VelocityValue = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_R(100, 100), DVerticalLayout_T_H(200, 50)));    m_VelocityValue->setColor(FontColor);    char str[64];    sprintf(str,"%d%%",0x0);//m_StepMotorHardware.getVelocity()    m_VelocityValue->setText(str);    m_VelocityValue->setFontSize(30);    m_VelocityValue->setTextAlignment(CATextAlignmentCenter);    m_VelocityValue->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(m_VelocityValue);    m_Slider = CASlider::createWithLayout(DLayout(DHorizontalLayout_L_R(120, 120), DVerticalLayout_T_H(250, 56)));    m_Slider->addTarget(this, CAControl_selector(StepMotorControlView::SliderValueChange));    m_Slider->setTag(100);    m_Slider->setValue(0);    this->getView()->addSubview(m_Slider);    CALabel* labelStepMotorSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(400, 40)));    labelStepMotorSwitch->setColor(FontColor);    labelStepMotorSwitch->setText(UTF8("电机开关"));    labelStepMotorSwitch->setFontSize(30);    labelStepMotorSwitch->setTextAlignment(CATextAlignmentCenter);    labelStepMotorSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelStepMotorSwitch);    m_RunSwitch = CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(400, 20)));    m_RunSwitch->setTag(101);    var = 0;    m_RunSwitch->setIsOn(var == 0 ? false : true, false);    m_RunSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_RunSwitch);}void StepMotorControlView::viewDidUnload(){    // Release any retained subviews of the main view.    // e.g. self.myOutlet = nil;}void StepMotorControlView::SliderValueChange(CAControl* btn, DPoint point){    char value[20] = "";    CASlider* p_Slider = (CASlider*)btn;    sprintf(value, "%.02f%%", p_Slider->getValue() * 100);    if (p_Slider->getTag()==100) {        m_VelocityValue->setText(value);        static int old_val = (int)(p_Slider->getValue() * 100);        if(old_val != (int)(p_Slider->getValue() * 100))        {            old_val = (int)(p_Slider->getValue() * 100);        }    }}void StepMotorControlView::switchStateChange(CAControl* btn, DPoint point){    CASwitch* state = (CASwitch*)btn;    switch(state->getTag())    {    case 101://action            break;    case 102://direction            break;    default:        break;    }}void StepMotorControlView::SendFCSMessage(const std::string& strFCSMsg){    CCLog("not implement");}#define MAX_TEXT 256void StepMotorControlView::SendMessage(const char *pszFormat,...){    char msg[256]={0};    va_list ap;    va_start(ap, pszFormat);#if defined(_WIN32 )    vsnprintf_s(msg, MAX_TEXT, MAX_TEXT, pszFormat, ap);#else //#elif defined(__GNUC__)    vsnprintf(msg, MAX_TEXT, pszFormat, ap);#endif    va_end(ap);    SendFCSMessage(msg);}void StepMotorControlView::SendDirMessage(int idx, int direction){    SendMessage("{\nidx:%d,\ndir:%d\n}",idx,direction);}void StepMotorControlView::SendLoopMessage(int idx, int loop){    SendMessage("{\nidx:%d,\nloop:%d\n}",idx,loop);}void StepMotorControlView::SendRecMessage(int idx, int recording){    SendMessage("{\nidx:%d,\nrecording:%d\n}",idx,recording);}void StepMotorControlView::SendStepsMessage(int idx, int steps){    SendMessage("{\nidx:%d,\nsteps:%d\n}",idx,steps);}void StepMotorControlView::SendActionMessage(int idx, int action, int direction, int velocity){    SendMessage("{\nidx:%d,\nact:%d,\ndir:%d,\nv:%d\n}",idx,action,direction,velocity);}void StepMotorControlView::SendVelocityMessage(int idx, int velocity){    SendMessage("{\nidx:%d,\nv:%d\n}",idx,velocity);}

把nano-CrossApp\samples\Test下的Resources复制到nano-CrossApp\projects\StepMotorController下。

再找几个1080x1920的图片放到nano-CrossApp\projects\StepMotorController\Resources\image下,作为背景图片。

初步大概的界面效果是:

这里写图片描述

这里写图片描述

这里写图片描述

三、数据库的操作

接下来,把easySQLite移植过来,实现对参数的存取。

把easySQLite_v10.zip\easySQLite\easySQLite下的整个easySQLite拷贝到nano-CrossApp\projects\StepMotorController\Classes目录下。
在vs上的StepMotorCotroller项目的Classes下新建一个筛选器,命名为easySQLite。并把刚才拷贝过来的文件加入进来。
这里写图片描述
F7编译一把,没问题。
其实这里有个问题,在安卓版编译时比较严重,那就是CrossApp框架本身已经集成了sqlite3这个模块进去了,链接会错误说重复定义。vs版没错误。

写三个个辅助类,简化对数据库的操作:
NetworkINFO类,对服务器的参数设置进行数据库操作。
EquipmentINFO类,对步进电机设备参数进行数据库操作。
SettingsHelper类,创建、打开或关闭数据库。

这部分放在SettingsHelper模块中:

SettingsHelper.h:

#ifndef __SETTINGS_HELPER_H__#define __SETTINGS_HELPER_H__#include <string>#include "easySQLite/SqlTable.h"class NetworkINFO{public:    NetworkINFO();    std::string getIP();    void setIP(const std::string& ip);    int getPort();    void setPort(int port);    std::string getUsername();    void setUsername(const std::string& username);    std::string getPassword();    void setPasswork(const std::string& password);    bool SaveToDatabase();    bool ReadFromDatabase();private:    std::string m_MQTTIP;    int m_MQTTIPPort;    std::string m_MQTTUsername;    std::string m_MQTTPassword;    sql::Table m_tbNetworkSettings;};class SlideRailINFO{public:    int getRate();    void setRate(int rate);};class EquipmentINFO{public:    explicit EquipmentINFO(const std::string& name);    int getIDX();    void setIDX(int idx);     int getActionState();    void setActionSate(int state);    int getDirection();    void setDirection(int direction);    int getSteps();    void setSteps(int steps);    int getVelocity();    void setVelocity(int velocity);    int getLoopFlag();    void setLoopFlag(int flag);    int getRecordingFlag();    void setRecordingFlag(int flag);    bool SaveToDatabase();    bool ReadFromDatabase();protected:    int m_IDX;//设备索引号    int m_ActionState;//执行状态    int m_Direction;//方向    int m_Steps;//要转的步数    int m_Velocity;//速度    int m_LoopFlag;//是否循环标志位    int m_RecordingFlag;//是否录制过程标志位    sql::Table m_tbEquipments;};class SettingsHelper{public:    static SettingsHelper* getInstance();    ~SettingsHelper();private:    SettingsHelper();    bool OpenDatabase();    void CloseDatabase();    static SettingsHelper* instance_;};#endif
#include "SettingsHelper.h"#include "easySQLite/SqlCommon.h"#include "easySQLite/SqlField.h"#include "easySQLite/SqlDatabase.h"#include "easySQLite/SqlTable.h"#include "easySQLite/SqlValue.h"#include "CrossApp.h"static sql::Database m_db;using namespace sql;Field definition_tbNetworkSettings[] ={    Field(FIELD_KEY),    Field("ip", type_text, flag_not_null),    Field("port", type_int, flag_not_null),    Field("username", type_text),    Field("password", type_text),    Field(DEFINITION_END),};NetworkINFO::NetworkINFO()    :m_tbNetworkSettings(m_db.getHandle(), "NetworkSettings", definition_tbNetworkSettings){    if (!m_tbNetworkSettings.exists())    {        m_tbNetworkSettings.create();        Record record(m_tbNetworkSettings.fields());        record.setString("ip", "127.0.0.1");        record.setInteger("port", 1883);        record.setNull("username");        record.setNull("password");        if (!m_tbNetworkSettings.addRecord(&record))        {            CCLog("NetworkINFO ERR: addRecord");        }    }    ReadFromDatabase();}std::string NetworkINFO::getIP(){    return m_MQTTIP;}void NetworkINFO::setIP(const std::string& ip){    m_MQTTIP = ip;}int NetworkINFO::getPort(){    return m_MQTTIPPort;}void NetworkINFO::setPort(int port){    m_MQTTIPPort = port;}std::string NetworkINFO::getUsername(){    return m_MQTTUsername;}void NetworkINFO::setUsername(const std::string& username){    m_MQTTUsername = username;}std::string NetworkINFO::getPassword(){    return m_MQTTPassword;}void NetworkINFO::setPasswork(const std::string& password){    m_MQTTPassword = password;}bool NetworkINFO::SaveToDatabase(){    m_tbNetworkSettings.open();    if (Record* record = m_tbNetworkSettings.getRecord(0))    {        record->setString("ip", m_MQTTIP);        record->setInteger("port", m_MQTTIPPort);        record->setString("username",m_MQTTUsername);        record->setString("password",m_MQTTPassword);        return m_tbNetworkSettings.updateRecord(record);    }    else    {        return false;    }}bool NetworkINFO::ReadFromDatabase(){    m_tbNetworkSettings.open();    //int count = m_tbNetworkSettings.recordCount();    Record* record = m_tbNetworkSettings.getRecord(0);    if (record)    {        CCLog(record->toString().c_str());        Value* v= record->getValue("ip");        if (v)        {            //CCLog(v->asString().c_str());            m_MQTTIP = v->asString();        }        v = record->getValue("port");        if (v)        {            m_MQTTIPPort = v->asInteger();        }        v= record->getValue("username");        if (v)        {            //CCLog(v->asString().c_str());            m_MQTTUsername = v->asString();        }        v = record->getValue("password");        if (v)        {            m_MQTTPassword = v->asString();        }        return true;    }    else    {        return false;    }}//--------------------------------------------------------/*    const std::string m_Name;    int m_IDX;    int m_ActionState;    int m_Direction;    int m_Steps;    int m_Velocity;    int m_LoopFlag;    int m_RecordingFlag;*/Field definition_tbEquipments[] ={    Field(FIELD_KEY),    Field("name", type_text, flag_not_null),    Field("idx", type_int, flag_not_null),    Field("actionsate", type_int, flag_not_null),    Field("direction", type_int, flag_not_null),    Field("steps", type_int, flag_not_null),    Field("velocity", type_int, flag_not_null),    Field("loopflag", type_int, flag_not_null),    Field("recordingflag", type_int, flag_not_null),    Field(DEFINITION_END),};EquipmentINFO::EquipmentINFO(const std::string& name)    :m_tbEquipments(m_db.getHandle(), name, definition_tbEquipments){    if (!m_tbEquipments.exists())    {        m_tbEquipments.create();        Record record(m_tbEquipments.fields());        record.setString("name", name);        record.setInteger("idx", 0);        record.setInteger("actionsate", 0);        record.setInteger("direction", 0);        record.setInteger("steps", 0);        record.setInteger("velocity", 0);        record.setInteger("loopflag", 0);        record.setInteger("recordingflag", 0);        if (!m_tbEquipments.addRecord(&record))        {            CCLog("EquipmentINFO ERR: addRecord");        }    }    ReadFromDatabase();}int EquipmentINFO::getIDX(){    return m_IDX;}void EquipmentINFO::setIDX(int idx){    m_IDX = idx>=0?idx:0;} int EquipmentINFO::getActionState(){    return m_ActionState;}void EquipmentINFO::setActionSate(int state){    m_ActionState = state>0?1:0;}int EquipmentINFO::getDirection(){    return m_Direction;}void EquipmentINFO::setDirection(int direction){    m_Direction = direction>0?1:0;}int EquipmentINFO::getSteps(){    return m_Steps;}void EquipmentINFO::setSteps(int steps){    m_Steps = steps>0?steps:0;}int EquipmentINFO::getVelocity(){    return m_Velocity;}void EquipmentINFO::setVelocity(int velocity){    m_Velocity = velocity>0?velocity:0;}int EquipmentINFO::getLoopFlag(){    return m_LoopFlag;}void EquipmentINFO::setLoopFlag(int flag){    m_LoopFlag = flag>0?1:0;}int EquipmentINFO::getRecordingFlag(){    return m_RecordingFlag;}void EquipmentINFO::setRecordingFlag(int flag){    m_RecordingFlag = flag>0?1:0;}bool EquipmentINFO::SaveToDatabase(){    m_tbEquipments.open();    if (Record* record = m_tbEquipments.getRecord(0))    {        record->setInteger("idx", m_IDX);        record->setInteger("actionsate", m_ActionState);        record->setInteger("direction", m_Direction);        record->setInteger("steps", m_Steps);        record->setInteger("velocity", m_Velocity);        record->setInteger("loopflag", m_LoopFlag);        record->setInteger("recordingflag", m_RecordingFlag);        return m_tbEquipments.updateRecord(record);    }    else    {        return false;    }}bool EquipmentINFO::ReadFromDatabase(){    m_tbEquipments.open();    //int count = m_tbNetworkSettings.recordCount();    Record* record = m_tbEquipments.getRecord(0);    if (record)    {        CCLog(record->toString().c_str());        Value* v= record->getValue("idx");        if (v)        {            m_IDX = v->asInteger();        }        v= record->getValue("actionsate");        if (v)        {            m_ActionState = v->asInteger();        }        v= record->getValue("direction");        if (v)        {            m_Direction = v->asInteger();        }        v= record->getValue("steps");        if (v)        {            m_Steps = v->asInteger();        }        v= record->getValue("velocity");        if (v)        {            m_Velocity = v->asInteger();        }        v= record->getValue("loopflag");        if (v)        {            m_LoopFlag = v->asInteger();        }        v= record->getValue("recordingflag");        if (v)        {            m_RecordingFlag = v->asInteger();        }        return true;    }    else    {        return false;    }}//--------------------------------------------------------SettingsHelper* SettingsHelper::instance_ = NULL;SettingsHelper* SettingsHelper::getInstance(){    if(instance_== NULL)    {        instance_ = new SettingsHelper();    }    return instance_;}SettingsHelper::SettingsHelper(){    OpenDatabase(); }SettingsHelper::~SettingsHelper(){    CloseDatabase();} bool SettingsHelper::OpenDatabase()  {     std::string path= CCFileUtils::sharedFileUtils()->getWritablePath()+"Equipments.db";    try    {        m_db.open(path);        //...    } catch (Exception e) {        //...        CCLog("open database failed:[ %s ]",e.msg().c_str());    }     return true;  } void SettingsHelper::CloseDatabase() {    m_db.close(); }

修改SettingsViewCotorller.h:

#ifndef __SettingsViewController_h__#define __SettingsViewController_h__#include "CrossApp.h"#include "SettingsHelper.h"USING_NS_CC;class SettingsViewController : public CAViewController,public CATextFieldDelegate{public:    SettingsViewController();    virtual ~SettingsViewController();    void viewDidLoad();    void viewDidUnload();public:    CAWebView* p_webView;protected:    virtual bool textFieldShouldBeginEditing(CATextField* sender);    //If the sender doesn't want to detach from the IME, return true;    virtual bool textFieldShouldEndEditing(CATextField* sender);    //    virtual void textFieldShouldReturn(CATextField* sender);    virtual void keyBoardHeight(CATextField* sender, int height);    //Warning!!! Warning!!! Warning!!!  This method is not on the OpenGL thread.    virtual bool textFieldShouldChangeCharacters(CATextField* sender,                                                 unsigned int location,                                                 unsigned int lenght,                                                 const std::string& changedText);    void alertButtonCallBack(CAControl* btn,DPoint point);private:    NetworkINFO m_NetworkInfo;    CATextField* m_textField_IP;    CATextField* m_textField_Port;    CATextField* m_textField_Username;    CATextField* m_textField_Password;    CAButton* m_SaveBtn;    std::string m_strIPInput;    std::string m_strPortInput;};#endif /* defined(__SettingsViewController__) */

SettingsViewController.cpp修改如下:

#include "SettingsViewController.h"SettingsViewController::SettingsViewController(){    CCLog(m_NetworkInfo.getIP().c_str());    CCLog("%d", m_NetworkInfo.getPort());    CCLog(m_NetworkInfo.getUsername().c_str());    CCLog(m_NetworkInfo.getPassword().c_str());}SettingsViewController::~SettingsViewController(){    this->getView()->removeSubview(p_webView);    p_webView = NULL;}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_L_R(100, 100), DVerticalLayout_T_H(250, 100)));    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_L_R(100, 100), DVerticalLayout_T_H(400, 100)));    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_H_C(54, 0.65)));    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);}void SettingsViewController::viewDidUnload(){}bool SettingsViewController::textFieldShouldBeginEditing(CATextField* sender){    return true;}//If the sender doesn't want to detach from the IME, return true;bool SettingsViewController::textFieldShouldEndEditing(CATextField* sender){    if(sender == m_textField_IP)    {        m_strIPInput = sender->getText();    }    else if(sender == m_textField_Port)    {        m_strPortInput = sender->getText();    }    else if(sender == m_textField_Username)    {    }    else if(sender == m_textField_Password)    {    }    return true;}//void SettingsViewController::textFieldShouldReturn(CATextField* sender){}void SettingsViewController::keyBoardHeight(CATextField* sender, int height){}//Warning!!! Warning!!! Warning!!!  This method is not on the OpenGL thread.bool SettingsViewController::textFieldShouldChangeCharacters(CATextField* sender,                                             unsigned int location,                                             unsigned int lenght,                                                    const std::string& changedText){    return true;}void SettingsViewController::alertButtonCallBack(CAControl* btn,DPoint point){    int tag = btn->getTag();    switch (tag) {        case 203:        {            if (!m_strIPInput.empty())                m_NetworkInfo.setIP(m_strIPInput);            if (!m_strPortInput.empty())                m_NetworkInfo.setPort(atoi(m_strPortInput.c_str()));            m_NetworkInfo.SaveToDatabase();            CAAlertView* alertView = CAAlertView::createWithText(UTF8("提示"), UTF8("保存成功!"), UTF8("关闭"), NULL);            alertView->show();            break;        }                    default:            break;    }}

接下来,要为SettingsHelper类实例化。
在AppDelegate.h中加入

#include "SettingsHelper.h"

在类AppDelegate中加入成员数据:

SettingsHelper *m_SettingsHelper;

在AppDelegate的构造函数中加入对其赋值:

AppDelegate::AppDelegate(){    m_SettingsHelper = SettingsHelper::getInstance();//added @2017.10.01}

编译运行,看看效果:
这里写图片描述

在 bool SettingsHelper::OpenDatabase() 中打上断点,重新运行到断点,可以看到:

这里写图片描述

这是我们的数据库存放的具体位置,手动找到这个数据库如下:

这里写图片描述

修改一下界面中的参数、保存,验证一下功能:
这里写图片描述

退出后重进,可以看到前面保存的参数已经读出来了。

然后在StepMotorControlView类中加入成员变量:

    EquipmentINFO m_StepMotorHardware;

然后子修改StepMotorControlView.cpp:

#include "StepMotorControlView.h"#include "platform/CACommon.h"#define FontColor ccc4(51,204,255,255) //ccc4(255,255,255,255)StepMotorControlView::StepMotorControlView()    :m_Slider(NULL), m_StepMotorHardware("mainstepmotor"){}StepMotorControlView::~StepMotorControlView(){    CADrawerController* drawer = (CADrawerController*)CAApplication::getApplication()->getRootWindow()->getRootViewController();    drawer->setTouchMoved(true);    m_StepMotorHardware.SaveToDatabase();}void StepMotorControlView::viewDidLoad(){    CAImageView* view1 = CAImageView::createWithImage(CAImage::create("image/motor_control_view.jpg"));    view1->setLayout(DLayoutFill);    this->getView()->addSubview(view1);    int var=0;    CALabel* labelDirectionSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(100, 40)));    labelDirectionSwitch->setColor(FontColor);    labelDirectionSwitch->setText(UTF8("方向开关"));    labelDirectionSwitch->setFontSize(30);    labelDirectionSwitch->setTextAlignment(CATextAlignmentCenter);    labelDirectionSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelDirectionSwitch);    m_DirectionSwitch =  CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(100, 20)));    m_DirectionSwitch->setTag(102);    var = m_StepMotorHardware.getDirection();    m_DirectionSwitch->setIsOn(var==0?false:true, false);    m_DirectionSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_DirectionSwitch);    //CAView* view1 = CAView::createWithLayout(DLayoutFill);    //view1->setColor(CAColor_gray);    m_VelocityValue = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_R(100, 100), DVerticalLayout_T_H(200, 50)));    m_VelocityValue->setColor(FontColor);    char str[64];    sprintf(str, "%d%%", m_StepMotorHardware.getVelocity());    m_VelocityValue->setText(str);    m_VelocityValue->setFontSize(30);    m_VelocityValue->setTextAlignment(CATextAlignmentCenter);    m_VelocityValue->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(m_VelocityValue);    m_Slider = CASlider::createWithLayout(DLayout(DHorizontalLayout_L_R(120, 120), DVerticalLayout_T_H(250, 56)));    m_Slider->addTarget(this, CAControl_selector(StepMotorControlView::SliderValueChange));    m_Slider->setTag(100);    m_Slider->setValue((float)m_StepMotorHardware.getVelocity() / (m_Slider->getMaxValue() * 100));    this->getView()->addSubview(m_Slider);    CALabel* labelStepMotorSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(400, 40)));    labelStepMotorSwitch->setColor(FontColor);    labelStepMotorSwitch->setText(UTF8("电机开关"));    labelStepMotorSwitch->setFontSize(30);    labelStepMotorSwitch->setTextAlignment(CATextAlignmentCenter);    labelStepMotorSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelStepMotorSwitch);    m_RunSwitch = CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(400, 20)));    m_RunSwitch->setTag(101);    var = m_StepMotorHardware.getActionState();    m_RunSwitch->setIsOn(var == 0 ? false : true, false);    m_RunSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_RunSwitch);}void StepMotorControlView::viewDidUnload(){    // Release any retained subviews of the main view.    // e.g. self.myOutlet = nil;    m_StepMotorHardware.SaveToDatabase();}void StepMotorControlView::SliderValueChange(CAControl* btn, DPoint point){    char value[20] = "";    CASlider* p_Slider = (CASlider*)btn;    int v = (int)(p_Slider->getValue() * 100);    sprintf(value, "%d%%", v);    if (p_Slider->getTag()==100) {        m_VelocityValue->setText(value);        static int old_val = v;        if(old_val != v)        {            old_val = v;            m_StepMotorHardware.setVelocity(old_val);        }    }}void StepMotorControlView::switchStateChange(CAControl* btn, DPoint point){    CASwitch* state = (CASwitch*)btn;    switch(state->getTag())    {    case 101://action            if (state->isOn())            {                //CCLog("switchStateChange 101: false");                m_StepMotorHardware.setActionSate(1);            }            else            {                //CCLog("switchStateChange 101: true");                m_StepMotorHardware.setActionSate(0);            }            break;    case 102://direction            if (state->isOn())            {                //CCLog("switchStateChange 102: false");                m_StepMotorHardware.setDirection(1);            }            else            {                //CCLog("switchStateChange 102:true");                m_StepMotorHardware.setDirection(0);        }            break;    default:        break;    }}void StepMotorControlView::SendFCSMessage(const std::string& strFCSMsg){    CCLog("not implement");}#define MAX_TEXT 256void StepMotorControlView::SendMessage(const char *pszFormat,...){    char msg[256]={0};    va_list ap;    va_start(ap, pszFormat);#if defined(_WIN32 )    vsnprintf_s(msg, MAX_TEXT, MAX_TEXT, pszFormat, ap);#else //#elif defined(__GNUC__)    vsnprintf(msg, MAX_TEXT, pszFormat, ap);#endif    va_end(ap);    SendFCSMessage(msg);}void StepMotorControlView::SendDirMessage(int idx, int direction){    SendMessage("{\nidx:%d,\ndir:%d\n}",idx,direction);}void StepMotorControlView::SendLoopMessage(int idx, int loop){    SendMessage("{\nidx:%d,\nloop:%d\n}",idx,loop);}void StepMotorControlView::SendRecMessage(int idx, int recording){    SendMessage("{\nidx:%d,\nrecording:%d\n}",idx,recording);}void StepMotorControlView::SendStepsMessage(int idx, int steps){    SendMessage("{\nidx:%d,\nsteps:%d\n}",idx,steps);}void StepMotorControlView::SendActionMessage(int idx, int action, int direction, int velocity){    SendMessage("{\nidx:%d,\nact:%d,\ndir:%d,\nv:%d\n}",idx,action,direction,velocity);}void StepMotorControlView::SendVelocityMessage(int idx, int velocity){    SendMessage("{\nidx:%d,\nv:%d\n}",idx,velocity);}

到此,电机操作界面部分也可以存取相应的参数了。

四、MQTT协议栈和功能实现

先交待一下大致功能:
本实现将在进入主界面(运行本软件看到的第一个界面——也即控制器面板)后立即读取网络设置,并根据网络设置进行连接,而一旦退出主界面进行其他操作,那么立即断开,当再次进入主界面,则重新连接。

下面是具体实现:

接下来,移植mosquito。

首先在nano-CrossApp\projects\StepMotorController\Classes目录下建一个MQTT空文件夹,把:
1、mosquitto-1.4.9.tar.gz\mosquitto-1.4.9\lib 里面所有的头文件和c文件
2、mosquitto-1.4.9.tar.gz\mosquitto-1.4.9\lib\cpp下的mosquittopp.h、和mosquittopp.cpp
3、mosquitto-1.4.9.tar.gz\mosquitto-1.4.9下的config.h
4、mosquitto-1.4.9.tar.gz\mosquitto-1.4.9\src下的lib_load.h、mosquitto_broker.h、mosquitto_plugin.h、persist.h、uthash.h
都拷贝到MQTT目录下:
这里写图片描述
这里写图片描述

把MQTT的源码文件加入到VS的工程中,把..\Classes\MQTT加入包含目录:

这里写图片描述

这里写图片描述

编译一下,可以通过,但是链接出现错误:

2>mosquitto.obj : error LNK2019: 无法解析的外部符号 ___WSAFDIsSet@8,该符号在函数 _mosquitto_loop 中被引用2>mosquitto.obj : error LNK2019: 无法解析的外部符号 __imp__closesocket@4,该符号在函数 __mosquitto_connect_init 中被引用2>net_mosq.obj : error LNK2001: 无法解析的外部符号 __imp__closesocket@42>mosquitto.obj : error LNK2019: 无法解析的外部符号 __imp__recv@16,该符号在函数 _mosquitto_loop 中被引用2>net_mosq.obj : error LNK2001: 无法解析的外部符号 __imp__recv@162>mosquitto.obj : error LNK2019: 无法解析的外部符号 __imp__select@20,该符号在函数 _mosquitto_loop 中被引用2>mosquitto.obj : error LNK2019: 无法解析的外部符号 __imp__WSAGetLastError@0,该符号在函数 _mosquitto_loop 中被引用2>net_mosq.obj : error LNK2001: 无法解析的外部符号 __imp__WSAGetLastError@02>mosquittopp.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) const mosqpp::mosquittopp::`vftable'" (__imp_??_7mosquittopp@mosqpp@@6B@),该符号在函数 "public: __thiscall mosqpp::mosquittopp::mosquittopp(char const *,bool)" (??0mosquittopp@mosqpp@@QAE@PBD_N@Z) 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__accept@12,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__bind@12,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__connect@12,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__ioctlsocket@12,该符号在函数 __mosquitto_socket_nonblock 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__getsockname@12,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__htonl@4,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__htons@4,该符号在函数 __mosquitto_try_connect 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__listen@8,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__send@16,该符号在函数 __mosquitto_net_write 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__socket@12,该符号在函数 __mosquitto_socketpair 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__WSAStartup@8,该符号在函数 __mosquitto_net_init 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__WSACleanup@0,该符号在函数 __mosquitto_net_cleanup 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__getaddrinfo@16,该符号在函数 __mosquitto_try_connect 中被引用2>net_mosq.obj : error LNK2019: 无法解析的外部符号 __imp__freeaddrinfo@4,该符号在函数 __mosquitto_try_connect 中被引用2>net_mosq.obj : error LNK2001: 无法解析的外部符号 _in6addr_loopback2>C:\download\nano-CrossApp\projects\StepMotorController\proj.win32\Debug.win32\StepMotorController.exe : fatal error LNK1120: 21 个无法解析的外部命令========== 生成:  成功 1 个,失败 1 个,最新 2 个,跳过 0 个 ==========

大多数的错误是因为缺少一个库:ws2_32.lib,在附加依赖项中加上即可:
这里写图片描述

F7再编译一下,还有一个错误:

2>mosquittopp.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) const mosqpp::mosquittopp::`vftable'" (__imp_??_7mosquittopp@mosqpp@@6B@),该符号在函数 "public: __thiscall mosqpp::mosquittopp::mosquittopp(char const *,bool)" (??0mosquittopp@mosqpp@@QAE@PBD_N@Z) 中被引用2>C:\download\nano-CrossApp\projects\StepMotorController\proj.win32\Debug.win32\StepMotorController.exe : fatal error LNK1120: 1 个无法解析的外部命令

这个错误原因在mosquittopp.h中对dll导入声明上:

#ifdef _WIN32#   ifdef mosquittopp_EXPORTS#       define mosqpp_EXPORT  __declspec(dllexport)#   else#       define mosqpp_EXPORT  __declspec(dllimport)#   endif#else#   define mosqpp_EXPORT#endif

因为我们用的是mosquitto的源码,而不是dll库,所以,应该把这个声明去掉。改为:

#define mosqpp_EXPORT

F7编译链接, 通过。

另外,mosquitto.h中的libmosq_EXPORT也如此处理:

#define libmosq_EXPORT

再有,还要在nano-CrossApp\projects\StepMotorController\Classes\MQTT\config.h中加入:

#define WITH_THREADING

以支持线程操作,否则,会在后面启动前程后不断出现异常。

接下来就是使用mosqpp::mosquittopp类写个派生类MQTT,来完成我的目标。
我们用MQTT类收发MQTT协议消息的时候,需要起另外的线程。
原CAThread类的退出线程的方式不符合我们要求,甚至导致崩溃,因此我们需要照葫芦画瓢,写个PlatformThread类:

PlatformThread.h:

#ifndef __CAPLATFORM_THREAD_H__#define __CAPLATFORM_THREAD_H__#include "platform/CCPlatformMacros.h"#include "ccMacros.h"#include "basics/CASyncQueue.h"#include <pthread.h>class PlatformThreadDelegate{public:    virtual ~PlatformThreadDelegate(){}    virtual void run()=0;};enum PlatformThreadRunType{    PlatformThreadRunDirectly,    PlatformThreadRunNotify};typedef bool (*THREAD_PROC_FUNC_t)(void* lpParameter);class PlatformThread{public:    PlatformThread(PlatformThreadDelegate* thread_delegate );    virtual ~PlatformThread();    void start();    void startAndWait(THREAD_PROC_FUNC_t func);    void notifyRun(void* param);    void clear(bool bFree=false);    int join();    void close();    void closeAtOnce();    void setMaxMsgCount(int v);    bool isRunning();    //-- put the initialization code here.    virtual void OnInitInstance() {}    ////-- put the main code of the thread here.    //virtual void OnRunning() {}    //-- put the cleanup code here.    virtual void OnExitInstance() {}    PlatformThreadDelegate* delegate(){return delegate_;}protected:    PlatformThreadDelegate* delegate_;private:    static void* _ThreadProc(void* lpParameter);    pthread_t m_hThread;    pthread_mutex_t m_SleepMutex;    pthread_cond_t m_SleepCondition;    int m_iMaxMsgCount;    CrossApp::CASyncQueue<void*> m_ThreadDataQueue;    THREAD_PROC_FUNC_t m_pThreadFunc;    bool m_bIsRunning;    PlatformThreadRunType m_ThreadRunType;};#endif   

PlatformThread.cpp:

#include "PlatformThread.h"#ifndef usleep#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32#include "the_third_party/websockets/include/win32/libwebsockets.h"#elif  CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID#include "the_third_party/websockets/include/android/libwebsockets.h"#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS#include "the_third_party/websockets/include/ios/libwebsockets.h"#endif#endifPlatformThread::PlatformThread(PlatformThreadDelegate* thread_delegate ):delegate_(thread_delegate) , m_bIsRunning(false), m_pThreadFunc(NULL), m_iMaxMsgCount(32){    pthread_mutex_init(&m_SleepMutex, NULL);    pthread_cond_init(&m_SleepCondition, NULL);}PlatformThread::~PlatformThread(){    close();    pthread_mutex_destroy(&m_SleepMutex);    pthread_cond_destroy(&m_SleepCondition);}void PlatformThread::start(){    m_ThreadRunType = PlatformThreadRunDirectly;#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)    pthread_create(&m_hThread, NULL, _ThreadProc, this);#endif}void PlatformThread::startAndWait(THREAD_PROC_FUNC_t func){    m_ThreadRunType = PlatformThreadRunNotify;#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)    pthread_create(&m_hThread, NULL, _ThreadProc, this);#endif    m_pThreadFunc = func;}void PlatformThread::notifyRun(void* param){    if (m_ThreadDataQueue.GetCount() < m_iMaxMsgCount)    {        m_ThreadDataQueue.AddElement(param);    }}void PlatformThread::clear(bool bFree){    if (bFree)    {        std::vector< void* > v = m_ThreadDataQueue.GetQueueElements();        for (int i = 0; i < v.size(); i++)        {            CC_SAFE_FREE(v[i]);        }    }    else    {        m_ThreadDataQueue.Clear();    }}int PlatformThread::join(){    return pthread_join(m_hThread, NULL);}void PlatformThread::close(){    if (m_bIsRunning)    {        m_bIsRunning = false;        pthread_cond_wait(&m_SleepCondition, &m_SleepMutex);        pthread_detach(m_hThread);    }}void PlatformThread::closeAtOnce(){    m_ThreadDataQueue.Clear();    close();}void PlatformThread::setMaxMsgCount(int v){    m_iMaxMsgCount = v;}bool PlatformThread::isRunning(){    return m_bIsRunning;}void* PlatformThread::_ThreadProc(void* lpParameter){    PlatformThread *pAThread = (PlatformThread*)lpParameter;    CCAssert(pAThread != NULL, "");    pAThread->m_bIsRunning = true;    pAThread->OnInitInstance();    pthread_mutex_lock(&pAThread->m_SleepMutex);    while (pAThread->m_bIsRunning)    {        if (pAThread->m_ThreadRunType == PlatformThreadRunDirectly)        {            if(pAThread->delegate())                pAThread->delegate()->run();            //pAThread->OnRunning();        }        else if (pAThread->m_ThreadRunType == PlatformThreadRunNotify)        {            void* param = NULL;            if (pAThread->m_ThreadDataQueue.PopElement(param))            {                if (pAThread->m_pThreadFunc)                {                    if (!pAThread->m_pThreadFunc(param))                        break;                }            }            else            {#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32                Sleep(5);#else                usleep(5000);#endif            }        }        else break;    }    pthread_mutex_unlock(&pAThread->m_SleepMutex);    pAThread->OnExitInstance();    pAThread->m_bIsRunning = false;    pthread_cond_signal(&pAThread->m_SleepCondition);    pAThread->join();    //pthread_exit((void *)0);    return 0;}

接下来就是真正实现MQTT的类:
MQTT.h

#pragma once#include "CrossApp.h"#include "mosquittopp.h"#include "PlatformThread.h"#define CLIENTID    "FC"#define TOPIC_FCS_OUT   "FCS/out" //FilmCenterSettings#define TOPIC_FCS_IN    "FCS/in"#define TOPIC_FCA_OUT   "FCA/out" //FilmCenterAction#define TOPIC_FCA_IN    "FCA/in"class MQTT :mosqpp::mosquittopp,public PlatformThreadDelegate{public:    MQTT(const std::string &IPAddress, const unsigned short usIPPort, const std::string &Username, const std::string &Password, const std::string &CAFile);//CAFile是证书文件名,供SSL验证用的    ~MQTT(void);    bool isConnected(){ return m_IsConnected; };    void on_connect(int rc);    void on_disconnect(int rc);    void on_message(const struct mosquitto_message *message);    void on_subscribe(int mid, int qos_count, const int *granted_qos);    void SendMessage(const std::string &Topic, const std::string &Message);    bool m_bDoReconnect;    bool m_IsConnected;public:    void run(){Do_Work();}    bool StartHardware();    bool StopHardware();    bool IsHardwareStarted(){return m_bIsMQTTStarted;}private:    bool ConnectInt();    bool ConnectIntEx();    void ProcessMySensorsMessage(const std::string &MySensorsMessage);protected:    std::string m_szIPAddress;    unsigned short m_usIPPort;    std::string m_UserName;    std::string m_Password;    std::string m_CAFilename;    void StopMQTT();    void Do_Work();    volatile bool m_stoprequested;    volatile bool m_exitrequested;private:    CALock m_Lock;    bool m_bIsMQTTStarted;protected:    PlatformThread* thread_;};

MQTT.cpp:

#include "MQTT.h"#include <iostream>#define RETRY_DELAY 30#define QOS         1#ifdef WIN32    #include <windows.h>#else    #include <unistd.h>#endifvoid sleep_seconds(unsigned int seconds){#ifdef WIN32                Sleep(seconds*1000);#else                sleep(seconds);#endif}void sleep_milliseconds(unsigned int ms){#ifdef WIN32                Sleep(ms);#else                usleep(ms*1000);#endif}MQTT::MQTT(const std::string &IPAddress, const unsigned short usIPPort, const std::string &Username, const std::string &Password, const std::string &CAfilename) :m_szIPAddress(IPAddress),m_UserName(Username),m_Password(Password),m_CAFilename(CAfilename),m_bIsMQTTStarted(false){    m_IsConnected = false;    m_bDoReconnect = false;    mosqpp::lib_init();    m_stoprequested=false;    m_exitrequested=false;//...    m_usIPPort=usIPPort;}MQTT::~MQTT(void){    mosqpp::lib_cleanup();}bool MQTT::StartHardware(){    thread_ = new PlatformThread(this);    if(!thread_)    {        CCLog("error: thread_=NULL!");        return false;    }    m_stoprequested=false;    //force connect the next first time    m_IsConnected = false;    //if(!isRunning())    //  PlatformThread::start();    //else    //{    //  resume();    //}    m_bIsMQTTStarted = true;    thread_->start();    return true;}void MQTT::StopMQTT(){    disconnect();}bool MQTT::StopHardware(){    m_stoprequested=true;    //if (m_sConnection.connected())    //  m_sConnection.disconnect();    m_IsConnected = false;    m_bIsMQTTStarted = false;    StopMQTT();    if(thread_)    {           delete thread_;        thread_ = NULL;    }    return true;}void MQTT::on_subscribe(int mid, int qos_count, const int *granted_qos){    CCLog("MQTT: Subscribed");    m_IsConnected = true;}void MQTT::on_connect(int rc){    /* rc=    ** 0 - success    ** 1 - connection refused(unacceptable protocol version)    ** 2 - connection refused(identifier rejected)    ** 3 - connection refused(broker unavailable)    */    if (rc == 0){        if (m_IsConnected) {            CCLog("MQTT: re-connected to: %s:%ld", m_szIPAddress.c_str(), m_usIPPort);        } else {            CCLog("MQTT: connected to: %s:%ld", m_szIPAddress.c_str(), m_usIPPort);            m_IsConnected = true;            //sOnConnected(this);        }        subscribe(NULL, TOPIC_FCS_IN);//.....        subscribe(NULL, TOPIC_FCA_IN);    }    else {        CCLog("MQTT: Connection failed!, restarting (rc=%d)",rc);        m_bDoReconnect = true;    }}void MQTT::on_message(const struct mosquitto_message *message){    std::string topic = message->topic;    std::string qMessage = std::string((char*)message->payload, (char*)message->payload + message->payloadlen);    CCLog("MQTT: Topic: %s, Message: %s", topic.c_str(), qMessage.c_str());    if (qMessage.empty())        return;    //收到消息后处理过程    if (topic == TOPIC_FCS_IN ||topic == TOPIC_FCA_IN)    {        ProcessMySensorsMessage(qMessage);    }}void MQTT::on_disconnect(int rc){    if (rc != 0)    {        if (!m_stoprequested)        {            if (rc == 5)            {                CCLog("MQTT: disconnected, Invalid Username/Password (rc=%d)", rc);            }            else            {                CCLog("MQTT: disconnected, restarting (rc=%d)", rc);            }            m_bDoReconnect = true;        }    }}bool MQTT::ConnectInt(){    StopMQTT();    return ConnectIntEx();}bool MQTT::ConnectIntEx(){    m_bDoReconnect = false;    CCLog("MQTT: Connecting to %s:%d", m_szIPAddress.c_str(), m_usIPPort);    int rc;    int keepalive = 60;    if (!m_CAFilename.empty()){        rc = tls_set(m_CAFilename.c_str());        if ( rc != MOSQ_ERR_SUCCESS)        {            CCLog("MQTT: Failed enabling TLS mode, return code: %d (CA certificate: '%s')", rc, m_CAFilename.c_str());            return false;        } else {            CCLog("MQTT: enabled TLS mode");        }    }    rc = username_pw_set((!m_UserName.empty()) ? m_UserName.c_str() : NULL, (!m_Password.empty()) ? m_Password.c_str() : NULL);    rc = connect(m_szIPAddress.c_str(), m_usIPPort, keepalive);    if ( rc != MOSQ_ERR_SUCCESS)    {        CCLog("MQTT: Failed to start, return code: %d (Check IP/Port)", rc);        m_bDoReconnect = true;        return false;    }    return true;}void MQTT::Do_Work(){    bool bFirstTime=true;    int msec_counter = 0;    int sec_counter = 0;    while (!m_stoprequested)    {        sleep_milliseconds(100);        if (!bFirstTime)        {            int rc = loop();            if (rc) {                if (rc != MOSQ_ERR_NO_CONN)                {                    if (!m_stoprequested)                    {                        if (!m_bDoReconnect)                        {                            reconnect();                        }                    }                }            }        }        msec_counter++;        if (msec_counter == 10)        {            msec_counter = 0;            sec_counter++;            if (bFirstTime)            {                bFirstTime = false;                ConnectInt();            }            else            {                if (sec_counter % 30 == 0)                {                    if (m_bDoReconnect)                        ConnectIntEx();                }            }        }    }    CCLog("MQTT: Worker stopped...");}void MQTT::SendMessage(const std::string &Topic, const std::string &Message){    try {        if (!m_IsConnected)        {            CCLog("MQTT: Not Connected, failed to send message: %s", Message.c_str());            return;        }        publish(NULL, Topic.c_str(), Message.size(), Message.c_str());    }    catch (...)    {        CCLog("MQTT: Failed to send message: %s", Message.c_str());    }}void MQTT::ProcessMySensorsMessage(const std::string &MySensorsMessage){    //有待进一步实现    CCLog("MQTT::ProcessMySensorsMessage not implement.");}

接下来,要修改一下StepMotorControlView类:
StepMotorControlView.h:

#ifndef __StepMotorControlView_h__#define __StepMotorControlView_h__#include <iostream>#include "CrossApp.h"#include "CrossAppExt.h"#include "SettingsHelper.h"#include "MQTT.h"USING_NS_CC;class StepMotorControlView : public CAViewController{public:    StepMotorControlView();    virtual ~StepMotorControlView();protected:    void viewDidLoad();    void viewDidUnload();    virtual void viewDidAppear();    virtual void viewDidDisappear();private:    void SliderValueChange(CAControl* btn, DPoint point);    CALabel* m_VelocityValue;    CASlider* m_Slider;      void switchStateChange(CAControl* btn, DPoint point);    CASwitch* m_RunSwitch;    CASwitch* m_DirectionSwitch;public:    void SendFCSMessage(const std::string& strFCSMsg);//FilmCenterSettings message    void SendMessage(const char *pszFormat,...);    void SendDirMessage(int idx, int direction);    void SendLoopMessage(int idx, int loop);    void SendRecMessage(int idx, int recording);    void SendStepsMessage(int idx, int recording);    void SendActionMessage(int idx, int action,int direction,int velocity);    void SendVelocityMessage(int idx, int velocity);private:    EquipmentINFO m_StepMotorHardware;    MQTT * m_MQTTInstance;};#endif /* defined(__HelloCpp__ViewController__) */

StepMotorControlView.cpp修改后如下:

#include "StepMotorControlView.h"#include "platform/CACommon.h"#define FontColor ccc4(51,204,255,255) //ccc4(255,255,255,255)StepMotorControlView::StepMotorControlView()    :m_Slider(NULL), m_StepMotorHardware("mainstepmotor"), m_MQTTInstance(NULL){}StepMotorControlView::~StepMotorControlView(){    CADrawerController* drawer = (CADrawerController*)CAApplication::getApplication()->getRootWindow()->getRootViewController();    drawer->setTouchMoved(true);    viewDidDisappear();    m_StepMotorHardware.SaveToDatabase();}void StepMotorControlView::viewDidLoad(){    CAImageView* view1 = CAImageView::createWithImage(CAImage::create("image/motor_control_view.jpg"));    view1->setLayout(DLayoutFill);    this->getView()->addSubview(view1);    int var=0;    CALabel* labelDirectionSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(100, 40)));    labelDirectionSwitch->setColor(FontColor);    labelDirectionSwitch->setText(UTF8("方向开关"));    labelDirectionSwitch->setFontSize(30);    labelDirectionSwitch->setTextAlignment(CATextAlignmentCenter);    labelDirectionSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelDirectionSwitch);    m_DirectionSwitch =  CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(100, 20)));    m_DirectionSwitch->setTag(102);    var = m_StepMotorHardware.getDirection();    m_DirectionSwitch->setIsOn(var==0?false:true, false);    m_DirectionSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_DirectionSwitch);    //CAView* view1 = CAView::createWithLayout(DLayoutFill);    //view1->setColor(CAColor_gray);    m_VelocityValue = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_R(100, 100), DVerticalLayout_T_H(200, 50)));    m_VelocityValue->setColor(FontColor);    char str[64];    sprintf(str, "%d%%", m_StepMotorHardware.getVelocity());    m_VelocityValue->setText(str);    m_VelocityValue->setFontSize(30);    m_VelocityValue->setTextAlignment(CATextAlignmentCenter);    m_VelocityValue->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(m_VelocityValue);    m_Slider = CASlider::createWithLayout(DLayout(DHorizontalLayout_L_R(120, 120), DVerticalLayout_T_H(250, 56)));    m_Slider->addTarget(this, CAControl_selector(StepMotorControlView::SliderValueChange));    m_Slider->setTag(100);    m_Slider->setValue((float)m_StepMotorHardware.getVelocity() / (m_Slider->getMaxValue() * 100));    this->getView()->addSubview(m_Slider);    CALabel* labelStepMotorSwitch = CALabel::createWithLayout(DLayout(DHorizontalLayout_L_W(10, 200), DVerticalLayout_T_H(400, 40)));    labelStepMotorSwitch->setColor(FontColor);    labelStepMotorSwitch->setText(UTF8("电机开关"));    labelStepMotorSwitch->setFontSize(30);    labelStepMotorSwitch->setTextAlignment(CATextAlignmentCenter);    labelStepMotorSwitch->setVerticalTextAlignmet(CAVerticalTextAlignmentCenter);    this->getView()->addSubview(labelStepMotorSwitch);    m_RunSwitch = CASwitch::createWithLayout(DLayout(DHorizontalLayout_L_W(250, 100), DVerticalLayout_T_H(400, 20)));    m_RunSwitch->setTag(101);    var = m_StepMotorHardware.getActionState();    m_RunSwitch->setIsOn(var == 0 ? false : true, false);    m_RunSwitch->addTarget(this, CAControl_selector(StepMotorControlView::switchStateChange));    this->getView()->addSubview(m_RunSwitch);}void StepMotorControlView::viewDidUnload(){    // Release any retained subviews of the main view.    // e.g. self.myOutlet = nil;    m_StepMotorHardware.SaveToDatabase();}void StepMotorControlView::viewDidAppear(){    if (!m_MQTTInstance)    {        NetworkINFO tNetworkInfo;        m_MQTTInstance = new MQTT(tNetworkInfo.getIP(), tNetworkInfo.getPort(), tNetworkInfo.getUsername(), tNetworkInfo.getPassword(), std::string());    }    if (!m_MQTTInstance->IsHardwareStarted())        m_MQTTInstance->StartHardware();}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();    }}void StepMotorControlView::SliderValueChange(CAControl* btn, DPoint point){    char value[20] = "";    CASlider* p_Slider = (CASlider*)btn;    int v = (int)(p_Slider->getValue() * 100);    sprintf(value, "%d%%", v);    if (p_Slider->getTag()==100) {        m_VelocityValue->setText(value);        static int old_val = v;        if(old_val != v)        {            old_val = v;            m_StepMotorHardware.setVelocity(old_val);            if (m_MQTTInstance && m_MQTTInstance->IsHardwareStarted())            {                SendVelocityMessage( m_StepMotorHardware.getIDX(),m_StepMotorHardware.getVelocity() );            }        }    }}void StepMotorControlView::switchStateChange(CAControl* btn, DPoint point){    CASwitch* state = (CASwitch*)btn;    switch(state->getTag())    {    case 101://action            if (state->isOn())            {                //CCLog("switchStateChange 101: false");                m_StepMotorHardware.setActionSate(1);            }            else            {                //CCLog("switchStateChange 101: true");                m_StepMotorHardware.setActionSate(0);            }            if (m_MQTTInstance && m_MQTTInstance->IsHardwareStarted())            {                SendActionMessage(m_StepMotorHardware.getIDX(), m_StepMotorHardware.getActionState(), m_StepMotorHardware.getDirection(), m_StepMotorHardware.getVelocity());            }            break;    case 102://direction            if (state->isOn())            {                //CCLog("switchStateChange 102: false");                m_StepMotorHardware.setDirection(1);            }            else            {                //CCLog("switchStateChange 102:true");                m_StepMotorHardware.setDirection(0);            }            if (m_MQTTInstance && m_MQTTInstance->IsHardwareStarted())            {                SendDirMessage( m_StepMotorHardware.getIDX(),m_StepMotorHardware.getDirection() );            }            break;    default:        break;    }}void StepMotorControlView::SendFCSMessage(const std::string& strFCSMsg){    if (m_MQTTInstance && m_MQTTInstance->IsHardwareStarted())    {        m_MQTTInstance->SendMessage(TOPIC_FCS_OUT, strFCSMsg);    }}#define MAX_TEXT 256void StepMotorControlView::SendMessage(const char *pszFormat,...){    char msg[256]={0};    va_list ap;    va_start(ap, pszFormat);#if defined(_WIN32 )    vsnprintf_s(msg, MAX_TEXT, MAX_TEXT, pszFormat, ap);#else //#elif defined(__GNUC__)    vsnprintf(msg, MAX_TEXT, pszFormat, ap);#endif    va_end(ap);    SendFCSMessage(msg);}void StepMotorControlView::SendDirMessage(int idx, int direction){    SendMessage("{\nidx:%d,\ndir:%d\n}",idx,direction);}void StepMotorControlView::SendLoopMessage(int idx, int loop){    SendMessage("{\nidx:%d,\nloop:%d\n}",idx,loop);}void StepMotorControlView::SendRecMessage(int idx, int recording){    SendMessage("{\nidx:%d,\nrecording:%d\n}",idx,recording);}void StepMotorControlView::SendStepsMessage(int idx, int steps){    SendMessage("{\nidx:%d,\nsteps:%d\n}",idx,steps);}void StepMotorControlView::SendActionMessage(int idx, int action, int direction, int velocity){    SendMessage("{\nidx:%d,\nact:%d,\ndir:%d,\nv:%d\n}",idx,action,direction,velocity);}void StepMotorControlView::SendVelocityMessage(int idx, int velocity){    SendMessage("{\nidx:%d,\nv:%d\n}",idx,velocity);}

编译链接后运行,测试一下结果:
这里写图片描述

这里写图片描述

联合开发板做测试:
这里写图片描述

这里写图片描述

本版完整源码地址:
StepMotorController_2017.10.02_VS2013-OK.rar

下一篇讲在本篇基础上,完善平台兼容性,实现安卓版,并在手机上运行试验。

阅读全文
0 0