2018/3/13
- 星期二晚上到货
- 取开发资料
- 浏览用户手册
2018/3/14
- 根据用户手册进行模块接线
- 接入串口,利用开发包中的上位机对指纹模块进行操作
- 用串口调试软件,输入相应的指令,进行指纹采集等操作,但进行相应的操作总是无法实现
- 原因:对原有指令进行了改造,而校验码并没有改变
对上位机软件进行改造,使其输出相应操作流程的指令
在OEMHostDlg.cpp中查找对应的按钮执行的内容
1.找到void COEMHostDlg::OnBtnVerify()
void COEMHostDlg::OnBtnVerify()
{
int w_nRet, w_nTmplNo, w_nFpStatus, w_nLearned;
DWORD w_dwTime;
CString w_strTmp;
UpdateData(TRUE);
if (!CheckUserID())
return;
EnableControl(FALSE);
GetDlgItem(IDC_BTN_DISCONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_STOP)->EnableWindow(TRUE);
m_bCancel = FALSE;
w_nTmplNo = m_nUserID;
//. Check if fp is exist
w_nRet = m_clsCommu.Run_GetStatus(w_nTmplNo, &w_nFpStatus);
if( w_nRet != ERR_SUCCESS )
{
m_strCmdResult = GetErrorMsg(w_nRet);
goto l_exit;
}
if( w_nRet == ERR_SUCCESS && w_nFpStatus == GD_TEMPLATE_EMPTY )
{
m_strCmdResult = _T("Template is empty");
goto l_exit;
}
m_clsCommu.Run_SLEDControl(1);
m_strCmdResult = _T("Input your finger.");
UpdateData(FALSE);
w_dwTime = GetTickCount();
//. Get Image
while (1)
{
DoEvents();
if(m_bCancel)
{
m_strCmdResult = _T("Operation Canceled");
goto l_exit;
}
//. Get Image
w_nRet = m_clsCommu.Run_GetImage();
if(w_nRet == ERR_SUCCESS)
break;
else if(w_nRet == ERR_CONNECTION)
{
m_strCmdResult = GetErrorMsg(w_nRet);
goto l_exit;
}
}
m_strCmdResult = "Release your finger";
UpdateData(FALSE);
DoEvents();
//. Up Image
if (m_chkShowImage.GetCheck())
{
m_strCmdResult = _T("Uploading image...");
UpdateData(FALSE);
DoEvents();
w_nRet = m_clsCommu.Run_UpImage(0, g_FpImageBuf, &g_nImageWidth, &g_nImageHeight);
if(w_nRet != ERR_SUCCESS)
{
m_strCmdResult = GetErrorMsg(w_nRet);
goto l_exit;
}
m_wndFinger.SetImage(g_FpImageBuf, g_nImageWidth, g_nImageHeight);
m_strCmdResult = _T("Uploading image is successed.");
UpdateData(FALSE);
DoEvents();
}
w_dwTime = GetTickCount();
//. Create Template
w_nRet = m_clsCommu.Run_Generate(0);
if (w_nRet != ERR_SUCCESS)
{
m_strCmdResult = GetErrorMsg(w_nRet);
goto l_exit;
}
//. Verify
w_nRet = m_clsCommu.Run_Verify(w_nTmplNo, 0, &w_nLearned);
w_dwTime = GetTickCount() - w_dwTime;
if (w_nRet == ERR_SUCCESS)
{
m_strCmdResult.Format(_T("Result : Success\r\nTemplate No : %d, Learn Result : %d\r\nMatch Time : %dms"), w_nTmplNo, w_nLearned, w_dwTime );
}
else
{
m_strCmdResult = GetErrorMsg(w_nRet);
}
l_exit:
m_clsCommu.Run_SLEDControl(0);
UpdateData(FALSE);
EnableControl(TRUE);
GetDlgItem(IDC_BTN_DISCONNECT)->EnableWindow(TRUE);
}
2.查看m_clsCommu.Run_SLEDControl(0),跳转到Communication.cpp
int CCommunication::Run_SLEDControl(int p_nState)
{
BOOL w_bRet;
BYTE w_abyData[2];
w_abyData[0] = LOBYTE(p_nState);
w_abyData[1] = HIBYTE(p_nState);
InitCmdPacket(CMD_SLED_CTRL, m_bySrcDeviceID, m_byDstDeviceID, (BYTE*)&w_abyData, 2);
SEND_COMMAND(CMD_SLED_CTRL, w_bRet, m_bySrcDeviceID, m_byDstDeviceID);
if(!w_bRet)
return ERR_CONNECTION;
return RESPONSE_RET;
}
3.查看SEND_COMMAND定义,跳转到Command.cpp
BOOL SendCommand(WORD p_wCMDCode, BYTE p_bySrcDeviceID, BYTE p_byDstDeviceID)
{
DWORD w_nSendCnt = 0;
LONG w_nResult = 0;
g_Serial.Purge();
::SendMessage(g_hMainWnd, WM_CMD_PACKET_HOOK, 0, 0);
w_nResult = g_Serial.Write(g_Packet, g_dwPacketSize , &w_nSendCnt, NULL, COMM_TIMEOUT);
if(ERROR_SUCCESS != w_nResult)
{
return FALSE;
}
return ReceiveAck(p_wCMDCode, p_bySrcDeviceID, p_byDstDeviceID);
}
4.可以看到串口输出函数g_Serial.Write,g_packet应该为输出的内容,现在要做的就是将g_packet打印出来
5.顺势根据return ReceiveAck(p_wCMDCode, p_bySrcDeviceID, p_byDstDeviceID)
语句找到ReceiveAck函数,分析可知发送了消息通过ReceiveAck函数接收响应内容,则在此也添加Print_gPacket(false)以打印接收的内容
BOOL ReceiveAck(WORD p_wCMDCode, BYTE p_bySrcDeviceID, BYTE p_byDstDeviceID)
{
Print_gPacket(true);
DWORD w_nAckCnt = 0;
LONG w_nResult = 0;
DWORD w_dwTimeOut = COMM_TIMEOUT;
if (p_wCMDCode == CMD_TEST_CONNECTION)
w_dwTimeOut = 2000;
else if (p_wCMDCode == CMD_ADJUST_SENSOR)
w_dwTimeOut = 30000;
l_read_packet:
//w_nResult = g_Serial.Read(g_Packet, sizeof(ST_RCM_PACKET), &w_nAckCnt, NULL, w_dwTimeOut);
if (!ReadDataN(g_Packet, sizeof(ST_RCM_PACKET), w_dwTimeOut))
{
return FALSE;
}
g_dwPacketSize = sizeof(ST_RCM_PACKET);
::SendMessage(g_hMainWnd, WM_RCM_PACKET_HOOK, 0, 0);
if (!CheckReceive(g_Packet, sizeof(ST_RCM_PACKET), RCM_PREFIX_CODE, p_wCMDCode))
return FALSE;
if (g_pCmdPacket->m_byDstDeviceID != p_bySrcDeviceID)
{
goto l_read_packet;
}
Print_gPacket(false);
return TRUE;
}
6.由于该软件为mfc程序,所以在command添加如下代码,在输出的debug内容中显示相应的内容
#include "windows.h"
#ifdef _DEBUG
#define DP0(fmt) {TCHAR sOut[256];_stprintf_s(sOut,_T(fmt));OutputDebugString(sOut);}
#define DP1(fmt,var) {TCHAR sOut[256];_stprintf_s(sOut,_T(fmt),var);OutputDebugString(sOut);}
#define DP2(fmt,var1,var2) {TCHAR sOut[256];_stprintf_s(sOut,_T(fmt),var1,var2);OutputDebugString(sOut);}
#define DP3(fmt,var1,var2,var3) {TCHAR sOut[256];_stprintf_s(sOut,_T(fmt),var1,var2,var3);OutputDebugString(sOut);}
#endif
7.添加一个函数,用于打印g_packet,
/******************************
create by Jacky 2018/3/14
To print command
type true for send
false for recive
*******************************/
void Print_gPacket(bool type) {
if (type) {
DP0("发送的数据:");
}
else {
DP0("接收的数据:");
}
for (int i = 0; i < 26; i++) {
DP1("%02x", g_Packet[i]);
}
DP0("\n");
}
- 总结出采集验证指纹的过程总共有以下几条指令
*****************************
* 指纹模块一次指纹比对
* host命令
*****************************
// 采集指纹
55aa000020000000000000000000000000000000000000001f01
// 模板生成到rambuffer0
55aa000060000200000000000000000000000000000000006101
// 1:N对比
55aa00006300060000000100f401000000000000000000005e02
// 关灯
55aa000024000200000000000000000000000000000000002501
2018/3/15
- 由于esp8266与指纹模块通讯的过程中串口的数据交换并不可见,所以想到透传
- 上午上完课回来,进行透传程序Transmission的编写
#include <ESP8266WiFi.h>
const char *ssid = "";
const char *password = "";
const int tcpPort = 80;//要建立的TCP服务的端口号
WiFiServer server(tcpPort);
void setup()
{
Serial.begin(115200);
delay(10);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop()
{
WiFiClient client = server.available();
if (client) {
while (client.connected()) {
/*while (client.available()) {
char c = client.read();
Serial.write(c);
}*/
if(client.available()){
size_t counti=client.available();
uint8_t *buf=new uint8_t[counti];
Serial.write((const uint8_t*)buf,counti);
delete(buf);
}
delay(1000); //由于指纹模块是首先发送响应头再发响应数据,若不加这句,响应数据会分两次读取
if (Serial.available())
{
size_t counti = Serial.available();
uint8_t *sbuf = new uint8_t[counti];
Serial.readBytes(sbuf, counti);
client.write((const uint8_t*)sbuf, counti);
delete(sbuf);
}
}
client.stop();
}
}
- 注:
- 1.有坑,请看注释
- 2.遇到下列报错:
Compiling debug version of 'Transmission' for 'NodeMCU 1.0 (ESP-12E Module)'
Error compiling project sources
Debug build failed for project 'Transmission'
ESP8266WiFi.h:39: In file included from
Transmission.ino: from
WiFiClient.h: In instantiation of size_t WiFiClient::write(T&, size_t) [with T = unsigned char*; size_t = unsigned int]
Transmission.ino:60: required from here
WiFiClient.h: 123:36: error: request for member 'available' in 'source', which is of non-class type 'unsigned char*
size_t left = source.available()
WiFiClient.h: 127:5: error: request for member 'read' in 'source', which is of non-class type 'unsigned char*
source.read(buffer.get(), will_send)
原因是client的write函数必须传入一个buffer,但是通过网上查找解决方案,发现在第一个参数前加上(const uint8_t*)进行强制转换也可以编译通过
2018/3/16
透传实现了,那么就开始改造原有的mySmartLock.ino,首先第一版的程序构思为:
循环 * 1.读取指纹模块的手指感应信号(有信号就逐条发送指纹验证指令) * 2.读取网络端是否传来请求(有就判断请求url是否包含指定的字符串) * 3.读取透传客户端是否已连接(若已连接且传入debug()就更改标志,(考虑到指令录指纹时会造成录指纹和验证指纹指令的冲突)停止1的指纹验证,并允许串口穿透输入与输出,若为exit()就修改标志,重新启用1的指纹验证,只输出串口通讯的信息)
第一版的编程实现,采用的串行处理模式
- 坑1:在判断串口传入数据是否为debug()或exit()的过程中,用到了strcmp()函数,但是貌似读取出来的unsigned char*类型的字节流是不带结束符的而”debug()“是带结束符的长度为8的char数组,所以一直判断不等,经过查阅资料,发现还有一个函数就是strncmp()可以进行一定长度字符串的比较,所以改用
strncmp((const char*)command, "debug()", counti)
语句进行判断,经测试完全可行!!
但是问题来了,在arduino的loop()函数中,是循环执行的,当透传客户端连接上之后,除非用while (client.connected())
语句进行连接的保持,否则当前的transclient实例会在一次循环后被销毁,但是若保持连接又无法输出当前指纹模块与esp8266的通讯交互信息
发现还是程序的状态图没分清楚,构思总结出改进的三个状态
- 1.透传连接,并通过debug()进入debug模式
- 2.透传连接,保持默认状态,或在debug模式下通过exit()退出调试模式的,就只输出esp8266与指纹通讯的信息
- 3.串口没有连接,esp8266与指纹模块正常通讯
编程实现
- 1.将指纹验证和读取网络请求两部分封装成loopBody(bool modeSwitch)
- 2.用modeSwitch标记是否进入了debug模式,通过判断modeSwitch来判断是否进行透传输出,modeSwitch通过是否传入debug()和exit()命令进行切换
- 3.在transclient可用时进入while(client.connected())的循环,可以进行回话的保持,返回当前串口通讯的数据
- 4.源码见github