serial protocol datasheet<\/a>\u00a0. The byte sequence looks like this:<\/p>\nbyte [] CMD_REQUEST_CONNECTION = {0x7e, \/\/ Start Byte\r\n0x00, 0x00, 0x00, 0x01, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x01, \/\/ Header Checksum\r\n};<\/pre>\n<\/p>\n
I wrote a processing code for communicating with the sensor. With it I am able to activate it, and put it in auto mode where it is scanning my finger, but something is still wrong with my attempts to register fingerprints. I think the problem is in the way I am sending the ‘data’ part. I don’t understand why I am sending data if there is nothing but retrieval from the device.<\/p>\n
Here is the sketch:<\/p>\n
\/*\r\nThis code interacts with the FIM5360N-LV Fingerprint Scanner\r\nMy setup is a USB - serial via MAX3232 to the FIM5360N-LV.\r\nmore info at http:\/\/www.mariarabinovich.com\/blog\/archives\/1061\r\nCommand info and responses are explained in the serial protocol\r\ndatasheet: http:\/\/dlnmh9ip6v2uc.cloudfront.net\/datasheets\/Sensors\/Biometric\/EN%20FIM%20ComProtocol%20V2.01.pdf\r\nSerial protocol I'm using is explained in this datasheet.\r\nOnly some of the commands are in this code.\r\n\r\nKeyPresses Activate the following commands:\r\n\r\nc- CMD_REQUEST_CONNECTION\r\nm- CMD_ENTER_MASTER_MODE2\r\nn- CMD_LEAVE_MASTER_MODE\r\nl- CMD_GET_FP_LIST2\r\ne- CMD_CHG_EMULMODE\r\n\r\nv- CMD_VERIFY_FP (0x11)\r\nr- CMD_REGISTER_FP (0x33)\r\nt- CMD_REGISTER_FP_SECOND_CAPTURE (0x33)\r\ni- CMD_IDENTIFY_FP (0x12)\r\na- CMD_START_AUTO_IDENTIFY (0x1A)\r\ns- CMD_STOP_AUTO_IDENTIFY (0x1A)\r\n\r\n*\/\r\n\r\nimport processing.serial.*;\r\nint counter=0;\r\nSerial myPort;\r\n\r\n\/\/DEFINE THE COMMANDS BY STORING THEM IN ARRAYS:\r\nbyte [] CMD_REQUEST_CONNECTION = {0x7e,\r\n0x00, 0x00, 0x00, 0x01, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x01, \/\/ Header Checksum\r\n};\r\n\r\nbyte [] CMD_ENTER_MASTER_MODE2 = {0x7e,\r\n0x00, 0x00, 0x00, 0x2F, \/\/ Command\r\n0x00, 0x00, 0x00, 0x03, \/\/ Parameter 1 is set here to NO AUTHORIZATION\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x32, \/\/ Header Checksum\r\n};\r\n\r\nbyte [] CMD_LEAVE_MASTER_MODE = {0x7e,\r\n0x00, 0x00, 0x00, 0x26, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x26, \/\/ Header Checksum\r\n};\r\n\r\nbyte [] CMD_GET_FP_LIST2 = {0x7e,\r\n0x00, 0x00, 0x00, 0x30, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1 \/\/ this lists the user count and IDs, use 0x01 for just the count\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x30, \/\/ Header Checksum\r\n};\r\n\r\n\/* Emulation Modes define how the general input\/output pins (GPIO's)\r\nare used. I think FIM30 is the way to go:\r\n\r\nVCC\r\nRX\r\nTX\r\n0 Output high when authentication, registration and deletion are succeeded.\r\n1 Output high when authentication, registration and deletion are failed.\r\n2 Do registration when the port level goes from high to low.\r\n3 Do deletion when the port level goes from high to low.\r\n4 Do identification when the port level goes from high to low.\r\nGRND\r\n*\/\r\n\r\nbyte [] CMD_CHG_EMULMODE = {0x7e,\r\n0x00, 0x00, 0x00, 0x51, \/\/ Command\r\n0x00, 0x00, 0x00, 0x02, \/\/ Parameter 1 \/\/ this sets it to FIM30 emulation mode\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x53, \/\/ Header Checksum\r\n};\r\n\r\n\/\/BUT USE IDENTIFY I THINK\r\nbyte [] CMD_VERIFY_FP = {0x7e,\r\n0x00, 0x00, 0x00, 0x11, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1 \/\/ no password\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2 \/\/packet index\r\n0x00, 0x00, 0x00, 0x0A, \/\/ Data Size \/\/fpid(10)+password(0)\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x1B, \/\/ Header Checksum\r\n};\r\n\r\nbyte [] CMD_IDENTIFY_FP = {0x7e,\r\n0x00, 0x00, 0x00, 0x12, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x12, \/\/ Header Checksum\r\n}; \/\/ response 12, 01, 00, 0A, 00, 1D means\r\n \/\/successful and user ID is returned\r\n\r\n\/*FIM30 emulation mode: (p91)\r\nLENGTH_OF_FPID = 10 \/\/this is a string, so the last byte is 0x00, available size of password is LENGTH-OF-PASSWD-1\r\nLENGTH_OF_PASSWD = 16\r\nLENGTH_OF_TEMPLATE_HEADER=0\r\nLENGTH_OF_TEMPLATE_DATA = 400*\/\r\n\r\n\/\/automatically tries to identify if place a finger on device:\r\nbyte [] CMD_START_AUTO_IDENTIFY = {0x7e,\r\n0x00, 0x00, 0x00, 0x1A, \/\/ Command\r\n0x00, 0x00, 0x00, 0x01, \/\/ Parameter 1 \/\/0=stop, 1=start\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x1B, \/\/ Header Checksum \/\/1A or 1B\r\n};\r\nbyte [] CMD_STOP_AUTO_IDENTIFY = {0x7e,\r\n0x00, 0x00, 0x00, 0x1A, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1 \/\/0=stop, 1=start\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 2\r\n0x00, 0x00, 0x00, 0x00, \/\/ Data Size\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x1A, \/\/ Header Checksum \/\/1A or 1B\r\n};\r\n\/*returns CMD_AUTO_IDENTIFY_RESULT:\r\n0x1B\r\n0x01(0r2=failed)\r\n0\r\nsize of FPID\r\nerror code\r\nFPID if successful, else, 0\r\n*\/\r\n\r\n\/\/IN MASTER MODE ONLY: RUN REGISTER in two parts:\r\nbyte [] CMD_REGISTER_FP = {0x7e,\r\n0x00, 0x00, 0x00, 0x33, \/\/ Command\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1 \/\/ 0= registers user 1=master\r\n0x00, 0x00, 0x00, 0x10, \/\/ Parameter 2 \/\/ auto generate id\r\n0x00, 0x00, 0x00, 0x1A, \/\/ Data Size \/\/sends 16 bytes null-data as password and length of FPID\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x5D, \/\/ Header Checksum\r\n\/\/data:\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00,<\/pre>\n0x00, 0x00, 0x00, 0x00 \/\/Data Checksum\r\n};<\/pre>\n\/\/If the first time returns success (param1= 1) send a second capture:\r\nbyte [] CMD_REGISTER_FP_SECOND_CAPTURE = {0x7e,\r\n0x00, 0x00, 0x00, 0x33, \/\/ Command \/\/same as above, 2nd run\r\n0x00, 0x00, 0x00, 0x00, \/\/ Parameter 1 \/\/ 0=user 1=master\r\n0x00, 0x00, 0x00, 0x01, \/\/ Parameter 2 \/\/ get read and save\r\n0x00, 0x00, 0x00, 0x1A, \/\/ Data Size \/\/sends 16 bytes null-data as password\r\n0x00, 0x00, 0x00, 0x00, \/\/ Error Code\r\n0x00, 0x00, 0x00, 0x4E, \/\/ Header Checksum<\/pre>\n\/\/data:\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00,<\/pre>\n0x00, 0x00, 0x00, 0x00 \/\/Data Checksum\r\n};<\/pre>\n\/\/Should get another param1=1, param2=0B. . . checksum3F\r\n\/\/Then User is Added to the Device\r\n\r\n\/*Some commands that may be useful:\r\n\r\nCMD_SET_MASTER (0x24)\r\nCMD_READ_USER_DATA (0x2B)\r\nCMD_WRITE_USER_DATA (0x2C)\r\nCMD_READ_LOG_DATA2 (0x32)\r\nCMD_GET_IMAGE_QUALITY (0x68)\r\nThis command returns image quality after using the following commands.\r\nCMD_VERIFY_FP, CMD_IDENTIFY_FP, CMD_INSTANT_MATCHING\r\nCMD_GET_TEMPLATE, CMD_GET_FP_IMAGE2, CMD_ENTER_MASTER_MODE2\r\nCMD_REGISTER_FP, CMD_CHANGE_FP, CMD_FEGISTER_MULTI_F*\/\r\n\r\nvoid setup(){\r\nprintln(Serial.list());\r\nmyPort=new Serial(this, Serial.list()[0], 9600);\r\n}\r\n\r\nvoid draw(){\r\n}\r\n\r\nvoid serialEvent(Serial myPort){\r\n\r\ncounter++;\r\nint inByte=myPort.read();\r\nbackground(255);\r\n\r\n\/\/CONVERTING DEC INPUT TO HEX TO MATCH SERIAL DATASHEET\r\nString inByteString=hex(inByte);\r\nString noZeros = inByteString.substring(6);\r\nprintln(noZeros);\r\n\r\n\/\/ADDING LABELS JUST TO READ EASIER:\r\n\r\nif(counter==1){println(\"Command:\");}\r\nelse if (counter==5){println(\"Param 1:\");}\r\n else if (counter==9){println(\"Param 2:\");}\r\n else if (counter==13){println(\"Data Size:\");}\r\n else if (counter==17){println(\"Error Code:\");}\r\n else if (counter==21){println(\"Header Checksum:\");}\r\n else if (counter==25){println(\"Data::\");}\r\n\/\/if(counter==24){counter=0;}\r\n}\r\n\r\nvoid keyReleased(){\r\nprintln();\r\ncounter=0;\r\nprintln(\"Begin response:\");\r\n\r\n\/\/CMD_REQUEST_CONNECTION 0x36\r\nif (key=='c'){\r\nfor (int i=0; i<CMD_REQUEST_CONNECTION .length; i++){\r\nmyPort.write(CMD_REQUEST_CONNECTION [i]);\r\nprintln(\"CMD_REQUEST_CONNECTION\");}} \r\n\r\n\/\/Command to Enter Master Mode: 0X2F\r\nif (key=='m'){\r\nfor (int i=0; i<CMD_ENTER_MASTER_MODE2.length; i++){\r\nmyPort.write(CMD_ENTER_MASTER_MODE2[i]);\r\nprintln(\"CMD_ENTER_MASTER_MODE2\");}} \r\n\r\n\/\/Command to Leave Master Mode: 0x26\r\nif (key=='n'){\r\nfor (int i=0; i<CMD_LEAVE_MASTER_MODE.length; i++){\r\nmyPort.write(CMD_LEAVE_MASTER_MODE[i]);\r\nprintln(\"CMD_LEAVE_MASTER_MODE\");}} \r\n\r\n\/\/Command to Get Fingerprint List: 0x30\r\nif (key=='l'){\r\nfor (int i=0; i<CMD_GET_FP_LIST2.length; i++){\r\nmyPort.write(CMD_GET_FP_LIST2[i]);\r\nprintln(\"CMD_GET_FP_LIST2\");}} \r\n\r\nif (key=='e'){\r\nfor (int i=0; i<CMD_CHG_EMULMODE.length; i++){\r\nmyPort.write(CMD_CHG_EMULMODE[i]);\r\nprintln(\"CMD_CHG_EMULMODE\");}} \r\n\r\nif (key=='v'){\r\nfor (int i=0; i<CMD_VERIFY_FP.length; i++){\r\nmyPort.write(CMD_VERIFY_FP[i]);\r\nprintln(\"CMD_VERIFY_FP\");}} \r\n\r\nif (key=='r'){\r\nfor (int i=0; i<CMD_REGISTER_FP.length; i++){\r\nmyPort.write(CMD_REGISTER_FP[i]);\r\nprintln(\"CMD_REGISTER_FP\");}} \r\n\r\nif (key=='t'){\r\nfor (int i=0; i<CMD_REGISTER_FP_SECOND_CAPTURE.length; i++){\r\nmyPort.write(CMD_REGISTER_FP_SECOND_CAPTURE[i]);\r\nprintln(\"CMD_REGISTER_FP_SECOND_CAPTURE\");}} \r\n\r\nif (key=='i'){\r\nfor (int i=0; i<CMD_IDENTIFY_FP.length; i++){\r\nmyPort.write(CMD_IDENTIFY_FP[i]);\r\nprintln(\"CMD_IDENTIFY_FP\");}} \r\n\r\nif (key=='a'){\r\nfor (int i=0; i<CMD_START_AUTO_IDENTIFY.length; i++){\r\nmyPort.write(CMD_START_AUTO_IDENTIFY[i]);\r\nprintln(\"CMD_START_AUTO_IDENTIFY\");}} \r\n\r\nif (key=='s'){\r\nfor (int i=0; i<CMD_STOP_AUTO_IDENTIFY.length; i++){\r\nmyPort.write(CMD_STOP_AUTO_IDENTIFY[i]);\r\nprintln(\"CMD_STOP_AUTO_IDENTIFY\");}} \r\n\r\n}<\/pre>\n<\/pre>\n<\/pre>\n<\/pre>\n","protected":false},"excerpt":{"rendered":" This is a summary of my progress in hacking the\u00a0FIM5360N-LV\u00a0fingerprint scanner. \u00a0I am not yet able to register fingerprints, but otherwise feel very close to having it work. I solved some issues that I couldn’t find answers for online, so I wanted to document this in detail for future reference. I used a\u00a0MAX3232\u00a0 […]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1061","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/posts\/1061","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/comments?post=1061"}],"version-history":[{"count":16,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/posts\/1061\/revisions"}],"predecessor-version":[{"id":1071,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/posts\/1061\/revisions\/1071"}],"wp:attachment":[{"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/media?parent=1061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/categories?post=1061"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mariarabinovich.com\/blog\/wp-json\/wp\/v2\/tags?post=1061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}