Skip to content

Commit

Permalink
💥 Happy New Year 2023!
Browse files Browse the repository at this point in the history
Initial commit
  • Loading branch information
Matrixchung committed Dec 31, 2022
1 parent f7ac0bf commit 493272f
Show file tree
Hide file tree
Showing 8 changed files with 465 additions and 0 deletions.
71 changes: 71 additions & 0 deletions examples/Serial_register/Serial_register.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "sfm.hpp"

#define SFM_RX 19
#define SFM_TX 18
#define SFM_IRQ 17
#define SFM_VCC 15

SFM_Module SFM(SFM_VCC, SFM_IRQ, SFM_TX, SFM_RX);

bool lastTouchState = 0;

void sfmPinInt1() {
SFM.pinInterrupt();
}

void setup() {
SFM.setPinInterrupt(sfmPinInt1); // must perform this step in setup() to attach the inner interrupt.
Serial.begin(115200); // not affiliated with module
}

uint8_t temp = 0; // used to get recognition return
uint16_t tempUid = 0; // used to get recognized uid

void loop() {
if(SFM.isTouched() != lastTouchState) { // Make sure the action just performed once when touch state changes
lastTouchState = SFM.isTouched();
if(SFM.isTouched()) {
SFM.setRingColor(SFM_RING_RED, SFM_RING_OFF); // Ring fade from red to black at default period (500ms), creating a breathe effect
// Here we are going to start recognition, if unlocked, we will change the ring color to green and send a message
temp = SFM.recognition_1vN(tempUid);
if(tempUid != 0) {
SFM.setRingColor(SFM_RING_GREEN);
Serial.printf("Successfully matched with UID: %d", tempUid);
}
}
else {
SFM.setRingColor(SFM_RING_OFF);
}
}
if(Serial.available()) { // sending any character to start register
Serial.println("Start register..");
SFM.setRingColor(SFM_RING_YELLOW, SFM_RING_OFF);
Serial.println("Please put your finger");
temp = SFM.register_3c3r_1st();
if(temp==SFM_ACK_SUCCESS){
Serial.println("Please releases your finger");
delay(2000);
SFM.setRingColor(SFM_RING_PURPLE, SFM_RING_OFF);
Serial.println("Please put your finger");
temp = SFM.register_3c3r_2nd();
if(temp==SFM_ACK_SUCCESS){
Serial.println("Please releases your finger");
delay(2000);
SFM.setRingColor(SFM_RING_BLUE, SFM_RING_OFF);
Serial.println("Please put your finger");
tempUid = 0;
temp = SFM.register_3c3r_3rd(tempUid);
if(temp==SFM_ACK_SUCCESS&&tempUid!=0){
Serial.printf("Register successful with return UID: %d\n", tempUid);
SFM.setRingColor(SFM_RING_GREEN);
}
else{
Serial.println("Register failed, please re-submit the register command");
SFM.setRingColor(SFM_RING_RED);
}
}
else Serial.println("Error in register step #2");
}
else Serial.println("Error in register step #1");
}
}
40 changes: 40 additions & 0 deletions examples/Touch_and_unlock/Touch_and_unlock.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "sfm.hpp"

#define SFM_RX 19
#define SFM_TX 18
#define SFM_IRQ 17
#define SFM_VCC 15

SFM_Module SFM(SFM_VCC, SFM_IRQ, SFM_TX, SFM_RX);

bool lastTouchState = 0;

void sfmPinInt1() {
SFM.pinInterrupt();
}

void setup() {
SFM.setPinInterrupt(sfmPinInt1); // must perform this step in setup() to attach the inner interrupt.
Serial.begin(115200); // not affiliated with module, just print unlock result.
}

uint8_t temp = 0; // used to get recognition return
uint16_t tempUid = 0; // used to get recognized uid

void loop() {
if(SFM.isTouched() != lastTouchState) { // Make sure the action just performed once when touch state changes
lastTouchState = SFM.isTouched();
if(SFM.isTouched()) {
SFM.setRingColor(SFM_RING_RED, SFM_RING_OFF); // Ring fade from red to black at default period (500ms), creating a breathe effect
// Here we are going to start recognition, if unlocked, we will change the ring color to green and send a message
temp = SFM.recognition_1vN(tempUid);
if(tempUid != 0) {
SFM.setRingColor(SFM_RING_GREEN);
Serial.printf("Successfully matched with UID: %d", tempUid);
}
}
else {
SFM.setRingColor(SFM_RING_OFF);
}
}
}
Binary file not shown.
Binary file added extras/SFM-V1.7 Datasheet (Chinese).pdf
Binary file not shown.
23 changes: 23 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Datatypes (KEYWORD1)
SFM_Module KEYWORD1

# Methods and Functions (KEYWORD2)

enable KEYWORD2
disable KEYWORD2
setPinInterrupt KEYWORD2
pinInterrupt KEYWORD2
isTouched KEYWORD2
isConnected KEYWORD2
getUserCount KEYWORD2
getUuid KEYWORD2
sendCmd KEYWORD2
setRingColor KEYWORD2
register_3c3r_1st KEYWORD2
register_3c3r_2nd KEYWORD2
register_3c3r_3rd KEYWORD2
deleteUser KEYWORD2
deleteAllUser KEYWORD2
recognition_1v1 KEYWORD2
recognition_1vN KEYWORD2
stopAll KEYWORD2
9 changes: 9 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=SFM-V1.7
version=1.0.0
author=Matrixchung
maintainer=Matrixchung <vip99013zhq@outlook.com>
sentence=Interfacing to the SFM-V1.7 Fingerprint Sensor
paragraph=Enables full control for SFM-V1.7, a fingerprint sensor which is famous in Chinese market
category=Sensors, Device Control
url=https://github.com/Matrixchung/SFM-V1.7
architectures=*
239 changes: 239 additions & 0 deletions src/sfm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/*!
* @file sfm.cpp
* @author Matrixchung
*/
#include "sfm.hpp"
char hex_char[17] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/*!
@brief Constructor for SFM-V1.7 Module
@param vccPin
Pin number for VCC
@param irqPin
Pin number for TOUCH_OUT
@param rxPin
Pin number for UART_TX
@param txPin
Pin number for UART_RX
@param uartIndex
HardwareSerial uart_nr, default 1 means UART 1 (UART 0 is preconfigured and can't be used)
@return SFM_Module object
@note Remember to call SFM_Module::setPinInterrupt() before loop()! (see example for more information)
*/
SFM_Module::SFM_Module(uint8_t vccPin, uint8_t irqPin, uint8_t rxPin, uint8_t txPin, uint8_t uartIndex):sfmSerial(uartIndex), vcc_pin(vccPin), irq_pin(irqPin), rx_pin(rxPin), tx_pin(txPin){
pinMode(irq_pin, INPUT_PULLDOWN);
pinMode(vcc_pin, OUTPUT);
pinMode(rx_pin, OUTPUT);
pinMode(tx_pin, OUTPUT);
digitalWrite(vcc_pin, HIGH); // Enable sensor vcc
cmdBuffer[0] = 0xF5;
cmdBuffer[7] = 0xF5;
sfmSerial.begin(115200, SERIAL_8N1, rx_pin, tx_pin);
}
SFM_Module::~SFM_Module(){
detachInterrupt(irq_pin);
}
/*!
@brief Set outside ring's LED color
@param startColor
LED's start color. Only SFM_RING_XXX can be chosen.
@param endColor
LED's end color. Only SFM_RING_XXX can be chosen.
@param period
LED will fade from startColor to endColor in given period. Measured in ms. range: 300-2000
@return SFM_ACK_XXX
*/
uint8_t SFM_Module::setRingColor(uint8_t startColor, int8_t endColor, uint16_t period){
uint8_t ackType, q1, q2, q3;
period /= 10;
period = constrain(period, 30, 200);
if(endColor == -1) endColor = startColor;
return _getCmdReturn(0xC3, startColor, endColor, period);
}
/*!
@brief 3C3R Register step #1
@param uid
Specify the UID you want to add a new user. Default 0 means add to the end
@return SFM_ACK_XXX
@note Please check example for how to register using 3C3R method.
*/
uint8_t SFM_Module::register_3c3r_1st(uint16_t uid){
return _getCmdReturn(0x01, uid >> 8, uid << 8, SFM_DEFAULT_USERROLE);
}
/*!
@brief 3C3R Register step #2
@return SFM_ACK_XXX
@note It must be called after SFM_Module::register_3c3r_1st() is successful, otherwise restart from #1
*/
uint8_t SFM_Module::register_3c3r_2nd(){
return _getCmdReturn(0x02);
}
/*!
@brief 3C3R Register step #3
@param &returnUid
Get the registered uid if success, else 0
@return SFM_ACK_XXX
@note It must be called after step #1 and #2 with both of them successful, otherwise you need to re-register from step #1
*/
uint8_t SFM_Module::register_3c3r_3rd(uint16_t &returnUid){
uint8_t ackType, q1, q2, q3;
q3 = sendCmd(0x03, 0x00, 0x00, 0x00, ackType, q1, q2);
if(ackType == 0x03 && q3 == SFM_ACK_SUCCESS){
returnUid = (q1 << 8) | q2;
return SFM_ACK_SUCCESS;
}
returnUid = 0;
return SFM_ACK_FAIL;
}
/*!
@brief Delete specific user by uid
@param uid
UID which is going to be deleted
@return SFM_ACK_XXX
*/
uint8_t SFM_Module::deleteUser(uint16_t uid){
return _getCmdReturn(0x04, uid >> 8, uid << 8);
}
/*!
@brief Delete ALL user(s)
@return SFM_ACK_XXX
*/
uint8_t SFM_Module::deleteAllUser(){
return _getCmdReturn(0x05);
}
/*!
@brief Match current fingerprint with specific uid
@param uid
Target uid
@return SFM_ACK_SUCCESS if matched
*/
uint8_t SFM_Module::recognition_1v1(uint16_t uid){
return _getCmdReturn(0x0B, uid >> 8, uid << 8);
}
/*!
@brief Search the database and find matched uid
@param &returnUid
Matched uid (0 if not matched)
@return SFM_ACK_SUCCESS if matched
*/
uint8_t SFM_Module::recognition_1vN(uint16_t &returnUid){
uint8_t ackType, q1, q2, q3;
q3 = sendCmd(0x0C, 0x00, 0x00, 0x00, ackType, q1, q2);
if(ackType == 0x0C){
returnUid = (q1 << 8) | q2;
return returnUid == 0 ? SFM_ACK_FAIL : SFM_ACK_SUCCESS;
}
return SFM_ACK_FAIL;
}
/*!
@brief Stop all current actions
@return SFM_ACK_SUCCESS if successfully stopped
SFM_ACK_IDLE if module is idle
SFM_ACK_FAIL if failed
*/
uint8_t SFM_Module::stopAll(){
uint8_t ackType, q1, q2, q3;
q3 = sendCmd(0xFE, 0x00, 0x00, 0x00, ackType, q1, q2);
if(ackType == 0x0C) return q3;
if(ackType == 0xFE && q3 == SFM_ACK_FAIL) return SFM_ACK_IDLE;
return SFM_ACK_FAIL;
}
/*!
@brief Get the module's UUID
@return 18-character hex string
*/
String SFM_Module::getUuid(){
return (_getCmdReturn(0x60) == SFM_ACK_SUCCESS && _getDataPackage(uuid) == SFM_ACK_SUCCESS) ? uuid : "";
}
/*!
@brief Get user count in database
@return user count
*/
uint16_t SFM_Module::getUserCount(){
uint8_t ackType, q1, q2, q3;
q3 = sendCmd(0x09, 0x00, 0x00, 0x00, ackType, q1, q2);
if(ackType == 0x09 && q3 == SFM_ACK_SUCCESS) userCount = (q1 << 8) | q2;
else userCount = 0;
return userCount;
}
uint8_t SFM_Module::sendCmd(uint8_t cmdType, uint8_t p1, uint8_t p2, uint8_t p3, uint8_t &ackType, uint8_t &q1, uint8_t &q2){
while(sfmSerial.available()) sfmSerial.read(); // flush rx buffer
cmdBuffer[1] = cmdType;
cmdBuffer[2] = p1;
cmdBuffer[3] = p2;
cmdBuffer[4] = p3;
cmdBuffer[6] = _getCheckSum(cmdBuffer);
sfmSerial.write(cmdBuffer, 8);
sfmSerial.flush(); // waiting for send complete
unsigned int timer = SFM_SERIAL_TIMEOUT;
while(timer--){
if(sfmSerial.available() >= 8){
while(sfmSerial.peek() != 0xF5) sfmSerial.read(); // trim the cache to find first 0xF5 (ack start)
if(sfmSerial.available() >= 8){ // more than 8 bytes since the first 0xF5
sfmSerial.readBytes(ackBuffer, 8);
if(ackBuffer[6] == _getCheckSum(ackBuffer)){ // checksum matched, exit without flush buffer
ackType = ackBuffer[1];
q1 = ackBuffer[2];
q2 = ackBuffer[3];
return ackBuffer[4]; // return q3 as SFM_ACK
}
else return SFM_ACK_FAIL;
}
}
delay(1);
}
while(sfmSerial.available()) sfmSerial.read(); // flush buffer
return SFM_ACK_SERIALTIMEOUT;
}
void SFM_Module::setPinInterrupt(void (*pinInt)(void)){
attachInterrupt(digitalPinToInterrupt(irq_pin), pinInt, CHANGE);
}
void IRAM_ATTR SFM_Module::pinInterrupt(){
touched = digitalRead(irq_pin);
}
bool SFM_Module::isTouched(){
return touched;
}
bool SFM_Module::isConnected(){
getUuid();
return uuid.length() == 18;
}
void SFM_Module::enable(){
digitalWrite(vcc_pin, HIGH);
}
void SFM_Module::disable(){
digitalWrite(vcc_pin, LOW);
}
// result = xor checksum buffer[1:5]
uint8_t SFM_Module::_getCheckSum(uint8_t *buffer){
uint8_t result = 0x00;
for(uint8_t i = 1; i <= 5; i++) result^=(*(buffer+i));
return result;
}
// get all bytes between two 0xF5 and convert to hex
uint8_t SFM_Module::_getDataPackage(String &package){
package = "";
char temp = '\0';
unsigned int timer = SFM_SERIAL_TIMEOUT;
while(timer--){
if(sfmSerial.available() > 0){
while(sfmSerial.read() != 0xF5); // trim the cache to find first 0xF5 and ignore it
while(sfmSerial.peek() != 0xF5){
// byte to hex char
temp = sfmSerial.read();
package += hex_char[temp / 16];
package += hex_char[temp % 16];
}
if(package.length() > 0) return SFM_ACK_SUCCESS;
}
delay(1);
}
while(sfmSerial.available()) sfmSerial.read(); // flush buffer
package = "";
return SFM_ACK_SERIALTIMEOUT;
}
uint8_t SFM_Module::_getCmdReturn(uint8_t cmdType, uint8_t p1, uint8_t p2, uint8_t p3){
uint8_t ackType, q1, q2, q3;
q3 = sendCmd(cmdType, p1, p2, p3, ackType, q1, q2);
if(ackType == cmdType) return q3;
return SFM_ACK_FAIL;
}
Loading

0 comments on commit 493272f

Please sign in to comment.