基于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
下一篇讲在本篇基础上,完善平台兼容性,实现安卓版,并在手机上运行试验。
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(六)基于CrossApp跨平台框架的MQTT客户端控制应用PC版
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(七)基于CrossApp跨平台框架的MQTT客户端控制应用android版
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(五)MQTT的移植和步进电机控制的实现
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(一)前言
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(二)FreeRTOS v9.0.0 的移植
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(四)FreeRTOS系统下LwIP-1.4.1的移植
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(三)SD卡驱动、FatFS等的移植和ini配置文件读取的实现
- 基于MSP430G2系列实现的步进电机控制
- 步进电机的技术参数 控制及其应用
- 基于8255扩展的步进电机的控制
- 基于控制步进电机转动的VHDl程序
- 步进电机的控制
- 【Python】基于MQTT的聊天客户端
- 基于CC3200的MQTT客户端网关设计
- 步进电机的单片机控制
- 步进电机的细分控制
- 步进电机的线速度控制
- ESP8266的MQTT客户端搭建教程(基于NONS_SDK_v2.0)
- HTTP状态码大全
- Task Schedule HDU
- Maven+SpringBoot环境搭建
- 创建生成word文档时候,iis出现无权限的问题{000209FF-0000-0000-C000-000000000046}
- Trie树
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(六)基于CrossApp跨平台框架的MQTT客户端控制应用PC版
- ORA-28000: the account is locked-的解决办法 解锁 SQL> conn /as sysdba 已连接。 SQL> alter user jd account unloc
- 基于OpenCV打开摄像头的控制台程序
- Shell终端输出字符的颜色总结
- 树链剖分bzoj3626
- Linux中MAVEN环境配置
- 软件工程论文书写设计步骤及如何降低重复率
- 网站 502 解决方法
- ##好好好####知识图谱的应用#######