Commit 5e721944 by NitefullWind

Merge branch 'EntityCard' into dev

parents d2c55b4b 79fb9d12
[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\
fmbackup.cpp \
fmnetwork.cpp \
fmvip.cpp \
rechargewnd.cpp \
fmvipwnd.cpp \
fmloading.cpp \
fmsetting.cpp \
cardreader.cpp \
fmmsgwnd.cpp \
fmlogger.cpp
HEADERS += \
fmbackup.h \
fmnetwork.h \
fmvip.h \
rechargewnd.h \
fmvipwnd.h \
fmloading.h \
fmsetting.h \
cardreader.h \
fmmsgwnd.h \
fmp_logstream.h \
fmlogger.h
FORMS += \
rechargewnd.ui \
fmloading.ui \
fmmsgwnd.ui
DESTDIR = $$PWD/../CardReader
LIBS += -L$$PWD/../CardReader -lmwrf32
RESOURCES += \
res/res.qrc
#include "cardreader.h"
#include "mwdll/mwrf32.h"
#include "fmsetting.h"
#include <QDebug>
CardReader::CardReader(QObject *parent) : QThread(parent)
{
}
CardReader::~CardReader()
{
}
void CardReader::run()
{
_isRunning = true;
int port = FMSetting::GetValue("Port", 0).toInt();
int baud = FMSetting::GetValue("Baud", 115200).toInt();
_isRunning &= ConnectDevice(port, baud);
if(!_isRunning) {
return;
}
def_sector = FMSetting::GetValue("DefaultSector", 4).toInt();
def_pwd = FMSetting::GetValue("DefaultPwd", "ffffffffffff").toString();
sector = FMSetting::GetValue("Sector", 1).toInt();
password = FMSetting::GetValue("Password", "313731383132").toString();
_isRunning &= LoadKeyHex(def_sector, def_pwd);
_isRunning &= LoadKeyHex(0, def_pwd);
_isRunning &= LoadKeyHex(sector, password);
_isRunning &= LoadKeyHex(15, "000000000000");
willActiveCard = needActiveCard = "";
while(_isRunning) {
OperatorCard();
Sleep(300);
}
}
void CardReader::Stop()
{
_isRunning = false;
}
void CardReader::setError(const QString &error)
{
_error = error;
FM_ERROR() << error;
emit hadError(_error);
}
QString CardReader::LastError() const
{
return _error;
}
bool CardReader::ConnectDevice(int port, int baud)
{
_handle = rf_init(port, baud);
if((int)_handle<=0)
{
setError("连接设备失败");
return false;
}
rf_beep(_handle, 30);
return true;
}
void CardReader::DisConnectDevice()
{
rf_exit(_handle);
}
bool CardReader::LoadKeyHex(qint8 sec, const QString &password)
{
char *pwd = password.toLatin1().data();
if(rf_load_key_hex(_handle, 0, sec, pwd) != 0) {
setError(QString("%1扇区密码加载失败").arg(sec));
return false;
}
return true;
}
bool CardReader::ReadData(qint8 sec, QString &data, qint8 blockNums, bool isHex)
{
data.clear();
// 验证密码
if(rf_authentication(_handle, 0, sec) != 0) {
setError(QString("%1扇区密码错误").arg(sec));
return false;
}
for(int i=0; i<blockNums; ++i) {
if(isHex){
// 读卡,16进制
char _data[32];
ZeroMemory(_data, 32);
if(rf_read_hex(_handle, sec*4+i, _data) != 0) {
setError(QString("%1扇区数据读取失败").arg(sec));
return false;
}
data += QString::fromLatin1(_data).trimmed();
} else {
unsigned char _data[17];
ZeroMemory(_data, 17);
if(rf_read(_handle, sec*4+i, _data) != 0) {
setError(QString("%1扇区数据读取失败").arg(sec));
return false;
}
data += QString::fromLatin1((char*)_data).trimmed();
}
}
return true;
}
bool CardReader::OperatorCard()
{
// 检查是否需要激活卡
if(needActiveCard != "" && needActiveCard==willActiveCard) {
FM_INFO() << "Active card: " << needActiveCard;
activedSuccess = Active(needActiveCard);
FM_INFO() << "Active card success: " << activedSuccess;
needActiveCard = willActiveCard = lastUUID = "";
waitActive.wakeAll();
}
// 故意鉴权失败,使卡片不用离开读卡器即可再次寻卡
rf_authentication(_handle, 0, 15);
bool isActived = true;
QString data, uuid, vipNo="";
unsigned long snr;
if(rf_card(_handle, 0, &snr) != 0) {
return false;
}
if(!ReadData(0, data)) {
return false;
}
uuid = data.mid(0, 10);
// 判断是否还是上一张卡
if(uuid == lastUUID) {
// 同一张卡,直接返回
return false;
} else {
lastUUID = uuid;
activedSuccess = false;
needActiveCard = willActiveCard = "";
FM_INFO() << "Find new card: " << lastUUID;
}
// 读默认扇区,看是否是激活过的卡(不用rf_authentcation,因为验证密码出错需重新寻卡)
if(ReadData(def_sector, data)) {
if(data == "00000000000000000000000000000000") {
if(ReadData(sector, data, 2, false)) {
vipNo = data;
isActived = true;
}
} else {
// 从def_sector扇区读取账号
if(ReadData(def_sector, data)){
vipNo = data.mid(16);
isActived = false;
needActiveCard = vipNo;
}
}
}
FM_INFO() << "Vip No: " << vipNo << " Is actived: " << isActived;
if(vipNo!="") {
emit hadVipNo(vipNo, uuid, isActived);
}
return false;
}
bool CardReader::ActiveCard(QString vipNo)
{
mutex.lock();
willActiveCard = vipNo;
waitActive.wait(&mutex);
mutex.unlock();
return activedSuccess;
}
bool CardReader::Active(const QString &vipNo)
{
// 将卡号写入sec的扇区
if(!LoadKeyHex(sector, def_pwd)) {
return false;
}
// 鉴权
if(rf_authentication(_handle, 0, sector) != 0){
setError(QString("%1扇区密码错误").arg(sector));
return false;
}
// 写入卡号
char* writeData = vipNo.toLatin1().toHex().mid(0,32).data();
if(rf_write_hex(_handle, sector*4, writeData) !=0 ) {
setError("写入卡号失败");
return false;
}
// 修改密码
QByteArray tmpData = password.toLatin1();
unsigned char wkey[7];
ZeroMemory(wkey, 7);
a_hex(tmpData.data(), wkey, 12);
if(rf_changeb3(_handle, sector, wkey, 0, 0, 0, 1, 0, wkey) != 0) {
setError("修改密码失败");
return false;
}
// 删除原扇区内容
LoadKeyHex(def_sector, def_pwd);
// 鉴权
if(rf_authentication(_handle, 0, def_sector) != 0) {
setError(QString("%1扇区密码错误").arg(def_sector));
return false;
}
// 初始化为0
char zeroData[33] = "00000000000000000000000000000000";
if(rf_write_hex(_handle, def_sector*4, zeroData) !=0 ){
setError("擦除原数据失败");
return false;
}
rf_beep(_handle, 30);
rf_halt(_handle);
return true;
}
void CardReader::ClearInfo()
{
willActiveCard = needActiveCard = lastUUID = "";
activedSuccess = false;
}
#ifndef CARDREADER_H
#define CARDREADER_H
#include "fmlogger.h"
#include <QThread>
#include <windows.h>
#include <QMutex>
#include <QWaitCondition>
class CardReader : public QThread
{
Q_OBJECT
public:
explicit CardReader(QObject *parent = 0);
~CardReader();
void Stop();
QString LastError() const;
bool ConnectDevice(int port, int baud);
void DisConnectDevice();
bool ActiveCard(QString vipNo);
void ClearInfo();
signals:
void hadError(const QString &error);
void hadVipNo(const QString &vipNo, const QString &uuid, bool isActived);
protected:
void run();
private:
HANDLE _handle;
QString _error;
bool _isRunning;
qint8 def_sector, sector;
QString def_pwd, password;
QString willActiveCard, needActiveCard, lastUUID;
QMutex mutex;
QWaitCondition waitActive;
bool activedSuccess;
void setError(const QString& error);
bool OperatorCard();
bool LoadKeyHex(qint8 sec, const QString &password);
/**
* @brief ReadData
* @param sec 扇区号0-15
* @param data 数据
* @param blockNums 块数量
* @param isHex 是否是16进制
* @return
*/
bool ReadData(qint8 sec, QString &data, qint8 blockNums=1, bool isHex=true);
bool Active(const QString &vipNo);
};
#endif // CARDREADER_H
#include "fmbackup.h"
#include "fmlogger.h"
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDir>
#include <QFile>
#include <QApplication>
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();
}
FM_INFO() << "连接数据库:" << dbname;
if(!isOk) {
setError("连接数据库失败:" + _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_recharge("
"id integer PRIMARY KEY autoincrement,"
"card_no char(20) NOT NULL,"
"inner_no char(20),"
"recharge_amount double,"
"after_amount double,"
"fm_id char(25),"
"recharge_date char(10), "
"recharge_time char(8))");
FM_DEBUG() << "创建表:" << dbname;
if (!isOk) {
setError("创建表失败:" + query.lastError().text());
}
return isOk;
}
bool FMBackup::insert(QString card_no, QString inner_no,
double recharge_amount, double after_amount,
QString fm_id,
QString date, QString time)
{
if(!_db.isOpen()) {
connect();
}
QSqlQuery query(_db);
bool isOk = query.exec(QString("insert into tbl_recharge("
"'card_no',"
"'inner_no',"
"'recharge_amount',"
"'after_amount',"
"'fm_id',"
"'recharge_date',"
"'recharge_time') values('%1','%2', '%3', '%4', '%5', '%6', '%7');")
.arg(card_no)
.arg(inner_no)
.arg(recharge_amount)
.arg(after_amount)
.arg(fm_id)
.arg(date)
.arg(time));
if(!isOk) {
setError("插入失败:" + query.lastError().text());
}
return isOk;
}
QSqlQuery FMBackup::cardQuery(QString date)
{
QSqlQuery query(_db);
bool isOk = query.exec(QString("select * from tbl_recharge where 'date'='%1'").arg(date));
if(!isOk) {
setError("查询数据时出现错误:" + query.lastError().text());
}
return query;
}
bool FMBackup::reset()
{
QSqlQuery query(_db);
bool isOk = query.exec("VACUUM");
setError("数据库重置: " + isOk ? "成功" : "失败");
return isOk;
}
void FMBackup::setError(const QString &error)
{
_error = error;
FM_ERROR() << error;
}
QString FMBackup::lastError() const
{
return _error;
}
#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, double recharge_amount, double after_amount, QString fm_id, QString date, QString time);
QSqlQuery cardQuery(QString date);
bool reset();
QString lastError() const;
private:
FMBackup();
QSqlDatabase _db;
QString _error;
bool connect();
bool createTable(const QString &dbname);
void setError(const QString &error);
};
#endif // FMBACKUP_H
#include "fmloading.h"
#include "ui_fmloading.h"
FMLoading::FMLoading(QDialog *parent) :
QDialog(parent),
ui(new Ui::FMLoading)
{
ui->setupUi(this);
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_TranslucentBackground, true);
movie = new QMovie(":/img/loading.gif");
movie->start();
connect(movie, SIGNAL(finished()), movie, SLOT(start()));
ui->loading_lbl->setMovie(movie);
}
FMLoading::~FMLoading()
{
if(movie != NULL) {
delete movie;
movie = NULL;
}
delete ui;
}
#ifndef FMLOADING_H
#define FMLOADING_H
#include <QDialog>
#include <QMovie>
namespace Ui {
class FMLoading;
}
class FMLoading : public QDialog
{
Q_OBJECT
public:
explicit FMLoading(QDialog *parent = 0);
~FMLoading();
private:
Ui::FMLoading *ui;
QMovie *movie;
};
#endif // FMLOADING_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FMLoading</class>
<widget class="QWidget" name="FMLoading">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>124</width>
<height>124</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QLabel" name="loading_lbl">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>124</width>
<height>124</height>
</rect>
</property>
<property name="text">
<string>loading...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
#include "fmlogger.h"
#include "fmsetting.h"
#include <QApplication>
#include <QDateTime>
#include <QFile>
#include <QDir>
FMLogger::FMLogger(QObject *parent) : QObject(parent),
_file(nullptr)
{
}
FMLogger::~FMLogger()
{
if(_file != nullptr) {
_file->close();
delete _file;
_file = nullptr;
}
}
FMLogger *FMLogger::Instance()
{
static FMLogger logger;
return &logger;
}
QIODevice *FMLogger::getIODevice()
{
if(_file == nullptr) {
QString fileName = _NewFileName();
_file = new QFile(fileName);
qDebug() << "New File: " << fileName;
_file->open(QIODevice::Append);
}
return _file;
}
QString FMLogger::GetLogPath()
{
QString path = FMSetting::GetValue("LogPath", qApp->applicationDirPath()+"/log").toString();
path.replace("\\", "/");
QDir log_dir;
if (!log_dir.isAbsolutePath(path)) {
path = qApp->applicationDirPath() + "/" + path;
}
return path;
}
QString FMLogger::_NewFileName()
{
QString log_path = GetLogPath();
QDir log_dir(log_path);
if (!log_dir.exists()) {
if (log_dir.mkdir(log_path)) {
qDebug() << "Create log dir:" << log_path;
}
else {
qDebug() << "Create log dir" << log_path << "failed!";
}
}
QString fileName = log_path + "/" + qApp->applicationName() + "_" +QString::number(QDateTime::currentMSecsSinceEpoch()) + ".log";
return fileName;
}
#ifndef FMLOGGER_H
#define FMLOGGER_H
#include "fmp_logstream.h"
#include <QObject>
class QFile;
class FMLogger : public QObject
{
Q_OBJECT
public:
enum {
LOG_ERROR = 1, LOG_WARNING, LOG_INFO, LOG_DEBUG
};
static FMLogger *Instance();
QIODevice *getIODevice();
QString GetLogPath();
~FMLogger();
private:
explicit FMLogger(QObject *parent = 0);
QString _NewFileName();
QFile *_file;
};
#define FMLOG(level, ioDevice) ((ioDevice == nullptr) ? \
FMPNullLogStream(level, __FILE__, __FUNCTION__, __LINE__) :\
FMPLogStream(level, __FILE__, __FUNCTION__, __LINE__, ioDevice))
#define FM_DEBUG() FMLOG(FMLogger::LOG_DEBUG, FMLogger::Instance()->getIODevice())
#define FM_INFO() FMLOG(FMLogger::LOG_INFO, FMLogger::Instance()->getIODevice())
#define FM_WARN() FMLOG(FMLogger::LOG_WARNING, FMLogger::Instance()->getIODevice())
#define FM_ERROR() FMLOG(FMLogger::LOG_ERROR, FMLogger::Instance()->getIODevice())
#endif // FMLOGGER_H
#include "fmmsgwnd.h"
#include "ui_fmmsgwnd.h"
FMMsgWnd::FMMsgWnd(FMVipWnd *parent) :
FMVipWnd(parent),
ui(new Ui::FMMsgWnd)
{
ui->setupUi(this);
setAttribute(Qt::WA_TranslucentBackground);
}
FMMsgWnd::~FMMsgWnd()
{
delete ui;
}
void FMMsgWnd::show(InfoType type, const QString &info)
{
QString iconUrl;
switch (type) {
case InfoType::T_Normal:
iconUrl = "";
break;
case InfoType::T_Success:
iconUrl = ":/img/tip_ok.png";
break;
case InfoType::T_Failure:
iconUrl = ":/img/tip_error.png";
break;
case InfoType::T_Warning:
iconUrl = ":/img/tip_warning.png";
break;
default:
iconUrl = "";
break;
}
if(iconUrl != ""){
QPixmap icon(iconUrl);
ui->alertIconLab->setPixmap(icon);
}
ui->alertLabMsg->setText(info);
QDialog::exec();
}
void FMMsgWnd::FailureWnd(const QString &info)
{
FMMsgWnd window;
window.show(FMMsgWnd::T_Failure, info);
}
void FMMsgWnd::WarningWnd(const QString &info)
{
FMMsgWnd window;
window.show(FMMsgWnd::T_Warning, info);
}
void FMMsgWnd::SuccessWnd(const QString &info)
{
FMMsgWnd window;
window.show(FMMsgWnd::T_Success, info);
}
void FMMsgWnd::on_alertBtnOk_clicked()
{
this->close();
}
#ifndef FMMSGWND_H
#define FMMSGWND_H
#include "fmvipwnd.h"
namespace Ui {
class FMMsgWnd;
}
class FMMsgWnd : public FMVipWnd
{
Q_OBJECT
public:
explicit FMMsgWnd(FMVipWnd *parent = 0);
~FMMsgWnd();
enum InfoType
{
T_Normal,
T_Success,
T_Failure,
T_Warning
};
void show(InfoType type = T_Normal, const QString &info = "");
static void FailureWnd(const QString &info);
static void WarningWnd(const QString &info);
static void SuccessWnd(const QString &info);
private slots:
void on_alertBtnOk_clicked();
private:
Ui::FMMsgWnd *ui;
};
#endif // FMMSGWND_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FMMsgWnd</class>
<widget class="QWidget" name="FMMsgWnd">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>425</width>
<height>290</height>
</rect>
</property>
<property name="mouseTracking">
<bool>false</bool>
</property>
<property name="windowTitle">
<string>FMMsgwnd</string>
</property>
<property name="styleSheet">
<string notr="true">
#FMMsgWnd{
min-width: 425px; min-height: 290;
border-image:url(&quot;:/img/alert_bg.png&quot;);
background: transparent;
}
#alertIconLab
{
color: rgb(0, 0, 0);
font: normal 22px &quot;Microsoft YaHei&quot;;
margin-top: 20px;
}
#alertLabMsg
{
min-height: 110px;
color: rgb(129, 129, 129);
font: normal 19px &quot;Microsoft YaHei&quot;
}
#alertBtnOk
{
max-width: 180px; max-height: 45px;
color: rgb(255, 255, 255);
background-color: rgb(221, 88, 51);
border-radius: 3px;
font: normal 22px &quot;Microsoft YaHei&quot;
}
#alertBtnOk:pressed
{
color: rgb(161, 161, 161);
background-color: rgb(221, 88, 51);
border-radius: 3px;
}
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>20</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="alertIconLab">
<property name="text">
<string>Title</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignHCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="close_btn">
<property name="maximumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<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>
<widget class="QLabel" name="alertLabMsg">
<property name="minimumSize">
<size>
<width>350</width>
<height>110</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>350</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<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>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QPushButton" name="alertBtnOk">
<property name="text">
<string>关闭</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
#include "fmnetwork.h"
#include "fmlogger.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include <QTimer>
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;
FM_INFO() << "Send Url: " << url;
FM_INFO() << "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
#ifndef FMP_LOGGERSTREAM_H
#define FMP_LOGGERSTREAM_H
#include <QDebug>
#include <QDateTime>
class FMPLogStream : public QDebug
{
public:
enum {
ERROR = 1, WARNING, INFO, DEBUG
};
explicit FMPLogStream(short level, const char* file, const char* func, int line, QIODevice* d = 0)
: QDebug(d),
_level(level),
_file(file),
_func(func),
_line(line),
_device(d)
{
_lvmap[ERROR] = "[ERROR]";
_lvmap[WARNING] = "[WARNING]";
_lvmap[INFO] = "[INFO]";
_lvmap[DEBUG] = "[DEBUG]";
}
~FMPLogStream()
{
if (this->_device) {
QDebug::operator <<(endl);
}
}
template <typename T>
QDebug & operator<<(const T& t)
{
qDebug() << t;
QDebug & stream = *(this);
if (!_device) {
stream = qDebug();
}
QString extra;
if (_level != INFO) {
QString filename(_file);
filename = filename.section("\\", -1);
filename = filename.section("/", -1);
extra += QString("%1(%2)").arg(filename).arg(QString::number(_line));
extra += QString("%1:").arg(_func);
}
QString s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
s.append(_lvmap[_level]);
stream.noquote() << s << extra << t;
return stream;
}
protected:
int _level;
QMap<int, QString> _lvmap;
const char * _file;
const char * _func;
int _line;
QIODevice* _device;
};
class FMPNullLogStream : public FMPLogStream
{
public:
explicit FMPNullLogStream(short level, const char* file, const char* func, int line)
: FMPLogStream(level, file, func, line)
{}
};
#endif // FMP_LOGSTREAM_H
#include "fmsetting.h"
#include <QSettings>
#include <QApplication>
FMSetting::FMSetting()
{
_sets = new QSettings(qApp->applicationName()+".ini", QSettings::IniFormat);
_sets->setIniCodec("UTF-8");
}
FMSetting *FMSetting::Instance()
{
static FMSetting instance;
return &instance;
}
QVariant FMSetting::getValue(const QString &k, QVariant default_val)
{
return _sets->value(k, default_val);
}
bool FMSetting::setValue(const QString &k, QVariant v)
{
_sets->setValue(k, v);
return (_sets->value(k) == v);
}
QVariant FMSetting::GetValue(const QString &k, QVariant default_val)
{
return FMSetting::Instance()->getValue(k, default_val);
}
bool FMSetting::SetValue(const QString &k, QVariant v)
{
return FMSetting::Instance()->setValue(k, v);
}
#ifndef FMSETTING_H
#define FMSETTING_H
#include <QObject>
#include <QVariant>
class QSettings;
class FMSetting : public QObject
{
Q_OBJECT
public:
static FMSetting *Instance();
static QVariant GetValue(const QString &k, QVariant default_val);
static bool SetValue(const QString&k, QVariant v);
private:
explicit FMSetting();
QVariant getValue(const QString &k, QVariant default_val);
bool setValue(const QString&k, QVariant v);
QSettings *_sets;
signals:
public slots:
};
#endif // FMSETTING_H
#include "fmvip.h"
#include "fmlogger.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 reqObj;
reqObj["fm_cmd"] = "member_check_request";
reqObj["member_sign"] = vipNo;
reqObj["inner_code"] = innerCode;
reqObj["member_type"] = (int)memberType(vipNo);
sendToServer(reqObj, rspObj);
}
void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj)
{
QJsonObject reqObj;
reqObj["fm_cmd"] = "order_recharge_request";
reqObj["trans_id"] = createTransId("117017", "8888");
QJsonObject transObj;
transObj["account"] = fm_open_id;
transObj["amount"] = amount;
transObj["cash_amount"] = amount;
reqObj["transaction"] = transObj;
sendToServer(reqObj, rspObj);
}
void FMVip::reversal(const QString &fmId)
{
QJsonObject reqObj;
reqObj["fm_cmd"] = "order_correct_request";
reqObj["fm_id"] = fmId;
QJsonObject rspObj;
sendToServer(reqObj, rspObj);
}
void FMVip::sendToServer(QJsonObject &reqObj, QJsonObject &rspObj)
{
reqObj["appId"] = APP_ID;
reqObj["business_date"] = QDate::currentDate().toString("yyyyMMdd");
reqObj["t"] = QString::number(QDateTime::currentMSecsSinceEpoch());
reqObj["partner_id"] = PARTNER_ID;
reqObj["store_id"] = "117017";
reqObj["pos_id"] = "8888";
reqObj["operator_id"] = "8888";
QJsonDocument jsonDoc(reqObj);
QString signStr = sign(reqObj);
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))
{
FM_INFO() << "Server Response:" << QString::fromUtf8(rspData);
rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
rspObj = rspJsonDoc.object();
if(rspObj.contains("errcode")) {
rspObj["status_code"] = rspObj["errcode"];
rspObj["msg"] = rspObj["errmsg"];
}
} else {
rspObj["status_code"] = 101;
rspObj["msg"] = jsonError.errorString();
}
} else {
rspObj["status_code"] = 300;
rspObj["msg"] = error;
FM_ERROR() << "Network error: " << 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
{
// 解析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);
FM_INFO() << "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"
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);
void reversal(const QString &fmId);
private:
void sendToServer(QJsonObject &reqObj, QJsonObject &rspObj);
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 "fmvipwnd.h"
#include <QDesktopWidget>
#include <QPainter>
#include <QStyleOption>
#include <QJsonDocument>
#include <QKeyEvent>
#ifdef Q_OS_WIN
#include <windows.h>
#include <windowsx.h>
#endif
FMVipWnd::FMVipWnd(QDialog *parent) :
QDialog(parent),
loadingWindow(new FMLoading(this))
{
setWindowFlags(Qt::FramelessWindowHint/* | Qt::WindowStaysOnTopHint*/);
setAttribute(Qt::WA_TranslucentBackground);
// setAttribute(Qt::WA_QuitOnClose, false);
// setAttribute(Qt::WA_DeleteOnClose, false);
setIsBusy(false);
}
FMVipWnd::~FMVipWnd()
{
if(loadingWindow!=nullptr){
delete loadingWindow;
loadingWindow = nullptr;
}
}
void FMVipWnd::on_close_btn_clicked()
{
this->done(-1);
}
bool FMVipWnd::close()
{
if(loadingWindow != nullptr) {
loadingWindow->hide();
}
return QDialog::close();
}
void FMVipWnd::setIsBusy(const bool isBusy)
{
if(isBusy)
{
loadingWindow->show();
}else{
loadingWindow->hide();
}
}
int FMVipWnd::exec()
{
showFullScreen();
::SetForegroundWindow((HWND)effectiveWinId());
::SetWindowPos( (HWND)effectiveWinId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
showFullScreen();
::SetForegroundWindow((HWND)effectiveWinId());
QDesktopWidget w;
QRect rc = w.availableGeometry();
setGeometry((rc.width() - width()) / 2, (rc.height() - height()) / 2, width(), height());
return QDialog::exec();
}
void FMVipWnd::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Escape) {
on_close_btn_clicked();
} else {
QDialog::keyPressEvent(e);
}
}
#ifdef Q_OS_WIN
//! Gui class member of platform
bool FMVipWnd::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
MSG *msg = (MSG*)message;
//! true indicates the message need to be processed by DefWindowProc
bool fCallDWP = true;
bool fMsgDone = false;
switch (msg->message) {
case WM_NCHITTEST: {
*result = winNCHitTest(msg);
if (*result != HTNOWHERE) {
// HTMINBUTTON 等消息当作HTCLIENT处理
switch (*result) {
case HTMINBUTTON:
case HTMAXBUTTON:
case HTCLOSE:
*result = HTCLIENT;
break;
}
fCallDWP = false;
}
break;
}
case WM_GETMINMAXINFO: {
// 最大化时的处理
MINMAXINFO *mmi = (MINMAXINFO*) (msg->lParam);
QDesktopWidget desktopWidget;
QRect desktop = desktopWidget.availableGeometry();
mmi->ptMaxSize.x = desktop.width();
mmi->ptMaxSize.y = desktop.height();
mmi->ptMaxPosition.x = desktop.x();
mmi->ptMaxPosition.y = desktop.y();
mmi->ptMinTrackSize.x = minimumWidth(); // minimum width for your window
mmi->ptMinTrackSize.y = minimumHeight(); // minimum height for your window
mmi->ptMaxTrackSize.x = maximumWidth();
mmi->ptMaxTrackSize.y = maximumHeight();
*result = 0;
fMsgDone = true;
break;
}
default:
break;
}
fMsgDone = fMsgDone || !fCallDWP;
return fMsgDone;
}
void FMVipWnd::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
long FMVipWnd::winNCHitTest(MSG *msg)
{
// Mouse position
QPoint mouse_pos(GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam));
QRect window_rect = geometry();
// Set default value (HTNOWHERE) (1,1).
USHORT uRow = 1;
USHORT uCol = 1;
bool fOnResizeBorder = false;
//! Test caption area
QRegion m_children_region(0, 0, width() - 54, 60);
QRegion new_region = m_children_region.translated(window_rect.x() , window_rect.y());
if (new_region.contains(mouse_pos)) {
//! Title regions contains the mouse position, treat it as caption area
uRow = 0;
}
// Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT)
LRESULT hitTests[3][3] =
{
{ HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT },
{ HTLEFT, HTNOWHERE, HTRIGHT },
{ HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT },
};
//! Test borders area
if (minimumSize() != maximumSize()) {
//! To be implemented
}
return hitTests[uRow][uCol];
}
#endif
#ifndef FMVIPWND_H
#define FMVIPWND_H
#include <QDialog>
#include <QJsonObject>
#include <QMap>
#include <QDebug>
#include "fmloading.h"
class FMVipWnd : public QDialog
{
Q_OBJECT
public:
explicit FMVipWnd(QDialog *parent = 0);
~FMVipWnd();
void setIsBusy(const bool isBusy = true);
virtual void resetWnd(){this->setEnabled(true);}
int exec();
bool close();
public slots:
void on_close_btn_clicked();
private:
FMLoading* loadingWindow;
protected:
bool _isBusy;
void keyPressEvent(QKeyEvent *e);
#ifdef Q_OS_WIN
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
void paintEvent(QPaintEvent *event);
protected:
long winNCHitTest(MSG *msg);
#endif
};
#endif // FMVIPWND_H
#include "rechargewnd.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
RechargeWnd wnd;
wnd.show();
return a.exec();
}
#include "rechargewnd.h"
#include "ui_rechargewnd.h"
#include "fmsetting.h"
#include "cardreader.h"
#include "fmbackup.h"
#include "fmmsgwnd.h"
#include "fmvip.h"
#include <QDateTime>
#include <QJsonObject>
#include <QButtonGroup>
#include <QDebug>
RechargeWnd::RechargeWnd(QDialog *parent) :
FMVipWnd(parent),
ui(new Ui::RechargeWnd),
_cardReader(new CardReader(this)),
_fmvip(new FMVip(this))
{
ui->setupUi(this);
initUi();
initReader();
FMBackup::instance();
connect(_cardReader, &CardReader::hadVipNo, this, &RechargeWnd::onHadVipNo);
}
RechargeWnd::~RechargeWnd()
{
foreach (QAbstractButton *btn, _amountBtnGroup->buttons()) {
delete btn;
}
delete _amountBtnGroup;
_cardReader->Stop();
_cardReader->wait();
delete _cardReader;
delete ui;
}
void RechargeWnd::initUi()
{
_amountBtnGroup = new QButtonGroup(this);
connect(_amountBtnGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(onAmountBtnClicked(QAbstractButton*)));
QStringList amountList = FMSetting::GetValue("amounts", QStringList()).toStringList();
QGridLayout *amountLayout = (QGridLayout *)ui->amount->layout();
int row=0, col=0;
foreach (QString amount, amountList) {
QPushButton* btn = new QPushButton(this);
btn->setObjectName(amount);
btn->setText(amount + "元");
btn->setCheckable(true);
btn->setCursor(QCursor(Qt::PointingHandCursor));
_amountBtnGroup->addButton(btn);
amountLayout->addWidget(btn, row, col);
// 计算按钮位置
if(++col==2) {
row++;
col = 0;
}
}
}
void RechargeWnd::clearUi()
{
card_no = inner_no = _fm_open_id = "";
ui->card_label->setText("未知");
ui->max_recharge_label->setText("0.00");
ui->amount_label->setText("0.00");
ui->amount_edit->setText("0.00");
ui->recharge_info_label->clear();
foreach (QAbstractButton *btn, _amountBtnGroup->buttons()) {
btn->setEnabled(true);
btn->setChecked(false);
btn->setStyleSheet("background-color: rgb(0, 204, 102);");
}
}
void RechargeWnd::onAmountBtnClicked(QAbstractButton *button)
{
double digit = button->objectName().toDouble();
ui->amount_edit->setText(QString::number(digit, 'f', 2));
}
void RechargeWnd::initReader()
{
_cardReader->start();
connect(_cardReader, &CardReader::hadError, this, &RechargeWnd::onHadError);
}
void RechargeWnd::onHadError(const QString &error)
{
setIsBusy(false);
FMMsgWnd::FailureWnd(error);
}
void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid, bool isActived)
{
_fm_open_id = card_no = inner_no = "";
_needActived = !isActived;
clearUi();
setIsBusy(true);
QJsonObject job;
_fmvip->login(vipNo, uuid, job);
setIsBusy(false);
if(job["status_code"] != 100) {
FMMsgWnd::FailureWnd(job["msg"].toString());
_cardReader->ClearInfo();
} else {
card_no = vipNo;
inner_no = uuid;
ui->card_label->setText(vipNo);
double amount = job["amount"].toInt()/100.0;
ui->amount_label->setText(QString::number(amount, 'f', 2));
_fm_open_id = job["fm_unique_id"].toString();
double min_recharge = job["min_recharge_value"].toInt()/100.0;
double max_recharge = job["max_recharge_value"].toInt()/100.0;
QString max_recharge_str = QString::number(max_recharge, 'f', 2);
// 按钮金额不在范围内,设置为不可用
foreach (QAbstractButton *btn, _amountBtnGroup->buttons()) {
double digit = btn->objectName().toDouble();
if(digit < min_recharge || digit > max_recharge) {
btn->setEnabled(false);
btn->setStyleSheet("background-color: rgb(159, 159, 159);");
} else {
btn->setStyleSheet("background-color: rgb(0, 204, 102);");
}
}
if(min_recharge == max_recharge) {
ui->amount_edit->setText(max_recharge_str);
}
ui->max_recharge_label->setText(max_recharge_str);
}
}
void RechargeWnd::on_recharge_btn_clicked()
{
int recharge_amount = (int)ui->amount_edit->text().toDouble()*100;
setIsBusy(true);
QJsonObject job;
_fmvip->recharge(_fm_open_id, recharge_amount, job);
if(job["status_code"] == 100) {
double after_amount = job["after_value"].toInt()/100.0;
QString fm_id = job["fm_id"].toString();
QDateTime dateTime = QDateTime::currentDateTime();
// 备份
bool isSuccess = FMBackup::instance()->insert(card_no, inner_no,
recharge_amount/100, after_amount,
fm_id, dateTime.toString("yyyy-MM-dd"),
dateTime.toString("hh:mm:ss"));
if(!isSuccess) {
ui->recharge_info_label->setText(FMBackup::instance()->lastError());
}
// 激活
if(isSuccess && _needActived) {
isSuccess = _cardReader->ActiveCard(ui->card_label->text());
}
setIsBusy(false);
// 是否成功
if(isSuccess) {
_needActived = false;
QString after_amount_str = QString::number(after_amount, 'f', 2);
ui->amount_label->setText(after_amount_str);
ui->recharge_info_label->setText("充值成功!");
ui->amount_edit->setText("0.00");
_fm_open_id = card_no = inner_no = "";
} else {
// 硬件激活失败,发起冲正
_fmvip->reversal(job["fm_id"].toString());
}
} else {
setIsBusy(false);
ui->recharge_info_label->setText("充值失败:"+job["msg"].toString());
}
}
#ifndef RECHARGEWND_H
#define RECHARGEWND_H
#include "fmvipwnd.h"
class QButtonGroup;
class QAbstractButton;
class CardReader;
class FMVip;
namespace Ui {
class RechargeWnd;
}
class RechargeWnd : public FMVipWnd
{
Q_OBJECT
public:
explicit RechargeWnd(QDialog *parent = 0);
~RechargeWnd();
private:
Ui::RechargeWnd *ui;
QButtonGroup *_amountBtnGroup;
void initUi();
void clearUi();
void initReader();
CardReader *_cardReader;
FMVip *_fmvip;
bool _needActived;
QString card_no, inner_no, _fm_open_id;
private slots:
void onAmountBtnClicked(QAbstractButton* button);
void onHadError(const QString &error);
void onHadVipNo(const QString &vipNo, const QString &uuid, bool isActived);
void on_recharge_btn_clicked();
};
#endif // RECHARGEWND_H
<RCC>
<qresource prefix="/">
<file>img/btn_alert_close.png</file>
<file>img/btn_close.png</file>
<file>img/img_logo.png</file>
<file>img/loading.gif</file>
<file>img/img_logo_lxj.png</file>
<file>img/tip_error.png</file>
<file>img/tip_ok.png</file>
<file>img/tip_warning.png</file>
<file>img/alert_bg.png</file>
</qresource>
</RCC>
#include "fm_mwrf32.h"
#include "fm_mwrf32.h"
#include "mwdll/mwrf32.h"
#include <QCryptographicHash>
#include <QDebug>
#include <iostream>
#define OldSector 4
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,7 @@ 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());
qDebug() << "st: " << st << "pwd: " << password.toLatin1().data();
if(st!=0)
{
rf_exit(handle);
......@@ -36,6 +42,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 +51,36 @@ 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_halt(handle);
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,130 @@ 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);
// 读卡
char rdata[32];
ZeroMemory(rdata,32);
st = rf_read_hex(handle, OldSector*4, rdata);
if(st!=0)
{
error = "read default card no error";
return false;
}
vipNo = QByteArray(rdata).mid(16);
// 将卡号写入传入的扇区
// 鉴权
st = rf_authentication(handle, 0, sector);
if(st!=0)
{
error = "read data error";
error = "check password failure";
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());
// 写入卡号
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_halt(handle);
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_halt(handle);
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 4
#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