Commit c970d0e8 by NitefullWind

1. 简单实现激活和充值独立程序。

parent 5fc70a5d
[Reader]
headlist="port,baud,section,password,password_default"
port="0"
baud="115200"
section="1"
password="313731383132"
password_default="ffffffffffff"
\ No newline at end of file
#-------------------------------------------------
#
# Project created by QtCreator 2017-04-12T18:03:30
#
#-------------------------------------------------
QT += core gui sql network
CONFIG += c++11
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = EntityCard
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp\
panel.cpp \
reader.cpp \
activateworker.cpp \
fmbackup.cpp \
readworker.cpp \
fmnetwork.cpp \
fmvip.cpp
HEADERS += panel.h \
readcfg.h \
reader.h \
activateworker.h \
fmbackup.h \
readworker.h \
fmnetwork.h \
fmvip.h
FORMS += panel.ui
DESTDIR = $$PWD/../CardReader
LIBS += -L$$PWD/../CardReader -lfm_mwrf32
#include "activateworker.h"
#include <QDebug>
#include <QDateTime>
#include "fmbackup.h"
ActivateWorker::ActivateWorker()
{
}
void ActivateWorker::Init(HANDLE handle, int sector, const QString newPwd)
{
m_handle = handle;
m_sector = sector;
m_newPwd = newPwd;
FMBackup::instance();
}
void ActivateWorker::Stop()
{
m_bStop = true;
}
void ActivateWorker::run()
{
m_bStop = false;
while(!m_bStop)
{
QString vipNo;
QString uuid;
QString error;
bool result;
result = ActivateCard(m_handle, m_sector, m_newPwd, vipNo, uuid, error);
if(result){
qDebug() << result << vipNo << error;
QDateTime dt = QDateTime::currentDateTime();
bool isOk = FMBackup::instance()->insert(vipNo, uuid, dt.toString("yyyy-MM-dd"), dt.toString("hh:mm:ss"));
if(!isOk) {
error = "保存数据失败";
qDebug() << error;
}
emit activeted(result, vipNo, error);
}
if(!result && error != "could not find the card") {
qDebug() << result << vipNo << error;
emit activeted(result, vipNo, error);
}
Sleep(500);
}
}
#ifndef ACTIVATEWORKER_H
#define ACTIVATEWORKER_H
#include <QThread>
#include "../fmvip_card_reader/fm_mwrf32/fm_mwrf32.h"
class ActivateWorker : public QThread
{
Q_OBJECT
public:
ActivateWorker();
void Init(HANDLE handle, int sector, const QString newPwd);
void Stop();
protected:
void run();
private:
bool m_bStop;
HANDLE m_handle;
int m_sector;
QString m_newPwd;
signals:
void activeted(bool,QString,QString);
};
#endif // ACTIVATEWORKER_H
#include "fmbackup.h"
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDir>
#include <QFile>
#include <QApplication>
#include <QDebug>
FMBackup::FMBackup()
{
connect();
}
FMBackup* FMBackup::instance()
{
static FMBackup _instance;
return &_instance;
}
bool FMBackup::connect()
{
bool isOk;
QString backupPath = qApp->applicationDirPath()+"/backup/";
QDir dir;
if(!dir.exists(backupPath)) {
dir.mkdir(backupPath);
}
QString dbname = backupPath + "backup.db";
if(!QFile::exists(dbname)) {
isOk = createTable(dbname);
} else {
_db = QSqlDatabase::addDatabase("QSQLITE");
_db.setDatabaseName(dbname);
isOk =_db.open();
}
qDebug() << "连接数据库:" << dbname;
if(!isOk) {
qDebug() << "连接失败:" << _db.lastError().text();
}
return isOk;
}
bool FMBackup::createTable(const QString &dbname)
{
_db = QSqlDatabase::addDatabase("QSQLITE");
_db.setDatabaseName(dbname);
_db.open();
QSqlQuery query(_db);
// 创建表
bool isOk = query.exec("create table tbl_card(card_no char(20) NOT NULL PRIMARY KEY, inner_no char(20), active_date char(10), active_time char(8))");
qDebug() << "创建数据库:" << dbname;
if (!isOk) {
qDebug() << "创建数据库失败:" << query.lastError().text();
}
return isOk;
}
bool FMBackup::insert(QString card_no, QString inner_no, QString date, QString time)
{
if(!_db.isOpen()) {
connect();
}
QSqlQuery query(_db);
bool isOk = query.exec(QString("insert into tbl_card('card_no','inner_no', 'active_date', 'active_time') values('%1','%2', '%3', '%4');")
.arg(card_no)
.arg(inner_no)
.arg(date)
.arg(time));
if(!isOk) {
qDebug() << "插入失败:" << query.lastError().text();
}
return isOk;
}
QSqlQuery FMBackup::cardQuery(QString date) const
{
QSqlQuery query(_db);
bool isOk = query.exec(QString("select * from tbl_card where 'date'='%1'").arg(date));
if(!isOk) {
qDebug() << "查询数据时出现错误:" << query.lastError().text();
}
return query;
}
bool FMBackup::reset()
{
QSqlQuery query(_db);
bool isOk = query.exec("VACUUM");
qDebug() << "数据库重置: " << isOk;
return isOk;
}
#ifndef FMBACKUP_H
#define FMBACKUP_H
#include <QSqlDatabase>
#include <QSqlRecord>
class FMBackup
{
public:
static FMBackup* instance();
QSqlDatabase database() { return _db;}
bool insert(QString card_no, QString inner_no, QString date, QString time);
QSqlQuery cardQuery(QString date) const;
bool reset();
private:
FMBackup();
QSqlDatabase _db;
bool connect();
bool createTable(const QString &dbname);
};
#endif // FMBACKUP_H
#include "fmnetwork.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include <QTimer>
#include <QDebug>
FMNetwork::FMNetwork(QObject *parent) :
QObject(parent),
_nam(new QNetworkAccessManager),
_req(new QNetworkRequest)
{
}
FMNetwork::~FMNetwork()
{
delete _nam;
delete _req;
}
bool FMNetwork::send(const QString &url, const QByteArray &reqData, QByteArray &rspData, QString &error)
{
bool isOk = false;
qDebug() << "Send Url: " << url;
qDebug() << "Send Data: " << reqData;
_req->setUrl(url);
// 设置请求头
_req->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
_req->setHeader(QNetworkRequest::ContentLengthHeader, reqData.length());
auto reply = _nam->post(*_req, reqData);
// 使用定时器处理超时
QEventLoop loop;
connect(_nam, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()),&loop,SLOT(quit()));
timer.start(1000 * 30);
loop.exec();
if(timer.isActive())
{
timer.stop();
if (reply->error() == QNetworkReply::NoError) {
isOk = true;
rspData = reply->readAll();
} else {
error = reply->errorString();
}
}else{
error = "请求超时";
}
return isOk;
}
#ifndef FMNETWORK_H
#define FMNETWORK_H
#include <QObject>
#include <QJsonObject>
class QNetworkAccessManager;
class QNetworkRequest;
class FMNetwork : public QObject
{
Q_OBJECT
public:
explicit FMNetwork(QObject *parent = 0);
~FMNetwork();
bool send(const QString &url, const QByteArray &reqData, QByteArray &rspData, QString &error);
private:
QNetworkAccessManager *_nam;
QNetworkRequest *_req;
};
#endif // FMNETWORK_H
#include "fmvip.h"
#include <QCryptographicHash>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include <QDebug>
FMVip::FMVip(QObject *parent) : QObject(parent)
{
}
void FMVip::login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj)
{
QJsonObject reqJob;
reqJob["appId"] = APP_ID;
reqJob["business_date"] = QDate::currentDate().toString("yyyyMMdd");
reqJob["t"] = QString::number(QDateTime::currentMSecsSinceEpoch());
reqJob["fm_cmd"] = "member_check_request";
reqJob["partner_id"] = PARTNER_ID;
reqJob["store_id"] = StoreId;
reqJob["pos_id"] = PosId;
reqJob["operator_id"] = "8888";
reqJob["member_sign"] = vipNo;
reqJob["inner_code"] = innerCode;
reqJob["member_type"] = (int)memberType(vipNo);
QJsonDocument jsonDoc(reqJob);
QString signStr = sign(reqJob);
QString url = QString("http://member.lxj.sandload.cn/member/service/restful/pos?sign=%1").arg(signStr);
QByteArray rspData;
QString error;
QJsonParseError jsonError;
QJsonDocument rspJsonDoc;
if(networker.send(url, jsonDoc.toJson(), rspData, error))
{
qDebug() << "Server Response:" << QString::fromUtf8(rspData);
rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
rspObj = rspJsonDoc.object();
} else {
rspObj["statuc_code"] = 101;
rspObj["msg"] = jsonError.errorString();
}
} else {
rspObj["status_code"] = 102;
rspObj["msg"] = error;
}
}
void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj)
{
QJsonObject reqJob;
reqJob["appId"] = APP_ID;
reqJob["business_date"] = QDate::currentDate().toString("yyyyMMdd");
reqJob["t"] = QString::number(QDateTime::currentMSecsSinceEpoch());
reqJob["fm_cmd"] = "order_recharge_request";
reqJob["partner_id"] = PARTNER_ID;
reqJob["store_id"] = StoreId;
reqJob["pos_id"] = PosId;
reqJob["operator_id"] = "8888";
reqJob["trans_id"] = createTransId(StoreId, PosId);
QJsonObject transObj;
transObj["account"] = fm_open_id;
transObj["amount"] = amount;
transObj["cash_amount"] = amount;
reqJob["transaction"] = transObj;
QJsonDocument jsonDoc(reqJob);
QString signStr = sign(reqJob);
QString url = QString("http://member.lxj.sandload.cn/member/service/restful/pos?sign=%1").arg(signStr);
QByteArray rspData;
QString error;
QJsonParseError jsonError;
QJsonDocument rspJsonDoc;
if(networker.send(url, jsonDoc.toJson(), rspData, error))
{
qDebug() << "Server Response:" << QString::fromUtf8(rspData);
rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
rspObj = rspJsonDoc.object();
} else {
rspObj["statuc_code"] = 101;
rspObj["msg"] = jsonError.errorString();
}
} else {
rspObj["status_code"] = 102;
rspObj["msg"] = error;
}
}
QString FMVip::createTransId(const QString &storeId, const QString posId) const
{
QString dateTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
QString transId = dateTime + storeId + posId;
return transId;
}
FMVip::MemberType FMVip::memberType(const QString &vipNo) const
{
switch (vipNo.length()) {
case 20:
return FMVip::PayCode;
case 16:
return FMVip::EntityCard;
case 11:
return FMVip::Phone;
case 10:
return FMVip::Account;
}
return FMVip::EntityCard;
}
QString FMVip::sign(const QJsonObject &reqJob) const
{
qDebug() << __FUNCTION__;
// 解析JSON插入MAP中按字典排序
QMap<QString, QString> mapData;
for (QString word : {"appId","fm_cmd","partner_id","store_id","pos_id","operator_id","t"}) {
if(reqJob[word].isDouble()) {
mapData[word] = QString::number(reqJob[word].toDouble());
} else {
mapData[word] = reqJob[word].toString();
}
}
// 使用URL键值对的格式拼接
QString sb = "";
foreach(QString key , mapData.keys())
{
sb += (key + "=" + mapData.value(key) + "&");
}
sb.remove(sb.length() - 1, 1); // 去掉最后一个&
sb.append(KEY_CODE);
QByteArray bt;
bt.append(sb);
qDebug() << "Sign String: " << bt;
QByteArray md5Bt = QCryptographicHash::hash(bt, QCryptographicHash::Md5);
return md5Bt.toHex();
}
#ifndef FMVIP_H
#define FMVIP_H
#include "fmnetwork.h"
#include <QObject>
// 商家信息
#define APP_ID "T008"
#define PARTNER_ID "17ef7396-4c56-4e08-9f3f-5cba520234d6"
#define KEY_CODE "ad124d4e-5f5a-450b-aa4b-902dfdb4631e"
#define StoreId "117017"
#define PosId "8888"
class FMVip : public QObject
{
Q_OBJECT
enum MemberType {
PayCode = 1,
Phone,
Account,
EntityCard
};
public:
explicit FMVip(QObject *parent = 0);
void login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj);
void recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj);
private:
QString createTransId(const QString &storeId, const QString posId) const;
MemberType memberType(const QString &vipNo) const;
QString sign(const QJsonObject &reqJob) const;
FMNetwork networker;
signals:
public slots:
};
#endif // FMVIP_H
#include "panel.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Panel w;
w.show();
return a.exec();
}
#include "panel.h"
#include "ui_panel.h"
#include "reader.h"
#include "fmbackup.h"
#include <QDateTime>
#include <QSqlQuery>
#include <QSqlTableModel>
Panel::Panel(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Panel)
{
ui->setupUi(this);
ui->history_date->setDate(QDate::currentDate());
Reader::instance()->connectReader();
connect(Reader::instance(), &Reader::read, this, &Panel::onReader);
connect(Reader::instance(), &Reader::actived, this, &Panel::onActived);
on_tabWidget_currentChanged(1);
sqlModel = new QSqlTableModel(this, FMBackup::instance()->database());
sqlModel->setTable("tbl_card");
sqlModel->setHeaderData(0, Qt::Horizontal, "卡号");
sqlModel->setHeaderData(1, Qt::Horizontal, "内码");
sqlModel->setHeaderData(2, Qt::Horizontal, "激活日期");
sqlModel->setHeaderData(3, Qt::Horizontal, "激活时间");
sqlModel->setSort(3, Qt::DescendingOrder);
ui->history_list->setModel(sqlModel);
connect(this, &Panel::dateChanged, this, &Panel::onDateChanged);
}
Panel::~Panel()
{
delete ui;
delete sqlModel;
}
void Panel::onReader(bool isOk, QString vipNo, QString uuid, QString error)
{
if(isOk) {
ui->card_label->setText(vipNo);
ui->state_label_rd->setText("正在登录...");
QJsonObject job;
fmvip.login(vipNo, uuid, job);
qDebug() << job;
if(job["status_code"].toInt() == 100) {
ui->state_label_rd->clear();
ui->account_label->setText(job["account"].toString());
ui->name_label->setText(job["name"].toString());
ui->phone_label->setText(job["mobile"].toString());
ui->birthday_label->setText(job["birthday"].toString());
ui->amount_label->setText(QString::number(job["amount"].toInt()/100.00, 'f', 2));
ui->score_label->setText(QString::number(job["score"].toInt()));
fm_open_id = job["fm_unique_id"].toString();
} else {
ui->state_label_rd->setText(job["msg"].toString());
fm_open_id.clear();
}
} else {
ui->card_label->setText("未知");
ui->state_label_rd->setText(error);
fm_open_id.clear();
}
}
void Panel::on_tabWidget_currentChanged(int index)
{
switch (index) {
case 0:
Reader::instance()->stopReadCard();
Reader::instance()->startActivateCard();
break;
case 1:
Reader::instance()->stopActivateCard();
Reader::instance()->startReadCard();
default:
break;
}
}
void Panel::onActived(bool isSuccess, QString vipNo, QString error)
{
ui->card_label_ac->setText(vipNo);
ui->state_label->setText(isSuccess ? "激活成功" : "激活失败:"+error);
if(isSuccess) {
emit dateChanged(QDateTime::currentDateTime().toString("yyyy-MM-dd"));
}
}
void Panel::on_history_date_dateChanged(const QDate &date)
{
emit dateChanged(date.toString("yyyy-MM-dd"));
}
void Panel::onDateChanged(QString date)
{
sqlModel->setFilter(QString("active_date='%1'").arg(date));
sqlModel->select();
}
void Panel::on_recharge_btn_clicked()
{
if(fm_open_id == "" || ui->account_label->text().isEmpty()) {
ui->state_label_rd->setText("充值失败,请先刷卡认证");
return;
}
int amount = ui->amount_edit->text().toDouble() * 100;
ui->state_label_rd->setText(QString("正在充值: %1 元").arg(amount));
QJsonObject job;
fmvip.recharge(fm_open_id, amount, job);
qDebug() << job;
if(job["status_code"].toInt() == 100) {
ui->state_label_rd->setText(QString("成功充值: %1 元").arg(job["amount"].toInt()/100.00));
ui->amount_label->setText(QString::number(job["after_value"].toInt()/100.00, 'f', 2));
ui->amount_edit->setText("0.00");
} else {
ui->state_label_rd->setText(job["msg"].toString());
}
fm_open_id.clear();
}
#ifndef PANEL_H
#define PANEL_H
#include "fmvip.h"
#include <QMainWindow>
class QSqlTableModel;
namespace Ui {
class Panel;
}
class Panel : public QMainWindow
{
Q_OBJECT
public:
explicit Panel(QWidget *parent = 0);
~Panel();
signals:
void dateChanged(QString date);
private slots:
void onReader(bool isOk, QString vipNo, QString uuid, QString error);
void on_tabWidget_currentChanged(int index);
void onActived(bool isSuccess, QString vipNo, QString error);
void on_history_date_dateChanged(const QDate &date);
void onDateChanged(QString date);
void on_recharge_btn_clicked();
private:
Ui::Panel *ui;
QSqlTableModel *sqlModel;
FMVip fmvip;
QString fm_open_id;
};
#endif // PANEL_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Panel</class>
<widget class="QMainWindow" name="Panel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<height>451</height>
</rect>
</property>
<property name="windowTitle">
<string>Panel</string>
</property>
<property name="styleSheet">
<string notr="true">#card_desc_label {
max-width: 40px;
}
#card_label {
min-width: 150px;
max-width: 150px;
}
#recharge_btn {
min-width: 100px;
max-width: 100px;
}
#amount_edit {
min-width: 50px;
max-width: 50px;
}</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="active_tab">
<attribute name="title">
<string>激活</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
<widget class="QDateEdit" name="history_date"/>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="card_desc_label_ac">
<property name="text">
<string>卡号:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="state_desc_label">
<property name="text">
<string>状态:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="card_label_ac">
<property name="text">
<string>000000000000</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="state_label">
<property name="text">
<string>未激活</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="history_label">
<property name="text">
<string>激活历史:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<widget class="QTableView" name="history_list"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="recharge_tab">
<attribute name="title">
<string>充值</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="account_desc_label">
<property name="text">
<string>会员账号:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="name_desc_label">
<property name="text">
<string>姓名:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="name_label">
<property name="text">
<string>未知</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="amount_label">
<property name="text">
<string>0.00</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="account_label">
<property name="text">
<string>未知</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="phone_label">
<property name="text">
<string>未知</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="birthday_label">
<property name="text">
<string>未知</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="birthday_desc_label">
<property name="text">
<string>生日:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="card_desc_label">
<property name="text">
<string>卡号:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="card_label">
<property name="text">
<string>0000000000000000</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLabel" name="state_label_rd">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLineEdit" name="amount_edit">
<property name="text">
<string>0.00</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QPushButton" name="recharge_btn">
<property name="text">
<string>充值</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="phone_desc_label">
<property name="text">
<string>手机号:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="amount_desc_label">
<property name="text">
<string>余额:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="score_desc_label">
<property name="text">
<string>积分:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="score_label">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
#ifndef READCFG_HPP
#define READCFG_HPP
#include <QDebug>
#include <QString>
#include <QVariantMap>
#include <QSettings>
#include <QCoreApplication>
#define CFG_FILENAME "FMVip.cfg"
#define CFG_SECTION_READER "Reader"
#define CFG_READER_PORT "port"
#define CFG_READER_SECTION "section"
#define CFG_READER_BAUD "baud"
#define CFG_READER_PWD "password"
#define CFG_READER_PWD_DEFAULT "password_default"
class ReadCfg
{
public:
static bool readvalueforkey(const QString &cfgfilename, const QString &section, const QString &key, QString &value)
{
QString path = qApp->applicationDirPath() + "/" + cfgfilename;
qDebug() << "read cfg file path:" << path;
auto *configIniRead = new QSettings(path, QSettings::IniFormat);
configIniRead->setIniCodec("utf-8");
QString akey = "/" + section + "/" + key;
value = configIniRead->value(akey).toString();
delete configIniRead;
return value == "" ? false : true;
}
static bool readvalueforheadlist(const QString &cfgfilename, const QString &section, QVariantMap &value)
{
QString path = qApp->applicationDirPath() + "/" + cfgfilename;
QSettings *configIniRead = new QSettings(path, QSettings::IniFormat);
configIniRead->setIniCodec("utf-8");
QString akey = "/" + section + "/" + "headlist";
QStringList keylist = configIniRead->value(akey).toString().split(",");
if(keylist.size() == 0 || keylist[0] == "")
{
qDebug() << QString("read %1 file %2 section for headlist failed").arg(path).arg(section);
return false;
}
foreach (auto key, keylist)
{
QString tmpkey = "/" + section + "/" + key;
if(configIniRead->value(tmpkey).toString() != "")
value.insert(key, configIniRead->value(tmpkey).toString());
}
delete configIniRead;
return (value.size() == 0)? false : true;
}
};
#endif // READCFG_HPP
#include "reader.h"
Reader* Reader::instance()
{
static Reader reader;
return &reader;
}
Reader::Reader(QObject *parent) : QObject(parent)
{
s_end = true;
s_initsuc = false;
s_reader = NULL;
this->moveToThread(&m_thread);
m_thread.start();
QVariantMap map;
bool isOk = ReadCfg::readvalueforheadlist(CFG_FILENAME, CFG_SECTION_READER, map);
if(isOk) {
s_readerCfg.Port = map.value(CFG_READER_PORT).toInt();
s_readerCfg.Baud = map.value(CFG_READER_BAUD).toInt();
s_readerCfg.Section = map.value(CFG_READER_SECTION).toInt();
s_readerCfg.Password = map.value(CFG_READER_PWD).toString();
s_readerCfg.PasswordDefault = map.value(CFG_READER_PWD_DEFAULT).toString();
qDebug() << "Read values: " << s_readerCfg.Port << s_readerCfg.Baud << s_readerCfg.Section << s_readerCfg.Password << s_readerCfg.PasswordDefault;
} else {
qDebug() << "Read value for head list failed.";
}
connect(&_activater, SIGNAL(activeted(bool,QString,QString)), this, SIGNAL(actived(bool,QString,QString)));
connect(&_readWorker, SIGNAL(read(bool,QString,QString,QString)), this, SIGNAL(read(bool,QString,QString,QString)));
}
Reader::~Reader()
{
_activater.Stop();
_readWorker.Stop();
disconnectReader();
}
bool Reader::readVipNO()
{
QString vipNo;
QString error;
QString uuid;
int tryTimes = 3;
while(tryTimes && s_end && (!ReadCard(s_reader, s_readerCfg.Section, vipNo, uuid , error)))
{
if(error != "") {
_errorMsg = "Readcard failed: " + error;;
qDebug() << _errorMsg;
}
--tryTimes;
Sleep(500);
}
if(!s_end)
{
condition.wakeAll();
return false;
}
qDebug() << __FUNCTION__ << vipNo << uuid;
emit getVipNO(vipNo, uuid);
return true;
}
void Reader::connectReader()
{
qDebug() << "son:" <<QThread::currentThreadId() << "s_initsuc:" << s_initsuc << "s_reader: " << s_reader;
bool sign = true;
QString error;
if(s_end)
{
if(s_initsuc) {
DisConnectDevice(s_reader);
}
int tryTimes = 3;
do
{
if(sign)
{
sign = ConnectDevice(s_readerCfg.Port,
s_readerCfg.Baud,
s_readerCfg.Section,
s_readerCfg.PasswordDefault,
s_reader,
error);
}
if(!sign) {
s_reader = NULL;
_errorMsg = "Connect reader device failed: ";
qDebug() << _errorMsg << error;
}
else
s_initsuc = sign;
Sleep(500);
}while(s_end && !sign && --tryTimes);
}
}
void Reader::disconnectReader()
{
s_end = false;
mutex.lock();
if(!condition.wait(&mutex, 2*1000))
{
m_thread.terminate();
m_thread.wait();
}
if(s_initsuc || s_reader > 0)
{
if(_activater.isRunning()) {
_activater.Stop();
}
DisConnectDevice(s_reader);
s_reader = NULL;
s_initsuc = false;
}
mutex.unlock();
}
void Reader::startActivateCard()
{
if(s_initsuc) {
QString error;
if(LoadKeyHex(s_reader, s_readerCfg.Section, s_readerCfg.PasswordDefault, error)){
_activater.Init(s_reader, s_readerCfg.Section, s_readerCfg.Password);
_activater.start();
}
}
}
void Reader::stopActivateCard()
{
_activater.Stop();
}
void Reader::startReadCard()
{
if(s_initsuc) {
QString error;
if(LoadKeyHex(s_reader, s_readerCfg.Section, s_readerCfg.Password, error)) {
_readWorker.Init(s_reader, s_readerCfg.Section);
_readWorker.start();
} else {
qDebug() << "load key error: " << error;
}
}
}
void Reader::stopReadCard()
{
_readWorker.Stop();
}
#ifndef READER_H
#define READER_H
#include "readcfg.h"
#include "../fmvip_card_reader/fm_mwrf32/fm_mwrf32.h"
#include "activateworker.h"
#include "readworker.h"
#include <QMutex>
#include <QString>
#include <QObject>
#include <QThread>
#include <QWaitCondition>
#include <windows.h>
class Reader : public QObject
{
Q_OBJECT
public:
static Reader* instance();
~Reader();
void connectReader();
void resetEnd() {s_end = false;}
QString errorMsg() const { return this->_errorMsg;}
// 读卡器错误
struct {
QString ConnectedError = "open device failed";
QString PasswordError = "check password failure";
} ReaderError;
// 读卡器配置
struct ReaderCfg{
int Port;
int Baud;
int Section;
QString Password;
QString PasswordDefault;
};
private:
Reader(QObject *parent = 0);
private:
bool s_end;
bool s_initsuc;
QMutex mutex;
QWaitCondition condition;
HANDLE s_reader;
QThread m_thread;
ReaderCfg s_readerCfg;
QString _errorMsg;
ActivateWorker _activater;
ReadWorker _readWorker;
signals:
void getVipNO(QString VipNO, QString uuid);
void actived(bool isSuccess, QString VipNO, QString error);
void read(bool isSuccess, QString vipNo, QString uuid, QString error);
public slots:
void disconnectReader();
bool readVipNO();
void startActivateCard();
void stopActivateCard();
void startReadCard();
void stopReadCard();
};
#endif // READER_H
#include "readworker.h"
#include <QDebug>
ReadWorker::ReadWorker()
{
}
void ReadWorker::Init(HANDLE handle, int sector)
{
m_handle = handle;
m_sector = sector;
}
void ReadWorker::Stop()
{
m_bStop = true;
}
void ReadWorker::run()
{
m_bStop = false;
while(!m_bStop)
{
QString vipNo;
QString uuid;
QString error;
bool result;
result = ReadCard(m_handle, m_sector, vipNo, uuid, error);
if(result){
emit read(result, vipNo, uuid, error);
}
if(!result && error != "could not find the card") {
qDebug() << result << vipNo << error;
emit read(result, vipNo, uuid, error);
}
Sleep(500);
}
}
#ifndef READWORKER_H
#define READWORKER_H
#include <QThread>
#include "../fmvip_card_reader/fm_mwrf32/fm_mwrf32.h"
class ReadWorker : public QThread
{
Q_OBJECT
public:
ReadWorker();
void Init(HANDLE handle, int sector);
void Stop();
protected:
void run();
private:
bool m_bStop;
HANDLE m_handle;
int m_sector;
signals:
void read(bool, QString vipNo, QString uuid, QString error);
};
#endif // READWORKER_H
#include "fm_mwrf32.h"
#include "fm_mwrf32.h"
#include "mwdll/mwrf32.h"
#include <QCryptographicHash>
#include <QDebug>
#include <iostream>
#define OldSector 2
bool ConnectDevice(int port, int baud, int sector, const QString password, HANDLE &handle, QString &error)
{
qDebug() << __FUNCTION__ << QString("port:%1,baud:%2,sector:%3,password:%4").arg(port).arg(baud).arg(sector).arg(password);
int st;
handle = rf_init(port, baud);
if((int)handle<=0)
......@@ -13,6 +18,8 @@ bool ConnectDevice(int port, int baud, int sector, const QString password, HANDL
return false;
}
st = rf_load_key_hex(handle, 0, sector, password.toLatin1().data());
st = rf_load_key_hex(handle, 0, OldSector, "ffffffffffff");
qDebug() << "st: " << st << "pwd: " << password.toLatin1().data();
if(st!=0)
{
rf_exit(handle);
......@@ -36,6 +43,7 @@ bool ReadCard(const HANDLE handle, int sector, QString &vipNo, QString& uuid, QS
return false;
}
uuid = QString::number(snr);
qDebug() << "uuid: " << uuid << "snr: " << snr;
// 鉴权
st = rf_authentication(handle, 0, sector);
if(st!=0)
......@@ -44,30 +52,35 @@ bool ReadCard(const HANDLE handle, int sector, QString &vipNo, QString& uuid, QS
return false;
}
// 读卡号
ZeroMemory(rdata,17);
st = rf_read(handle, sector*4, rdata);
if(st!=0)
{
error = "read data error";
return false;
for(int i=0; i<2; ++i) {
ZeroMemory(rdata,17);
st = rf_read(handle, sector*4+i, rdata);
qDebug() << "st: " << st<< "rdata: "<< (char*)rdata << QByteArray((char*)rdata).length();
if(st!=0)
{
error = "read data error";
return false;
}
vipNo += QByteArray((char*)rdata).trimmed();
}
vipNo = QString(QByteArray((char*)rdata, 16).toHex()).mid(17);
// 读效验数据
QString keyData;
ZeroMemory(rdata,17);
st = rf_read(handle, sector*4+1, rdata);
if(st!=0)
{
error = "read key_data error";
return false;
}
keyData = QString::fromLatin1((char*)rdata);
// 对比数据
if(keyData.compare(QCryptographicHash::hash(QString("%1%2").arg(vipNo,MD5_KEY).toLatin1(), QCryptographicHash::Md5).toHex().mid(8, 16)))
{
error = "check key_data error";
return false;
}
// QString keyData;
// ZeroMemory(rdata,20);
// st = rf_read(handle, sector*4+1, rdata);
// if(st!=0)
// {
// error = "read key_data error";
// return false;
// }
// keyData = QString::fromLatin1((char*)rdata);
// // 对比数据
// if(keyData.compare(QCryptographicHash::hash(QString("%1%2").arg(vipNo,MD5_KEY).toLatin1(), QCryptographicHash::Md5).toHex().mid(8, 16)))
// {
// error = "check key_data error";
// return false;
// }
rf_beep(handle,30);
return true;
}
......@@ -77,10 +90,9 @@ void DisConnectDevice(const HANDLE handle)
rf_exit(handle);
}
bool ActivateCard(const HANDLE handle, int sector, const QString newPassword, QString &error)
bool ActivateCard(const HANDLE handle, int sector, const QString newPassword, QString &vipNo, QString& uuid, QString &error)
{
int st;
QString vipNo;
// 寻卡
unsigned long snr; //卡片序列号
st = rf_card(handle, 0, &snr);
......@@ -89,44 +101,129 @@ bool ActivateCard(const HANDLE handle, int sector, const QString newPassword, QS
error = "could not find the card";
return false;
}
uuid = QString::number(snr);
// 从默认扇区读卡号
// 鉴权
st = rf_authentication(handle, 0, sector);
st = rf_authentication(handle, 0, OldSector);
if(st!=0)
{
error = "check password failure";
return false;
}
// 读卡
// 读卡
unsigned char rdata[17];
ZeroMemory(rdata,17);
st = rf_read(handle, sector*4, rdata);
st = rf_read(handle, OldSector*4, rdata);
if(st!=0)
{
error = "read data error";
error = "read default card no error";
return false;
}
vipNo = QString::fromLatin1(QByteArray((char*)rdata, 16).toHex()).mid(17);
// 写入效验数据
QByteArray keyData = QCryptographicHash::hash(QString("%1%2").arg(vipNo,MD5_KEY).toLatin1(), QCryptographicHash::Md5);
st = rf_write(handle, sector*4+1, (unsigned char*)keyData.toHex().mid(8, 16).data());
vipNo = QByteArray((char*)rdata);
// 将卡号写入传入的扇区
// 鉴权
st = rf_authentication(handle, 0, sector);
if(st!=0)
{
error = "check password failure";
return false;
}
// 写入卡号
qDebug() << "writeData: " << vipNo.toLatin1().toHex().mid(0,32);
char* writeData = vipNo.toLatin1().toHex().mid(0,32).data();
st = rf_write_hex(handle, sector*4, writeData);
if(st!=0)
{
error = "write data error";
error = "write data failure";
return false;
}
// 修改密码
QByteArray tmpData = newPassword.toLatin1();
char* key= tmpData.data();
unsigned char wkey[7];
ZeroMemory(wkey, 7);
a_hex(key, wkey, 12);
a_hex(tmpData.data(), wkey, 12);
st= rf_changeb3(handle, sector, wkey, 0, 0, 0, 1, 0, wkey);
if(st!=0)
{
error = "change password error";
return false;
}
qDebug() << "change password: " << tmpData;
// 删除原扇区内容
// 鉴权
st = rf_authentication(handle, 0, OldSector);
if(st!=0)
{
error = "check password failure";
return false;
}
// 初始化为0
st= rf_initval(handle, OldSector*4, 0);
if(st!=0)
{
error = "initval error";
return false;
}
// // 写入效验数据
// QByteArray keyData = QCryptographicHash::hash(QString("%1%2").arg(vipNo,MD5_KEY).toLatin1(), QCryptographicHash::Md5);
// st = rf_write(handle, sector*4+1, (unsigned char*)keyData.toHex().mid(8, 16).data());
// if(st!=0)
// {
// error = "write data error";
// return false;
// }
rf_beep(handle,30);
return true;
}
bool WriteCard(const HANDLE handle, int sector, QString data, QString &error)
{
qDebug() << __FUNCTION__ << QString("sector:%1, data:%2").arg(sector).arg(data);
int st;
unsigned char rdata[17];
// 寻卡
unsigned long snr; //卡片序列号
st = rf_card(handle, 0, &snr);
if(st!=0)
{
error = "could not find the card";
return false;
}
QString uuid = QString::number(snr);
qDebug() << "uuid: " << uuid << "snr: " << snr;
// 鉴权
st = rf_authentication(handle, 0, sector);
if(st!=0)
{
error = "check password failure";
return false;
}
qDebug() << "writeData: " << data.toLatin1().toHex().mid(0,32);
char* writeData = data.toLatin1().toHex().mid(0,32).data();
st = rf_write_hex(handle, sector*4, writeData);
if(st!=0)
{
error = "write data failure";
return false;
}
rf_beep(handle,30);
return true;
}
bool LoadKeyHex(const HANDLE handle, int sector, QString password, QString &error)
{
int st;
st = rf_load_key_hex(handle, 0, sector, password.toLatin1().data());
if(st!=0)
{
error = "Load key error";
return false;
}
return true;
}
#ifndef FM_MWRF32_H
#ifndef FM_MWRF32_H
#define FM_MWRF32_H
#include "fm_mwrf32_global.h"
......@@ -20,10 +20,10 @@ FM_MWRF32SHARED_EXPORT bool ConnectDevice(int port, int baud, int sector, const
FM_MWRF32SHARED_EXPORT void DisConnectDevice(const HANDLE handle);
/* 功能:激活卡片
* 参数:[1]设备句柄[2]新的读卡密码[3]错误信息[4]默认密码
* 参数:[1]设备句柄[2]新的读卡密码[3]错误信息[4]默认密码[5]卡号
* 返回:成功true
* */
FM_MWRF32SHARED_EXPORT bool ActivateCard(const HANDLE handle, int sector, const QString newPassword, QString& error);
FM_MWRF32SHARED_EXPORT bool ActivateCard(const HANDLE handle, int sector, const QString newPassword, QString& vipNo, QString& uuid, QString& error);
/* 功能:读取会员号
* 参数:[1]设备句柄[2]要读取的扇区号[3_out]会员号[4_out]UUID[5_out]错误原因
......@@ -31,4 +31,8 @@ FM_MWRF32SHARED_EXPORT bool ActivateCard(const HANDLE handle, int sector, const
* */
FM_MWRF32SHARED_EXPORT bool ReadCard(const HANDLE handle, int sector, QString& vipNo, QString& uuid, QString& error);
FM_MWRF32SHARED_EXPORT bool WriteCard(const HANDLE handle, int sector, QString data, QString &error);
FM_MWRF32SHARED_EXPORT bool LoadKeyHex(const HANDLE handle, int sector, QString password, QString &error);
#endif // FM_MWRF32_H
......@@ -23,3 +23,5 @@ unix {
}
Release:LIBS += -L$$PWD/mwdll -lmwrf32
DESTDIR = $$PWD/../../CardReader
#include "activateworker.h"
#include "activateworker.h"
#include <QDebug>
#include <QDateTime>
......@@ -24,8 +24,8 @@ void ActivateWorker::run()
{
QString error;
bool result;
result = ActivateCard(m_handle, 15, "ffffffffffff", error);
qDebug() << QDateTime::currentDateTime() << result << error;
QString vip, uuid;
result = ActivateCard(m_handle, 6, "313731383132", vip, uuid, error);
emit activeted(result, error);
Sleep(1000);
}
......
#include "mainwindow.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "../fm_mwrf32/fm_mwrf32.h"
#include <QDebug>
#include <QCryptographicHash>
#define ReadS 2
#if 1
#define ReadP "ffffffffffff"
#else
#define ReadP "313731383132"
#endif
HANDLE handle;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
......@@ -25,14 +32,14 @@ MainWindow::~MainWindow()
void MainWindow::on_pbt0_clicked()
{
QString error;
if(ConnectDevice(0, 9600, 15, "ffffffffffff", handle, error))
if(ConnectDevice(0, 115200, ReadS, ReadP, handle, error))
{
ui->label->setText("连接设备成功!");
ui->pbt1->setEnabled(true);
ui->pbt2->setEnabled(true);
}else
{
ui->label->setText("连接设备失败!");
ui->label->setText("连接设备失败!" + error);
qDebug() << error;
}
......@@ -52,7 +59,7 @@ void MainWindow::on_pbt2_clicked()
QString error;
QString vipNo;
QString uuid;
if(ReadCard(handle, 15, vipNo, uuid, error))
if(ReadCard(handle, ReadS, vipNo, uuid, error))
{
ui->label_3->setText(uuid + "###" + vipNo);
}else
......@@ -79,3 +86,14 @@ void MainWindow::on_pbt1_2_clicked()
ui->pbt1_2->setEnabled(false);
ui->pbt2->setEnabled(true);
}
void MainWindow::on_write_btn_clicked()
{
QString error;
if(WriteCard(handle, 2, ui->write_line->text(), error))
{
qDebug() << "写入成功";
} else {
qDebug() << "写入失败:" << error;
}
}
#ifndef MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
......@@ -25,6 +25,8 @@ private slots:
void on_pbt1_2_clicked();
void on_write_btn_clicked();
private:
Ui::MainWindow *ui;
......
......@@ -60,7 +60,7 @@
<property name="geometry">
<rect>
<x>150</x>
<y>420</y>
<y>430</y>
<width>81</width>
<height>51</height>
</rect>
......@@ -88,8 +88,8 @@
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>80</x>
<y>374</y>
<x>10</x>
<y>390</y>
<width>231</width>
<height>31</height>
</rect>
......@@ -129,7 +129,11 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
<widget class="QLineEdit" name="lineEdit">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</widget>
......@@ -151,10 +155,37 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_2"/>
<widget class="QLineEdit" name="lineEdit_2">
<property name="text">
<string>9600</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="write_btn">
<property name="geometry">
<rect>
<x>370</x>
<y>430</y>
<width>81</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>写数据</string>
</property>
</widget>
<widget class="QLineEdit" name="write_line">
<property name="geometry">
<rect>
<x>350</x>
<y>400</y>
<width>113</width>
<height>20</height>
</rect>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
......
......@@ -21,4 +21,6 @@ HEADERS += mainwindow.h \
FORMS += mainwindow.ui
Release:LIBS += -L../fm_mwrf32/release -lfm_mwrf32
DESTDIR = $$PWD/../../CardReader
Release:LIBS += -L$$PWD/../../CardReader -lfm_mwrf32
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment