Project: Update and bug fix.

1. Optimize static build.
2. Fix Config couldn't be used in QML.
3. Fix RibbonMessageListView's slide lag bug.
4. Add FrameChooser to let user customize DataFrame.
5. Fix EventHistoryList display bug.
6. Add Slider for ListTable.
This commit is contained in:
Mentalflow 2024-03-11 00:21:37 +08:00
parent cc08435a3a
commit 93c11e7ecf
Signed by: Mentalflow
GPG Key ID: 5AE68D4401A2EE71
19 changed files with 586 additions and 115 deletions

2
3rdparty/RibbonUI vendored

@ -1 +1 @@
Subproject commit 43240eab1f351a90afdc843119743b0aca4d311c Subproject commit 18edf9f0fdf0f11663d328a8166486226246e656

View File

@ -2,13 +2,23 @@ cmake_minimum_required(VERSION 3.21)
project(ProtocolParser VERSION ${CMAKE_PROJECT_VERSION} LANGUAGES CXX) project(ProtocolParser VERSION ${CMAKE_PROJECT_VERSION} LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(QT_VERSION VERSION_GREATER_EQUAL "6.3")
qt_standard_project_setup()
qt_policy(SET QTP0001 NEW)
else()
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
endif()
if(APPLE) if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif() endif()
set(QML_IMPORT_PATH ${CMAKE_BINARY_DIR}/app_source CACHE STRING "Qt Creator extra QML import paths" FORCE)
set(PROJECT_COMPANY "Mentalflow's Lab") set(PROJECT_COMPANY "Mentalflow's Lab")
set(PROJECT_COPYRIGHT "Copyright (c) 2023 Mentalflow's Lab. All rights reserved.") set(PROJECT_COPYRIGHT "Copyright (c) 2023 Mentalflow's Lab. All rights reserved.")
set(PROJECT_DOMAIN "dev.ourdocs.cn.protocolparser") set(PROJECT_DOMAIN "dev.ourdocs.cn.protocolparser")
@ -36,7 +46,7 @@ set(
qml/components/ZigBeeMessage.qml qml/components/SerialPortAssistant.qml qml/components/ZigBeeMessage.qml qml/components/SerialPortAssistant.qml
qml/components/ZigBeeDataView.qml qml/components/TabBar.qml qml/components/CenterView.qml qml/components/ZigBeeDataView.qml qml/components/TabBar.qml qml/components/CenterView.qml
qml/components/ListTable.qml qml/components/DeviceList.qml qml/components/KeysList.qml qml/components/ListTable.qml qml/components/DeviceList.qml qml/components/KeysList.qml
qml/components/EventsHistoryList.qml qml/components/EventsHistoryList.qml qml/components/FrameChooser.qml
) )
INCLUDE_DIRECTORIES(dlln3x include) INCLUDE_DIRECTORIES(dlln3x include)

View File

@ -9,17 +9,18 @@ class Config : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_SINGLETON
QML_NAMED_ELEMENT(Config) QML_NAMED_ELEMENT(Config)
public: public:
static Config* instance(); static Config* instance();
static Config* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} static Config* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();}
Q_INVOKABLE void Set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue); Q_INVOKABLE void set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue);
Q_INVOKABLE void SetArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue); Q_INVOKABLE void setArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue);
Q_INVOKABLE QVariant Get(QString qstrnodename,QString qstrkeyname); Q_INVOKABLE QVariant get(QString qstrnodename,QString qstrkeyname);
Q_INVOKABLE QVariant GetArray(QString qstrnodename,QString qstrkeyname); Q_INVOKABLE QVariant getArray(QString qstrnodename,QString qstrkeyname);
void Clear(); void Clear();
private: private:
Config(QString qstrfilename = ""); explicit Config(QString qstrfilename = "");
~Config(void); ~Config(void);
Q_DISABLE_COPY_MOVE(Config) Q_DISABLE_COPY_MOVE(Config)
QString m_qstrFileName; QString m_qstrFileName;

View File

@ -24,6 +24,7 @@ private:
void src_port_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false); void src_port_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false);
void des_port_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false); void des_port_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false);
void remote_addr_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false); void remote_addr_parser(zigbee_protocol::ZigbeeFrame &zframe, bool is_demo = false);
QString sensor_data_reader(void **data,QString type);
zigbee_protocol::Protocol* _protocol = nullptr; zigbee_protocol::Protocol* _protocol = nullptr;
QString _self_addr; QString _self_addr;
QMap<uint16_t, QPair<device,device>> nodes; QMap<uint16_t, QPair<device,device>> nodes;

View File

@ -33,9 +33,9 @@ public:
QList<uint16_t> wait_queue(){if(!_resolver)_resolver=ZigBeeDataResolver::instance();return _resolver->get_wait_queue();}; QList<uint16_t> wait_queue(){if(!_resolver)_resolver=ZigBeeDataResolver::instance();return _resolver->get_wait_queue();};
void setWait_queue(QList<uint16_t> wait_queue){if(!_resolver)_resolver=ZigBeeDataResolver::instance();QList<uint16_t> &a=_resolver->get_wait_queue();a=wait_queue;emit wait_queueChanged();}; void setWait_queue(QList<uint16_t> wait_queue){if(!_resolver)_resolver=ZigBeeDataResolver::instance();QList<uint16_t> &a=_resolver->get_wait_queue();a=wait_queue;emit wait_queueChanged();};
QString hmac_verify_key(){ return _protocol->hmac_verify_key;}; QString hmac_verify_key(){ return _protocol->hmac_verify_key;};
void setHmac_verify_key(QString key){ _config->Set("Protocol","hmac_verify_key",key); _protocol->hmac_verify_key = key;emit hmac_verify_keyChanged();}; void setHmac_verify_key(QString key){ _config->set("Protocol","hmac_verify_key",key); _protocol->hmac_verify_key = key;emit hmac_verify_keyChanged();};
QStringList pre_hmac_verify_key(){ return _protocol->pre_hmac_verify_key;}; QStringList pre_hmac_verify_key(){ return _protocol->pre_hmac_verify_key;};
void setPre_hmac_verify_key(QStringList keys){ _config->SetArray("Protocol","pre_hmac_verify_key",keys); _protocol->pre_hmac_verify_key = keys;emit pre_hmac_verify_keyChanged();}; void setPre_hmac_verify_key(QStringList keys){ _config->setArray("Protocol","pre_hmac_verify_key",keys); _protocol->pre_hmac_verify_key = keys;emit pre_hmac_verify_keyChanged();};
static ZigBeeParser* instance(); static ZigBeeParser* instance();
static ZigBeeParser* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} static ZigBeeParser* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();}
void message_parser(QJsonObject message); void message_parser(QJsonObject message);

View File

@ -10,7 +10,9 @@ import "components"
RibbonWindow { RibbonWindow {
id:root id:root
width: 1200 width: 1200
minimumWidth: 1200
height: 800 height: 800
minimumHeight: 800
title: qsTr("Protocol Parser") + ` V${PPAPP_Version}` title: qsTr("Protocol Parser") + ` V${PPAPP_Version}`
TabBar{ TabBar{

View File

@ -7,7 +7,7 @@ import ProtocolParser
Item { Item {
id:obj id:obj
property var header_items: ["序号","事件"] property var header_items: ["序号","事件"]
property var header_items_width: [100,400] property var header_items_width: [100,700]
property var data_source: [] property var data_source: []
implicitHeight: list_layout.height implicitHeight: list_layout.height
implicitWidth: list_layout.width implicitWidth: list_layout.width
@ -21,7 +21,7 @@ Item {
var data = [] var data = []
for (var i = 0; i < EventsBus.event_history.length; i++) for (var i = 0; i < EventsBus.event_history.length; i++)
{ {
data.push({"序号":i+1,"事件":JSON.stringify(EventsBus.event_history)}) data.push({"序号":i+1,"事件":JSON.stringify(EventsBus.event_history[i])})
} }
data_source = data data_source = data
} }
@ -32,7 +32,7 @@ Item {
var data = [] var data = []
for (var i = 0; i < EventsBus.event_history.length; i++) for (var i = 0; i < EventsBus.event_history.length; i++)
{ {
data.push({"序号":i+1,"事件":JSON.stringify(EventsBus.event_history)}) data.push({"序号":i+1,"事件":JSON.stringify(EventsBus.event_history[i])})
} }
data_source = data data_source = data
} }

View File

@ -0,0 +1,373 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import RibbonUI
import ProtocolParser
Item {
clip: true
id: root
implicitWidth: layout.width + margins*2
implicitHeight: layout.height + margins*2
property double margins: 30
property int object_width: 30
ListModel{
id: frame_model
ListElement{
name:"温度"
type:"float"
}
ListElement{
name:"湿度"
type:"float"
}
ListElement{
name:"气体浓度"
type:"float"
}
ListElement{
name:"火焰指数"
type:"float"
}
}
Component.onCompleted: {
let result = Config.getArray('Protocol', 'data_frame_name')
if (result)
{
frame_model.clear()
var name_array=[],type_array=[]
name_array = Config.getArray('Protocol', 'data_frame_name')
type_array = Config.getArray('Protocol', 'data_frame_type')
for (var i=0;i<name_array.length;i++)
{
frame_model.append({
name:name_array[i],
type:type_array[i]
})
}
}
else
{
let name_array=[],type_array=[]
for (let i=0;i<frame_model.count;i++)
{
name_array[i] = frame_model.get(i).name
type_array[i] = frame_model.get(i).type
}
Config.setArray('Protocol', 'data_frame_name', name_array)
Config.setArray('Protocol', 'data_frame_type', type_array)
}
}
RibbonButton{
anchors{
top:parent.top
margins: 4
right:parent.right
}
show_bg: false
show_hovered_bg: false
icon_source: RibbonIcons.Dismiss
onClicked: window_popup.close()
}
ColumnLayout{
id:layout
anchors{
top:parent.top
horizontalCenter: parent.horizontalCenter
margins: margins
}
RibbonText{
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
width: implicitWidth > parent.width ? parent.width : implicitWidth
text: qsTr("自定义传感器数据结构")
font.pixelSize: 20
wrapMode: RibbonText.WordWrap
view_only: true
}
RibbonText{
Layout.topMargin: margins/2
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
width: implicitWidth > parent.width ? parent.width : implicitWidth
text: qsTr("传感器数据帧结构组成:")
wrapMode: RibbonText.WordWrap
view_only: true
}
Rectangle{
id: frame_bg
radius: 5
Layout.preferredHeight: object_width + frame.anchors.leftMargin*2
Layout.preferredWidth: object_width * 16 + frame.anchors.leftMargin*2
color: RibbonTheme.dark_mode ? '#2A2C31' : '#F2F4F7'
ListView{
id: frame
property int current_size: 0
property bool is_full: current_size === 16
property int has_selected: 0
clip: true
model: frame_model
orientation: ListView.Horizontal
implicitHeight: object_width
implicitWidth: contentWidth
anchors{
leftMargin: 2
left: parent.left
verticalCenter: parent.verticalCenter
}
delegate:RibbonRectangle{
id: bg
topLeftRadius: index === 0 ? 5 : 0
bottomLeftRadius: topLeftRadius
topRightRadius: frame.current_size === 16 && (index + 1) === frame.count ? 5 : 0
bottomRightRadius: topRightRadius
implicitHeight: object_width
implicitWidth: object_width
color: bg.selected || mouse.containsMouse ? "#506BBD" : RibbonTheme.dark_mode ? '#3A4045' : "white"
property bool selected: false
property bool is_focused: frame.currentIndex === index
onIs_focusedChanged: {
if (!is_focused && selected)
bg.selected = !bg.selected
}
onSelectedChanged: frame.has_selected += bg.selected ? 1 : -1
property string type: model.type
property int data_size
onTypeChanged: {
data_size = cal_size(model.type)
implicitWidth = object_width * data_size
}
RibbonText{
anchors.centerIn: parent
width: implicitWidth > parent.width ? parent.width : implicitWidth
text: model.name
wrapMode: RibbonText.WordWrap
view_only: true
color:{
if(!RibbonTheme.dark_mode)
{
if(mouse.containsMouse&&!bg.selected)
return 'black'
else if(mouse.containsMouse&&bg.selected)
return 'white'
else if(!mouse.containsMouse&&bg.selected)
return 'black'
else
return 'black'
}
else
{
if(mouse.containsMouse&&!bg.selected)
return 'white'
else if(mouse.containsMouse&&bg.selected)
return 'black'
else if(!mouse.containsMouse&&bg.selected)
return 'white'
else
return 'white'
}
}
}
Rectangle{
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
width: 1
height: parent.height - frame.anchors.leftMargin * 2
visible: index + 1 !== frame.count
color: RibbonTheme.dark_mode ? "#525252" : "#D4D4D4"
Behavior on color {
ColorAnimation {
duration: 60
easing.type: Easing.OutSine
}
}
}
RibbonToolTip{
text: qsTr(`${bg.type}, ${bg.data_size}B`)
visible: text && mouse.containsMouse
}
MouseArea{
id: mouse
anchors.fill: parent
hoverEnabled: true
onClicked:
{
frame.currentIndex = index
bg.selected = !bg.selected
}
}
ListView.onRemove: cal_size(type,true)
function cal_size(type,is_remove)
{
let size = frame.judge_size(type);
if(!is_remove)
frame.current_size += size
else
frame.current_size -= size
return size
}
}
function judge_size(type)
{
let size = 0
switch(type)
{
case "float":
size = 4
break
case "double":
size = 8
break
case "int64_t":
size = 8
break
case "int32_t":
size = 4
break
case "int16_t":
size = 2
break
case "int8_t":
size = 1
break
case "uint64_t":
size = 8
break
case "uint32_t":
size = 4
break
case "uint16_t":
size = 2
break
case "uint8_t":
size = 1
break
}
return size
}
}
}
RowLayout{
Layout.preferredWidth: parent.width
Layout.topMargin: margins/2
Layout.alignment: Qt.AlignHCenter
spacing: margins/3
RibbonText{
text: qsTr("类型:")
view_only: true
}
RibbonComboBox{
id: type_combo
Layout.preferredWidth: 100
model: ListModel {
ListElement { text: "float" }
ListElement { text: "double" }
ListElement { text: "int64_t" }
ListElement { text: "int32_t" }
ListElement { text: "int16_t" }
ListElement { text: "int8_t" }
ListElement { text: "uint64_t" }
ListElement { text: "uint32_t" }
ListElement { text: "uint16_t" }
ListElement { text: "uint8_t" }
}
enabled: frame.current_size !==16
}
RibbonText{
text: qsTr("名称:")
view_only: true
}
RibbonLineEdit{
id: name_edit
Layout.preferredWidth: 120
placeholderText: qsTr("请输入数据名称")
onCommit: save_btn.clicked()
enabled: frame.current_size !==16
}
RibbonButton{
id: add_btn
icon_source: RibbonIcons.Add
text: qsTr("添加")
show_tooltip: false
enabled: {
if (frame.judge_size(type_combo.currentText)+frame.current_size>16)
return false
else
return true
}
onClicked: {
frame_model.append({
type:type_combo.currentText,
name:name_edit.text
})
}
}
RibbonButton{
id: delete_btn
icon_source: RibbonIcons.Delete
text: qsTr("删除")
show_tooltip: false
enabled: frame.has_selected !== 0
onClicked: {
frame_model.remove(frame.currentIndex)
}
}
}
RowLayout{
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: margins/2
spacing: margins
RibbonButton{
id: save_btn
Layout.preferredWidth: 150
Layout.alignment: Qt.AlignHCenter
icon_source: RibbonIcons.Save
text: qsTr("保存")
show_tooltip: false
onClicked: {
if (!type_combo.enabled && !name_edit.enabled && frame.current_size > 0)
{
let name_array=[],type_array=[]
for (let i=0;i<frame_model.count;i++)
{
name_array[i] = frame_model.get(i).name
type_array[i] = frame_model.get(i).type
}
Config.setArray('Protocol', 'data_frame_name', name_array)
Config.setArray('Protocol', 'data_frame_type', type_array)
}
else
{
name_edit.text = qsTr("请检查数据长度")
}
}
}
RibbonButton{
id: reset_btn
Layout.preferredWidth: 150
icon_source: RibbonIcons.ArrowReset
text: qsTr("还原默认值")
show_tooltip: false
onClicked: {
frame_model.clear()
frame_model.append([{
name:"温度",
type:"float"
},{
name:"湿度",
type:"float"
},{
name:"气体浓度",
type:"float"
},{
name:"火焰指数",
type:"float"
}])
}
}
}
}
}

View File

@ -93,7 +93,30 @@ Item {
view_only: true view_only: true
text: modelData.data text: modelData.data
wrapMode: RibbonText.WordWrap wrapMode: RibbonText.WordWrap
color: RibbonTheme.dark_mode ? mouse.containsMouse ? 'black' : 'white' : mouse.containsMouse ? 'white':'black' color: {
if(RibbonTheme.dark_mode)
{
if(mouse.containsMouse&&!row_bg.selected)
return 'black'
else if(mouse.containsMouse&&row_bg.selected)
return 'white'
else if(!mouse.containsMouse&&row_bg.selected)
return 'black'
else
return 'white'
}
else
{
if(mouse.containsMouse&&!row_bg.selected)
return 'white'
else if(mouse.containsMouse&&row_bg.selected)
return 'black'
else if(!mouse.containsMouse&&row_bg.selected)
return 'white'
else
return 'black'
}
}
} }
} }
} }
@ -114,6 +137,11 @@ Item {
add: Transition { add: Transition {
NumberAnimation { properties: "y"; from: list_table.height; duration: 200 } NumberAnimation { properties: "y"; from: list_table.height; duration: 200 }
} }
ScrollBar.vertical: ScrollBar {
anchors.right: list_table.right
anchors.rightMargin: 2
}
} }
function getRowValues(index) { function getRowValues(index) {

View File

@ -8,11 +8,12 @@ Rectangle{
color: "transparent" color: "transparent"
property double padding: 10 property double padding: 10
default property alias content: message_layout.data default property alias content: message_layout.data
property var data_model:model property var data_model: model
property int font_size: 13 property int font_size: 13
property string sender_text: "sender" property string sender_text: "sender"
width: ListView.view.width width: ListView.view.width
height: bubble_layout.height + padding*2 height: bubble_layout.height + padding*2
ColumnLayout{ ColumnLayout{
id: bubble_layout id: bubble_layout
anchors{ anchors{

View File

@ -12,80 +12,53 @@ RibbonView{
spacing: 0 spacing: 0
property int max_msg_num: 10 property int max_msg_num: 10
property bool auto_scroll_to_bottom: false
property int animation_time: 200
property alias delegate: message_list.delegate property alias delegate: message_list.delegate
property alias message_model: message_model property alias message_model: message_model
property alias view: message_list property alias view: message_list
ListModel{ ListModel{
id: message_model id: message_model
property int begin_index: 0 onCountChanged: auto_scroll_btn_timer.restart()
property int end_index: 0
onCountChanged: {
if (end_index == count - 2 || begin_index == end_index)
{
while(show_model.count > max_msg_num)
{
show_model.remove(0)
begin_index++
}
show_model.append(message_model.get(count - 1))
end_index = count-1
//console.log('append:',begin_index,end_index)
}
if(count===0)
show_model.clear()
}
} }
ListModel{
id: show_model Timer{
id: auto_scroll_btn_timer
interval: animation_time
repeat: false
onTriggered: {
if(view.auto_scroll_to_bottom)
view.scroll_to_bottom()
}
} }
ListView{ ListView{
id: message_list id: message_list
cacheBuffer: message_list.height * 2 cacheBuffer: message_list.height * 2
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: contentHeight Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
interactive: false model: message_model
model: show_model
add: Transition { add: Transition {
NumberAnimation { properties: "y"; from: message_list.height; duration: 100 } NumberAnimation {
properties: "y"
from: message_list.height
duration: animation_time
}
} }
displaced: Transition { ScrollBar.vertical: ScrollBar {
NumberAnimation { properties: "y"; duration: 100 } anchors.right: message_list.right
anchors.rightMargin: 2
} }
} }
Connections{
target: view function scroll_to_up(){
function onPull_up_triggered() message_list.positionViewAtBeginning()
{
for(let i = message_model.begin_index - 1, count = 0;
i >= 0 && count < max_msg_num; i--,count++ )
{
show_model.insert(0,message_model.get(i))
message_model.begin_index = i
if (show_model.count > max_msg_num + 2)
{
show_model.remove(show_model.count - 1)
message_model.end_index--
}
}
//console.log('up:',message_model.begin_index,message_model.end_index)
}
function onPull_down_triggered()
{
for(let i = message_model.end_index + 1, count = 0;
i < message_model.count && count < max_msg_num; i++,count++ )
{
show_model.append(message_model.get(i))
message_model.end_index = i
if (show_model.count > max_msg_num)
{
show_model.remove(0)
message_model.begin_index++
}
}
//console.log('down:',message_model.begin_index,message_model.end_index)
}
} }
function scroll_to_bottom(){
message_list.positionViewAtEnd()
}
} }

View File

@ -14,22 +14,23 @@ Item{
property double bottom_padding: 0 property double bottom_padding: 0
property bool handle_serial: true property bool handle_serial: true
onAuto_scroll_to_bottomChanged: if(auto_scroll_to_bottom) serial_view.scroll_to_bottom() onAuto_scroll_to_bottomChanged: {
serial_view.auto_scroll_to_bottom = auto_scroll_to_bottom
if(auto_scroll_to_bottom)
serial_view.scroll_to_bottom()
}
RibbonMessageListView{ RibbonMessageListView{
id: serial_view id: serial_view
anchors.fill: parent anchors.fill: parent
top_padding: serial_title_bar.height + control.top_padding + (!RibbonTheme.modern_style ? 10 : 0) top_padding: serial_title_bar.height + control.top_padding + (!RibbonTheme.modern_style ? 10 : 0)
bottom_padding: message_sender.height + control.bottom_padding bottom_padding: message_sender.height + control.bottom_padding
auto_scroll_to_bottom: control.auto_scroll_to_bottom
delegate: ZigBeeMessage{ delegate: ZigBeeMessage{
sender_text: `${model.time} ${model.recieved ? '收' : '发'}` sender_text: `${model.time} ${model.recieved ? '收' : '发'}`
show_tooltip: control.show_tooltip show_tooltip: control.show_tooltip
component_width: serial_view.width / 2 component_width: serial_view.width / 2
} }
view.onHeightChanged: {
if (control.auto_scroll_to_bottom)
scroll_to_bottom()
}
Connections{ Connections{
target: SerialPortManager target: SerialPortManager
function onRecved(data) function onRecved(data)

View File

@ -404,8 +404,8 @@ RibbonTabBar {
} }
let repeat_count = 16 let repeat_count = 16
let t = `FF 29 ${get_rand_byte()}${get_rand_byte()} 83 56 56 `+ let t = `FF 2B ${get_rand_byte()}${get_rand_byte()} 83 56 56 `+
`AA AD 56 56 52 48 23 32 01 00 17 00 00 00 AA AA 01 10 00 FF FF ` `AA AD 56 56 EE EE 56 56 01 00 26 00 00 00 AA AA 01 FF 10 00 FF FF `
for (let j=0;j<repeat_count;j++){ for (let j=0;j<repeat_count;j++){
t+=` ${get_rand_byte()}${get_rand_byte()}` t+=` ${get_rand_byte()}${get_rand_byte()}`
} }
@ -458,5 +458,27 @@ RibbonTabBar {
} }
} }
} }
RibbonTabGroup{
text: qsTr("数据结构自定义")
width: frame_custom_layout.width + 30
RowLayout{
id: frame_custom_layout
anchors.centerIn: parent
height: parent.height
spacing: 10
ColumnLayout{
spacing: 10
RibbonButton{
Layout.fillWidth: true
icon_source: RibbonIcons.CodeTextEdit
text: qsTr("自定义数据帧")
tip_text: qsTr("自定义传感器数据帧结构")
onClicked: {
show_popup("components/FrameChooser.qml")
}
}
}
}
}
} }
} }

View File

@ -43,7 +43,10 @@ Item{
identify_view.scroll_to_bottom() identify_view.scroll_to_bottom()
data_view.scroll_to_bottom() data_view.scroll_to_bottom()
} }
identify_view.auto_scroll_to_bottom = auto_scroll_to_bottom
data_view.auto_scroll_to_bottom = auto_scroll_to_bottom
} }
Item{ Item{
anchors{ anchors{
top:parent.top top:parent.top
@ -56,14 +59,11 @@ Item{
anchors.fill: parent anchors.fill: parent
top_padding: control.top_padding + identify_title_bar.height + (!RibbonTheme.modern_style ? 10 : 0) top_padding: control.top_padding + identify_title_bar.height + (!RibbonTheme.modern_style ? 10 : 0)
bottom_padding: control.bottom_padding bottom_padding: control.bottom_padding
auto_scroll_to_bottom: control.auto_scroll_to_bottom
delegate: ZigBeeMessage{ delegate: ZigBeeMessage{
show_tooltip: control.show_tooltip show_tooltip: control.show_tooltip
component_width: identify_view.width / 2 component_width: identify_view.width / 2
} }
view.onHeightChanged: {
if (control.auto_scroll_to_bottom)
scroll_to_bottom()
}
Event{ Event{
id:identify_view_event id:identify_view_event
type: "zigbee_identify_data_view" type: "zigbee_identify_data_view"

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.21) cmake_minimum_required(VERSION 3.21)
project(sm_crypto VERSION 1.0.0.0) project(sm_crypto VERSION 1.0.0)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)

View File

@ -35,12 +35,12 @@ Config* Config::instance()
return singleton; return singleton;
} }
void Config::Set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue) void Config::set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue)
{ {
m_psetting->setValue(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname), qvarvalue); m_psetting->setValue(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname), qvarvalue);
} }
void Config::SetArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue) void Config::setArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue)
{ {
m_psetting->beginWriteArray(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname)); m_psetting->beginWriteArray(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname));
QList<QVariant> list = qvarvalue.toList(); QList<QVariant> list = qvarvalue.toList();
@ -52,13 +52,13 @@ void Config::SetArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalu
m_psetting->endArray(); m_psetting->endArray();
} }
QVariant Config::Get(QString qstrnodename,QString qstrkeyname) QVariant Config::get(QString qstrnodename,QString qstrkeyname)
{ {
QVariant qvar = m_psetting->value(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname)); QVariant qvar = m_psetting->value(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname));
return qvar; return qvar;
} }
QVariant Config::GetArray(QString qstrnodename,QString qstrkeyname) QVariant Config::getArray(QString qstrnodename,QString qstrkeyname)
{ {
QList<QVariant> list; QList<QVariant> list;
int size = m_psetting->beginReadArray(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname)); int size = m_psetting->beginReadArray(QString("/%1/%2").arg(qstrnodename).arg(qstrkeyname));

View File

@ -31,9 +31,6 @@ int main(int argc, char *argv[])
QList<int> verl = {PROTOCOLPARSER_VERSION}; QList<int> verl = {PROTOCOLPARSER_VERSION};
QString version = QString::number(verl[0])+'.'+QString::number(verl[1])+'.'+QString::number(verl[2]); QString version = QString::number(verl[0])+'.'+QString::number(verl[1])+'.'+QString::number(verl[2]);
engine.rootContext()->setContextProperty("PPAPP_Version",version); engine.rootContext()->setContextProperty("PPAPP_Version",version);
#ifdef RIBBONUI_BUILD_STATIC_LIB
engine.addImportPath("qrc:/");
#endif
const QUrl url(u"qrc:/qt/qml/ProtocolParser/Main.qml"_qs); const QUrl url(u"qrc:/qt/qml/ProtocolParser/Main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) { &app, [url](QObject *obj, const QUrl &objUrl) {

View File

@ -5,20 +5,18 @@ using namespace zigbee_protocol;
Protocol::Protocol(){ Protocol::Protocol(){
_config = Config::instance(); _config = Config::instance();
if (_config->Get("Protocol","hmac_verify_key").toString().isEmpty()) if (_config->get("Protocol","hmac_verify_key").toString().isEmpty())
_config->Set("Protocol","hmac_verify_key",hmac_verify_key); _config->set("Protocol","hmac_verify_key",hmac_verify_key);
else else
hmac_verify_key = _config->Get("Protocol","hmac_verify_key").toString(); hmac_verify_key = _config->get("Protocol","hmac_verify_key").toString();
if (_config->GetArray("Protocol","pre_hmac_verify_key").toStringList().isEmpty()) if (_config->getArray("Protocol","pre_hmac_verify_key").toStringList().isEmpty())
_config->SetArray("Protocol","pre_hmac_verify_key",pre_hmac_verify_key); _config->setArray("Protocol","pre_hmac_verify_key",pre_hmac_verify_key);
else else
pre_hmac_verify_key = _config->GetArray("Protocol","pre_hmac_verify_key").toStringList(); pre_hmac_verify_key = _config->getArray("Protocol","pre_hmac_verify_key").toStringList();
} }
Protocol::~Protocol() Protocol::~Protocol()
{ {
_config->Set("Protocol","hmac_verify_key",hmac_verify_key);
_config->SetArray("Protocol","pre_hmac_verify_key",pre_hmac_verify_key);
} }
Protocol* Protocol::getInstance() Protocol* Protocol::getInstance()

View File

@ -221,6 +221,7 @@ void ZigBeeDataResolver::des_port_parser(zigbee_protocol::ZigbeeFrame &zframe, b
QJsonObject object; QJsonObject object;
if (node->first.verified) if (node->first.verified)
{ {
QString note_text;
new_data_frame(72) ndata; new_data_frame(72) ndata;
uint8_t data_len = 0; uint8_t data_len = 0;
memset(&ndata,0,sizeof(ndata)); memset(&ndata,0,sizeof(ndata));
@ -231,7 +232,7 @@ void ZigBeeDataResolver::des_port_parser(zigbee_protocol::ZigbeeFrame &zframe, b
object.insert("type","zigbee_recv_data"); object.insert("type","zigbee_recv_data");
if (*(u16 *)frame == CRYPTO_ZDATA_FRAME_HEAD) if (*(u16 *)frame == CRYPTO_ZDATA_FRAME_HEAD)
{ {
QString note_text = "解密数据为按照未加密传输重新打包的原始数据,因此数据长度会有差异\n"; note_text = "解密数据为按照未加密传输重新打包的原始数据,因此数据长度会有差异\n";
new_base_frame(sizeof(ndata)) nbframe; new_base_frame(sizeof(ndata)) nbframe;
memcpy(&nbframe, bframe, BASE_FRAME_PREFIX_LEN); memcpy(&nbframe, bframe, BASE_FRAME_PREFIX_LEN);
zigbee_protocol::ZigbeeFrame nzframe = zframe; zigbee_protocol::ZigbeeFrame nzframe = zframe;
@ -242,22 +243,29 @@ void ZigBeeDataResolver::des_port_parser(zigbee_protocol::ZigbeeFrame &zframe, b
nzframe.setData((char*)&nbframe,nbframe.length); nzframe.setData((char*)&nbframe,nbframe.length);
zdata = QByteArray((char *)nzframe.data(), nzframe.size()); zdata = QByteArray((char *)nzframe.data(), nzframe.size());
object.insert("decrypted_text", QJsonValue(QString(zdata.toHex(' ').toUpper()))); object.insert("decrypted_text", QJsonValue(QString(zdata.toHex(' ').toUpper())));
switch (ndata.type) { ddata = (data_frame*)&ndata;
case SENSOR_DATA_TYPE:
{
note_text += "传感器数据:";
sensor_data* sdata = (sensor_data*)ndata.data;
note_text += "PPM:" + QString::number(sdata->ppm) + ' ';
note_text += "Temperature:" + QString::number(sdata->temp) + ' ';
note_text += "Humidity:" + QString::number(sdata->humi) + ' ';
note_text += "Flare:" + QString::number(sdata->flare) + ' ';
break;
}
default:
break;
}
object.insert("note_text",QJsonValue(note_text));
} }
else{
ddata = (data_frame*)frame;
}
switch (ddata->type) {
case SENSOR_DATA_TYPE:
{
QStringList name_list, type_list;
name_list = Config::instance()->getArray("Protocol", "data_frame_name").toStringList();
type_list = Config::instance()->getArray("Protocol", "data_frame_type").toStringList();
note_text += "传感器数据:";
void* pdata = (void *)ddata->data;
for (uint8_t i = 0; i < name_list.length(); i++)
{
note_text += name_list[i]+ ":" + sensor_data_reader(&pdata,type_list[i]) + ' ';
}
break;
}
default:
break;
}
object.insert("note_text",QJsonValue(note_text));
if (QRandomGenerator::global()->bounded(2)!=0 && is_demo) if (QRandomGenerator::global()->bounded(2)!=0 && is_demo)
object.insert("decrypted_text", QJsonValue(QString(zdata.toHex(' ').toUpper()))); object.insert("decrypted_text", QJsonValue(QString(zdata.toHex(' ').toUpper())));
emit data_send("zigbee_recv_data_view",object); emit data_send("zigbee_recv_data_view",object);
@ -353,3 +361,59 @@ void ZigBeeDataResolver::message_parser(QJsonObject message, QString self_addr)
data_parser(zf, message["type"] == "demo_recv_data"); data_parser(zf, message["type"] == "demo_recv_data");
} }
} }
QString ZigBeeDataResolver::sensor_data_reader(void **data,QString type)
{
QString d;
uint8_t** pdata = (uint8_t**)(data);
if (type.contains("64"))
{
if(type.contains("u"))
d = QString::number(*(uint64_t*)(*data));
else
d = QString::number(*(int64_t*)(*data));
*pdata += sizeof(uint64_t);
return d;
}
else if (type.contains("32"))
{
if(type.contains("u"))
d = QString::number(*(uint32_t*)(*data));
else
d = QString::number(*(int32_t*)(*data));
*pdata += sizeof(uint32_t);
return d;
}
else if (type.contains("16"))
{
if(type.contains("u"))
d = QString::number(*(uint16_t*)(*data));
else
d = QString::number(*(int16_t*)(*data));
*pdata += sizeof(uint16_t);
return d;
}
else if (type.contains("8"))
{
if(type.contains("u"))
d = QString::number(*(uint8_t*)(*data));
else
d = QString::number(*(int8_t*)(*data));
*pdata += sizeof(uint8_t);
return d;
}
else if (type=="float")
{
d = QString::number(*(float*)(*data), 'g', 1);
*pdata += sizeof(float);
return d;
}
else if (type=="double")
{
d = QString::number(*(double*)(*data), 'g', 1);
*pdata += sizeof(double);
return d;
}
else
return d;
}