1+ /*
2+ *---------------------------------------------------------------------------------
3+ *
4+ * Copyright (c) 2025, SparkFun Electronics Inc.
5+ *
6+ * SPDX-License-Identifier: MIT
7+ *
8+ *---------------------------------------------------------------------------------
9+ */
10+
11+ /*
12+ * Example using the SparkFun FPC2534 Fingerprint sensor library to demonstrate the configuration
13+ * capabilities of the sensor. The example retrieves the current system configuration from the sensor,
14+ * modifies one of the configuration values, and sends the updated configuration back to the sensor.
15+ *
16+ * NOTE: Currently, the set of the updated values fails.
17+ *
18+ * This version of this example uses the SPI interface to communicate with the sensor.
19+ *
20+ *---------------------------------------------------------------------------------
21+ */
22+
23+ #include < Arduino.h>
24+
25+ #include " SparkFun_FPC2534.h"
26+
27+ // ----------------------------------------------------------------------------
28+ // User Config -
29+ // ----------------------------------------------------------------------------
30+ // Define the pins being used for operation
31+ //
32+ // The FPC2534 uses one pin for reset, No interrupt pin is needed for UART operation
33+ //
34+ // The following pin definitions were used for testing - but can be modified as needed.
35+ //
36+ // ESP32 thing plus
37+ // #define RST_PIN 21
38+
39+ // ESP32 thing plus C
40+ // #define RST_PIN 14
41+
42+ // RP2350 thing plus
43+ #define RST_PIN 12
44+
45+ // IoT RedBoard - RP2350
46+ // #define RST_PIN 29
47+
48+ // ----------------------------------------------------------------------------------
49+ // NOTE:
50+ // This example makes use of the Serial1 hardware serial port for communication with the FPC2534. If the board
51+ // being used does not have a Serial1 port, you will need to modify the code to use SoftwareSerial or another
52+ // serial port available on your board.
53+
54+ // Declare our sensor object. Note the SPI version of the sensor class is used.
55+ SfeFPC2534UART mySensor;
56+
57+ // flag used to indicate if config has been set....
58+ #define CONFIG_BEGIN 0
59+ #define CONFIG_REQUESTED 1
60+ #define CONFIG_RECEIVED 2
61+ #define CONFIG_SET 3
62+ #define CONFIG_VERIFY 4
63+ #define CONFIG_RESET 5
64+ #define CONFIG_COMPLETE 6
65+ #define CONFIG_EXIT 255
66+
67+ uint8_t configState = CONFIG_BEGIN;
68+
69+ fpc_system_config_t the_config = {0 };
70+ bool deviceIdle = false ;
71+ // ------------------------------------------------------------------------------------
72+ // Callback functions the library calls
73+ // ------------------------------------------------------------------------------------
74+
75+ // ----------------------------------------------------------------------------
76+ // on_error()
77+ //
78+ // Called if the sensor library detects/encounters an error
79+ //
80+ static void on_error (uint16_t error)
81+ {
82+ Serial.print (" [ERROR]\t Sensor Error Code: " );
83+ Serial.println (error);
84+
85+ // this could indicated the sensor communications is out of synch - a reset might be needed
86+ reset_sensor ();
87+ }
88+
89+ // ----------------------------------------------------------------------------
90+ // on_is_ready_change()
91+ //
92+ // Called when the device ready state changes
93+ //
94+ static void on_is_ready_change (bool isReady)
95+ {
96+ // On startup the device isn't immediately ready. A message is sent when it is.
97+ // The Library will call this function when that happens
98+
99+ if (isReady)
100+ {
101+ Serial.println (" [STARTUP]\t FPC2534 Device is ready" );
102+
103+ Serial.println (" [INFO]\t\t Requesting system configuration..." );
104+ // Request the configuration from the connected device.
105+ fpc_result_t rc = mySensor.requestGetSystemConfig (FPC_SYS_CFG_TYPE_DEFAULT);
106+ if (rc != FPC_RESULT_OK)
107+ {
108+ Serial.print (" [ERROR]\t Get config request failed - error: " );
109+ Serial.println (rc);
110+ }
111+ else
112+ configState = CONFIG_REQUESTED;
113+ }
114+ }
115+
116+ // ----------------------------------------------------------------------------
117+ // on_status()
118+ //
119+ // Called when the sensor sends a status message
120+ //
121+ static void on_status (uint16_t event, uint16_t state)
122+ {
123+ deviceIdle = (event == EVENT_IDLE);
124+ }
125+
126+ // ----------------------------------------------------------------------------
127+ static void update_config (fpc_system_config_t &new_config)
128+ {
129+ // The current values haven't been received yet
130+ if (configState < CONFIG_RECEIVED)
131+ return ;
132+
133+ fpc_result_t rc = mySensor.setSystemConfig (&new_config);
134+ if (rc != FPC_RESULT_OK)
135+ {
136+ Serial.print (" [ERROR]\t Set config request failed - error: " );
137+ Serial.println (rc);
138+ }
139+ }
140+ // ----------------------------------------------------------------------------
141+ static void update_config_max_fails (uint8_t max_fails)
142+ {
143+ // The current values haven't been received yet
144+ if (configState < CONFIG_RECEIVED)
145+ return ;
146+ // copy over the current defaults
147+ fpc_system_config_t new_config = the_config;
148+
149+ // update the value of max consecutive fails
150+ new_config.idfy_max_consecutive_fails = max_fails;
151+
152+ Serial.println ();
153+ delay (500 );
154+ Serial.print (" [INFO]\t\t Setting Max Fails To: " );
155+
156+ Serial.println (new_config.idfy_max_consecutive_fails );
157+
158+ update_config (new_config);
159+ }
160+ // ----------------------------------------------------------------------------
161+ static void print_config (fpc_system_config_t &cfg)
162+ {
163+
164+ Serial.print (" Version:\t\t\t " );
165+ Serial.println (cfg.version );
166+ Serial.print (" Finger Scan Interval (ms):\t " );
167+ Serial.println (cfg.finger_scan_interval_ms );
168+ Serial.print (" System Flags:\t\t\t 0x" );
169+ Serial.println (cfg.sys_flags , HEX);
170+ Serial.print (" Allows Factory Reset:\t\t " );
171+ Serial.println ((cfg.sys_flags & CFG_SYS_FLAG_ALLOW_FACTORY_RESET) ? " Yes" : " No" );
172+ Serial.print (" UART Delay Before IRQ (ms):\t " );
173+ Serial.println (cfg.uart_delay_before_irq_ms );
174+ Serial.print (" UART Baudrate:\t\t 0x" );
175+ Serial.println (cfg.uart_baudrate , HEX);
176+ Serial.print (" Max Consecutive Identify Fails: " );
177+ Serial.println (cfg.idfy_max_consecutive_fails );
178+ Serial.print (" Identify Lockout Time (s):\t " );
179+ Serial.println (cfg.idfy_lockout_time_s );
180+ Serial.print (" Idle Time Before Sleep (ms):\t " );
181+ Serial.println (cfg.idle_time_before_sleep_ms );
182+ Serial.print (" Enroll Touches:\t\t " );
183+ Serial.println (cfg.enroll_touches );
184+ Serial.print (" Enroll Immobile Touches:\t " );
185+ Serial.println (cfg.enroll_immobile_touches );
186+ Serial.print (" I2C Address (7bit):\t\t 0x" );
187+ Serial.println (cfg.i2c_address , HEX);
188+ }
189+ // ----------------------------------------------------------------------------
190+ // on_system_config_get()
191+ void on_system_config_get (fpc_system_config_t *cfg)
192+ {
193+ if (cfg == NULL )
194+ {
195+ Serial.println (" [ERROR]\t Invalid configuration data received" );
196+ return ;
197+ }
198+ // first print the config
199+ Serial.println (" [CONFIG]\t System Configuration Received:" );
200+ print_config (*cfg);
201+
202+ // result of our initial request to get the config
203+ if (configState == CONFIG_REQUESTED)
204+ {
205+ // stash our current config as the default
206+ the_config = *cfg;
207+
208+ configState = CONFIG_RECEIVED;
209+ }
210+ else if (configState == CONFIG_VERIFY)
211+ {
212+ // verify the config set worked
213+ if (cfg->idfy_max_consecutive_fails == the_config.idfy_max_consecutive_fails + 1 )
214+ Serial.println (" [INFO]\t\t Configuration update verified successfully." );
215+ else
216+ {
217+ Serial.println ();
218+ Serial.println (" [ERROR]\t Configuration update verification failed." );
219+ Serial.println ();
220+ }
221+
222+ // back to entry state
223+ configState = CONFIG_RESET;
224+ }
225+ }
226+ // ------------------------------------------------------------------------------------
227+ // Callbacks
228+ //
229+ // Define our command callbacks structure - callback methods are assigned in setup
230+ static sfDevFPC2534Callbacks_t cmd_cb = {0 };
231+
232+ // ------------------------------------------------------------------------------------
233+ // reset_sensor()
234+ //
235+ // Simple function to toggle the reset pin of the sensor
236+ //
237+ void reset_sensor (void )
238+ {
239+ // Reset the sensor by toggling the reset pin.
240+ //
241+ // clear out our data buffer
242+ mySensor.clearData ();
243+ pinMode (RST_PIN, OUTPUT);
244+ digitalWrite (RST_PIN, LOW); // Set reset pin low
245+ delay (10 ); // Wait for 10 ms
246+
247+ digitalWrite (RST_PIN, HIGH); // Set reset pin high
248+ delay (250 ); // Wait for sensor to initialize
249+ }
250+ // ------------------------------------------------------------------------------------
251+ // Process the simple sequece of steps for the demo.
252+
253+ void process_demo_steps (void )
254+ {
255+
256+ // if we have the config, and haven't updated it yet, do so now
257+ if (configState == CONFIG_RECEIVED)
258+ {
259+ // update the max fails value
260+ update_config_max_fails (the_config.idfy_max_consecutive_fails + 1 );
261+
262+ configState = CONFIG_SET;
263+ }
264+ else if (configState == CONFIG_SET)
265+ {
266+ // Get the new value of the config to verify the set worked
267+ Serial.println (" [INFO]\t\t Requesting system configuration..." );
268+ // Request the configuration from the connected device.
269+ fpc_result_t rc = mySensor.requestGetSystemConfig (FPC_SYS_CFG_TYPE_DEFAULT);
270+ if (rc != FPC_RESULT_OK)
271+ {
272+ Serial.print (" [ERROR]\t Get config request failed - error: " );
273+ Serial.println (rc);
274+ }
275+ else
276+ configState = CONFIG_VERIFY;
277+ }
278+ else if (configState == CONFIG_RESET)
279+ {
280+ // Reset to defaults
281+ fpc_result_t rc = mySensor.setSystemConfig (&the_config);
282+ if (rc != FPC_RESULT_OK)
283+ {
284+ Serial.print (" [ERROR]\t Set config request failed - error: " );
285+ Serial.println (rc);
286+ }
287+ else
288+ Serial.println (" [INFO]\t\t Set config to the original value" );
289+ configState = CONFIG_COMPLETE;
290+ }
291+ else if (configState == CONFIG_COMPLETE)
292+ {
293+ // Get the new value of the config to verify the set worked
294+ Serial.println (" [INFO]\t\t Requesting final configuration..." );
295+ // Request the configuration from the connected device.
296+ fpc_result_t rc = mySensor.requestGetSystemConfig (FPC_SYS_CFG_TYPE_DEFAULT);
297+ if (rc != FPC_RESULT_OK)
298+ {
299+ Serial.print (" [ERROR]\t Get config request failed - error: " );
300+ Serial.println (rc);
301+ }
302+ else
303+ configState = CONFIG_EXIT;
304+ }
305+ }
306+ // ------------------------------------------------------------------------------------
307+ // setup()
308+ //
309+ void setup ()
310+ {
311+ delay (2000 );
312+
313+ // Set up serial communication for debugging
314+ Serial.begin (115200 ); // Set baud rate to 115200
315+ while (!Serial)
316+ {
317+ ; // Wait for serial port to connect. Needed for native USB port only
318+ }
319+ Serial.println ();
320+ Serial.println (" ----------------------------------------------------------------" );
321+ Serial.println (" SparkFun FPC2534 Fingerprint Config Example - SPI" );
322+ Serial.println ();
323+ Serial.println (" **NOTE** Currently the `setSystemConfig` command fails to set the updated values." );
324+ Serial.println ();
325+ Serial.println (" ----------------------------------------------------------------" );
326+ Serial.println ();
327+
328+ // The internal UART buffer can fill up quickly and overflow. As such, increase its size.
329+ // This example is supporting ESP32 and RP2040 based boards - adjust as needed for other platforms.
330+ #if defined(ARDUINO_ARCH_RP2040)
331+ Serial1.setFIFOSize (512 );
332+ #elif defined(ESP32)
333+ Serial1.setRxBufferSize (512 );
334+ #endif
335+
336+ Serial1.begin (921600 , SERIAL_8N1);
337+ delay (100 );
338+ for (uint32_t startMS = millis (); !Serial1 && (millis () - startMS < 5000 );) // Wait for the serial port to be ready
339+ delay (200 );
340+ Serial.println (" [STARTUP]\t Serial1 started for FPC2534 communication." );
341+
342+ // Reset the sensor to ensure it's in a known state - by default this also triggers the
343+ // sensor to send a status message
344+ reset_sensor ();
345+
346+ // Initialize the sensor library
347+ if (!mySensor.begin (Serial1))
348+ {
349+ Serial.println (" [ERROR]\t FPC2534 not found. Check wiring. HALT." );
350+ while (1 )
351+ delay (1000 );
352+ }
353+ Serial.println (" [STARTUP]\t FPC2534 initialized." );
354+
355+ // setup our callback functions structure
356+ cmd_cb.on_error = on_error;
357+ cmd_cb.on_status = on_status;
358+ cmd_cb.on_is_ready_change = on_is_ready_change;
359+ cmd_cb.on_system_config_get = on_system_config_get;
360+
361+ // set the callbacks for the sensor library to call
362+ mySensor.setCallbacks (cmd_cb);
363+
364+ // Reset the sensor to start fresh
365+ reset_sensor ();
366+
367+ // Ready to go!
368+ Serial.println (" [STARTUP]\t Fingerprint system initialized." );
369+ }
370+
371+ // ------------------------------------------------------------------------------------
372+ void loop ()
373+ {
374+
375+ // Call the library to process the next response from the sensor. The library will call our above
376+ // callback functions as events occur.
377+ fpc_result_t rc = mySensor.processNextResponse ();
378+ if (rc != FPC_RESULT_OK && rc != FPC_PENDING_OPERATION)
379+ {
380+ Serial.print (" [ERROR] Processing Error: " );
381+ Serial.println (rc);
382+ // Hmm - reset the sensor and start again?
383+ reset_sensor ();
384+ }
385+ else if (deviceIdle)
386+ process_demo_steps ();
387+
388+ delay (200 );
389+ }
0 commit comments