You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
11 KiB
C

9 months ago
// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#define SERVICES_COMMAND_TOPIC "/v1/devices/MSRDT-A/command"
#define SERVICES_RESPONSE_TOPIC "/v1/devices/MSRDT-A/commandResponse"
#define DEVICES_DATA_TOPIC "/v1/devices/MSRDT-A/datas"
#define MQTT_SERVER "61.169.135.146"
#define MQTT_PORT 51001
#define MQTT_USERNAME "test"
#define MQTT_PASSWORD "123456"
#define MQTT_KEEP_ALIVE 60
#define SYNC_CLIENT_CAC_MQTT 10
#define SYNC_QOS_LEVEL_0 0
#define WM_NEW_MSG (WM_USER + 2)
class CView : public CDialogImpl<CView>, public CDialogResize<CView>
{
public:
enum { IDD = IDD_MQTTCLIENT_FORM };
struct mosquitto *m_mosq;
bool m_session;
std::thread m_mqttThread;
CString m_userName;
CString m_password;
BOOL PreTranslateMessage(MSG* pMsg)
{
return CWindow::IsDialogMessage(pMsg);
}
BEGIN_DLGRESIZE_MAP(CView)
DLGRESIZE_CONTROL(IDC_SEND, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_CLEAR, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_TOPICES, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_TO_SEND, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_TO_RECV, DLSZ_SIZE_X | DLSZ_SIZE_Y)
END_DLGRESIZE_MAP()
BEGIN_MSG_MAP(CView)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_NEW_MSG, OnNewMsgArrived)
COMMAND_HANDLER(IDC_SEND, BN_CLICKED, OnSendCmd)
COMMAND_HANDLER(IDC_CLEAR, BN_CLICKED, OnClearCmd)
CHAIN_MSG_MAP(CDialogResize<CView>)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
DlgResize_Init();
m_userName = TEXT(MQTT_USERNAME);
m_password = TEXT(MQTT_PASSWORD);
LoadUserAndPassword();
CEdit edt = GetDlgItem(IDC_TO_RECV);
edt.SetLimitText(-1);
CComboBox cmb = GetDlgItem(IDC_TOPICES);
cmb.AddString(TEXT(SERVICES_COMMAND_TOPIC));
cmb.AddString(TEXT(SERVICES_RESPONSE_TOPIC));
cmb.AddString(TEXT(DEVICES_DATA_TOPIC));
cmb.SetCurSel(0);
m_mosq = NULL;
m_session = true;
mosquitto_lib_init();
//create mosquitto client
const char * clientId = NULL;
m_mosq = mosquitto_new(clientId, m_session, NULL);
if (!m_mosq)
{
// printf("create client failed..\n");
// mosquitto_lib_cleanup();
return false;
}
// Callback
mosquitto_user_data_set(m_mosq, (void *)this);
// mosquitto_log_callback_set(mosq, cac_log_callback);
mosquitto_connect_callback_set(m_mosq, cac_connect_callback);
mosquitto_message_callback_set(m_mosq, cac_message_callback);
mosquitto_subscribe_callback_set(m_mosq, cac_subscribe_callback);
// connect to server
CW2A userName(CT2W(m_userName), CP_UTF8);
CW2A password(CT2W(m_password), CP_UTF8);
mosquitto_username_pw_set(m_mosq, (LPCSTR)userName, (LPCSTR)password);
if (mosquitto_connect(m_mosq, MQTT_SERVER, MQTT_PORT, MQTT_KEEP_ALIVE))
{
mosquitto_destroy(m_mosq);
m_mosq = NULL;
fprintf(stderr, "Unable to connect.\n");
#ifndef _DEBUG
return false;
#endif
}
/* Subscribe to broker information topics on successful connect. */
std::thread th = std::thread(MQTTThreadProc, this);
m_mqttThread.swap(th);
int mid = 0;
// mosquitto_subscribe(m_mosq, &mid, SERVICES_COMMAND_TOPIC, SYNC_QOS_LEVEL_0);
// mosquitto_subscribe(m_mosq, &mid, SERVICES_RESPONSE_TOPIC, SYNC_QOS_LEVEL_0);
// mosquitto_subscribe(m_mosq, &mid, DEVICES_DATA_TOPIC, SYNC_QOS_LEVEL_0);
return TRUE;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if (m_mosq != NULL)
{
int mid = 0;
mosquitto_unsubscribe(m_mosq, &mid, SERVICES_COMMAND_TOPIC);
mosquitto_unsubscribe(m_mosq, &mid, SERVICES_RESPONSE_TOPIC);
mosquitto_unsubscribe(m_mosq, &mid, DEVICES_DATA_TOPIC);
mosquitto_disconnect(m_mosq);
mosquitto_loop_stop(m_mosq, false);
if (m_mqttThread.joinable())
{
m_mqttThread.join();
}
mosquitto_destroy(m_mosq);
m_mosq = NULL;
}
mosquitto_lib_cleanup();
return TRUE;
}
LRESULT OnClearCmd(WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
{
CEdit edt = GetDlgItem(IDC_TO_RECV);
edt.SetWindowText(TEXT(""));
return 1;
}
LRESULT OnSendCmd(WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
{
CString text;
CEdit edt = GetDlgItem(IDC_TO_SEND);
edt.GetWindowText(text);
if (text.GetLength() == 0)
{
return TRUE;
}
CString topic;
CComboBox cmb = GetDlgItem(IDC_TOPICES);
cmb.GetWindowText(topic);
if (topic.GetLength() == 0)
{
return TRUE;
}
CW2A utf8(CT2W(text), CP_UTF8);
CW2A utf8Topic(CT2W(topic), CP_UTF8);
int mid = 0;
int res = mosquitto_publish(m_mosq, &mid, utf8Topic, strlen((LPCSTR)utf8), (void *)((LPCSTR)utf8), SYNC_QOS_LEVEL_0, false);
if (res == MOSQ_ERR_SUCCESS)
{
// Update time
int aa = 0;
}
else
{
if (MOSQ_ERR_ERRNO == res)
{
int errorno = errno;
char* errmsg = strerror(errorno);
int aa = 0;
}
int bbb = 0;
}
return TRUE;
}
LRESULT OnNewMsgArrived(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
LPTSTR pszMsg = (LPTSTR)lParam;
LPTSTR pszTopic = (LPTSTR)wParam;
CString text;
CEdit edt = GetDlgItem(IDC_TO_RECV);
edt.GetWindowText(text);
edt.AppendText(TEXT("\r\n"));
if (pszTopic != NULL)
{
edt.AppendText(TEXT("\r\n"));
edt.AppendText(FormatLocalTime());
edt.AppendText(TEXT(" "));
edt.AppendText(pszTopic);
delete[] pszTopic;
}
if (pszMsg != NULL)
{
edt.AppendText(TEXT("\r\n"));
edt.AppendText(pszMsg);
delete[] pszMsg;
}
return TRUE;
}
int MQTTProc()
{
mosquitto_loop_forever(m_mosq, -1, 1);
return 0;
}
static int MQTTThreadProc(CView *pThis);
static void cac_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message);
static void cac_connect_callback(struct mosquitto *mosq, void *userdata, int result);
static void cac_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos);
static void cac_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str);
LPTSTR ConvertStr(const char* utf8)
{
CW2T str(CA2W(utf8, CP_UTF8));
size_t len = _tcslen((LPCTSTR)str);
TCHAR *pszT = new TCHAR[len + 1];
pszT[len] = 0;
_tcscpy(pszT, (LPCTSTR)str);
return pszT;
}
void MessageCallback(struct mosquitto *mosq, const struct mosquitto_message *message)
{
if (message->payloadlen) {
LPTSTR pszTopic = ConvertStr((char *)(message->topic));
LPTSTR pszMsg = NULL;
bool isJson = false;
char* sz = (char *)message->payload;
if (sz[0] == '{')
{
Json::Value jsonObj;
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
isJson = reader->parse(sz, sz + message->payloadlen, &jsonObj, NULL);
if (isJson)
{
Json::StreamWriterBuilder writeBuilder;
writeBuilder["indentation"] = " "; // assume default for comments is None
writeBuilder["emitUTF8"] = true;
std::string content = Json::writeString(writeBuilder, jsonObj);
size_t pos = 0;
std::string replace = "\r\n";
while ((pos = content.find('\n', pos)) != std::string::npos)
{
content.replace(pos, 1, replace);
pos += replace.length();
}
pszMsg = ConvertStr(content.c_str());
}
}
if (pszMsg == NULL)
{
pszMsg = ConvertStr((char *)(message->payload));
}
::PostMessage(m_hWnd, WM_NEW_MSG, (WPARAM)pszTopic, (LPARAM)pszMsg);
}
else {
// LPTSTR pszMsg = ConvertStr((char *)(message->payload));
LPTSTR pszTopic = ConvertStr((char *)(message->topic));
::PostMessage(m_hWnd, WM_NEW_MSG, (WPARAM)pszTopic, 0);
}
// fflush(stdout);
}
void ConnectCallback(struct mosquitto *mosq, int result)
{
int i;
if (!result)
{
/* Subscribe to broker information topics on successful connect. */
// std::thread th = std::thread(MQTTThreadProc, this);
// m_mqttThread.swap(th);
int mid = 0;
int res = 0;
char* subs[] = { SERVICES_COMMAND_TOPIC, SERVICES_RESPONSE_TOPIC, DEVICES_DATA_TOPIC};
res = mosquitto_subscribe_multiple(m_mosq, &mid, sizeof(subs) / sizeof(char *), subs, SYNC_QOS_LEVEL_0, 0, NULL);
if (res != MOSQ_ERR_SUCCESS)
{
int aa = 0;
}
// res = mosquitto_subscribe(m_mosq, &mid, SERVICES_COMMAND_TOPIC, SYNC_QOS_LEVEL_0);
// res = mosquitto_subscribe(m_mosq, &mid, SERVICES_RESPONSE_TOPIC, SYNC_QOS_LEVEL_0);
// res = mosquitto_subscribe(m_mosq, &mid, DEVICES_DATA_TOPIC, SYNC_QOS_LEVEL_0);
if (res != MOSQ_ERR_SUCCESS)
{
int aa = 0;
}
}
else
{
fprintf(stderr, "Connect failed\n");
}
}
void SubscribeCallback(struct mosquitto *mosq, int mid, int qos_count, const int *granted_qos)
{
int i;
printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
for (i = 1; i < qos_count; i++)
{
printf(", %d", granted_qos[i]);
}
printf("\n");
}
void LogCallback(struct mosquitto *mosq, int level, const char *str)
{
/* Pring all log messages regardless of level. */
printf("%s\n", str);
}
CString FormatLocalTime(time_t t = 0)
{
if (t == 0)
{
time(&t);
}
struct std::tm* tp = localtime(&t);
CString str;
str.Format(TEXT("%02d-%02d %02d:%02d:%02d"), tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
return str;
}
void LoadUserAndPassword()
{
TCHAR buf[MAX_PATH] = { 0 };
CRegKey key;
if (key.Open(HKEY_CURRENT_USER, TEXT("Software\\XYPower\\MQTTClient"), KEY_READ) == ERROR_SUCCESS)
{
ULONG bufLen = MAX_PATH;
if (key.QueryStringValue(TEXT("UserName"), buf, &bufLen) == ERROR_SUCCESS)
{
m_userName = buf;
}
bufLen = MAX_PATH;
if (key.QueryStringValue(TEXT("Password"), buf, &bufLen) == ERROR_SUCCESS)
{
m_password = buf;
}
key.Close();
}
}
};
int CView::MQTTThreadProc(CView *pThis)
{
return pThis->MQTTProc();
}
void CView::cac_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
((CView*)userdata)->MessageCallback(mosq, message);
}
void CView::cac_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
((CView*)userdata)->ConnectCallback(mosq, result);
}
void CView::cac_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
((CView*)userdata)->SubscribeCallback(mosq, mid, qos_count, granted_qos);
}
void CView::cac_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
((CView*)userdata)->LogCallback(mosq, level, str);
}