├── README.md ├── sections ├── ex_data.md ├── realtime.md ├── other.md ├── data-record.md ├── access.md ├── data-user.md └── terminal.md └── protocol.md /README.md: -------------------------------------------------------------------------------- 1 | # zk-protocol # 2 | A precise, clean and easy to understand description of the protocol used in ZKTeco devices. 3 | 4 | **Check the [PyZatt lib](https://github.com/adrobinoga/pyzatt)!!!** 5 | 6 | ## Getting Started ## 7 | 8 | This project is part of an effort to build an alternative for ZKTeco's Standalone devices, you should begin by reading the user manual and the Standalone SDK docs, that can be found in ZKTeco's SDKs Download page. 9 | 10 | Then begin with the main page: 11 | 12 | - [protocol.md](./protocol.md) 13 | 14 | Protocol related operations are grouped in the following sections: 15 | 16 | - [ex_data.md](sections/ex_data.md): Protocol for the exchange of large amounts of data. 17 | - [terminal.md](sections/terminal.md): Protocol for procedures to get/set device parameters. 18 | - [data-user.md](sections/data-user.md): Protocol to manage the users data. 19 | - [data-record.md](sections/data-record.md): Protocol to manage records. 20 | - [access.md](sections/access.md): Protocol to manage the access settings. 21 | - [realtime.md](sections/realtime.md): Protocol of the realtime events. 22 | - [other.md](sections/other.md): Other procedures. 23 | 24 | ## Develop ## 25 | 26 | Currently this spec is intended for devices of the TFT series, but there's no reason to keep it that way. 27 | 28 | Make contributions to the develop branch under a pull request. 29 | 30 | Capture files of network traffic of documented tests are welcomed. 31 | 32 | ## Contact ## 33 | 34 | Author: Alexander Marin 35 | -------------------------------------------------------------------------------- /sections/ex_data.md: -------------------------------------------------------------------------------- 1 | # Exchange of Data # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Introduction ## 10 | 11 | When sending/receiving, small sets of data (approx. less than 1KB) to/from the machine, using `CMD_DATA_WRRQ` command, the protocol follows a very simple scheme. For a reading operation we have: 12 | 13 | > packet(id=CMD_DISABLEDEVICE) 14 | > packet(id=CMD_ACK_OK) 15 | > packet(id=CMD_DATA_WRRQ, data=) 16 | > packet(id=CMD_DATA, data=) 17 | > packet(id=CMD_ENABLEDEVICE) 18 | > packet(id=CMD_ACK_OK) 19 | 20 | **Notes**: 21 | 22 | - The `dataset` and `data id` fields are specific to each procedure and are described in the corresponding sections. 23 | - Writing of small datasets is performed with specific commands described in the corresponding sections. 24 | 25 | For larger sets of data (approx. more than 1KB) a set of additional commands should be used. 26 | 27 | ## Receiving Large Datasets ## 28 | 29 | Before requesting a large dataset a disable command should be sent. 30 | 31 | Then a request of data can be done with the command `CMD_DATA_WRRQ`, if the data is large enough the device may decide to not send the data in one command, like in the previous section. If that's the case the device will reply with packet with the code `CMD_ACK_OK` and a data structure. 32 | 33 | > packet(id=CMD_DISABLEDEVICE) 34 | > packet(id=CMD_ACK_OK) 35 | > packet(id=CMD_DATA_WRRQ, data=) 36 | > packet(id=CMD_ACK_OK, data=) 37 | 38 | The `data stat` structure contains the size of the data to be sent to the client: 39 | 40 | |Name |Description |Value[hex] |Size[bytes] |Offset | 41 | |--- |--- |--- |--- |--- | 42 | | |Fixed. |00 |1 |0 | 43 | |size dataset (*) |Size of the dataset to be sent from the device.|varies (<) |4 |1 | 44 | |size dataset (*) |"" |varies (<) |4 |5 | 45 | |unknown |Unknown value, seems to be a kind of checksum. |varies |4 |9 | 46 | 47 | (<): Little endian format. 48 | 49 | (*): These values show the same value, but for larger datasets we dont know if that would be the case, since it doesn't make sense to have the value duplicated. 50 | 51 | After that, send a `CMD_DATA_RDY` command to indicate the device to trasmit the data. This command carries a structure, `rdy struct`, with the following fields: 52 | 53 | |Name |Description |Value[hex] |Size[bytes] |Offset | 54 | |--- |--- |--- |--- |--- | 55 | | |Fixed. |0000 |4 |0 | 56 | |size dataset |Size of the dataset to be sent from the device.|varies (<) |4 |4 | 57 | 58 | (<): Little endian format. 59 | 60 | After that the device would send a packet with the command `CMD_PREPARE_DATA` and a structure, `prep struct`, which has the following fields: 61 | 62 | |Name |Description |Value[hex] |Size[bytes] |Offset | 63 | |--- |--- |--- |--- |--- | 64 | |size dataset |Size of the dataset to be sent from the device.|varies (<) |4 |0 | 65 | | |Fixed. |0010 |4 |4 | 66 | 67 | (<): Little endian format. 68 | 69 | Just after that, without a reply from the client, the machine sends the data with a `CMD_DATA` command, the data field of this packet carries the requested info. Keep in mind that the length of the data field of this packet equals to `size dataset`. After sending the dataset and without waiting for a client reply, the device sends an acknowledge command, without any data. 70 | 71 | It is worth to note that the reply number for this sequence of commands(`CMD_PREPARE_DATA`, `CMD_DATA`, `CMD_ACK_OK`) is the same. 72 | 73 | The procedure ends with a command to free the buffer of the machine, using `CMD_FREE_DATA` command, and an enable command, to return to normal operation. 74 | 75 | > packet(id=CMD_DATA_RDY, data=, reply number=) 76 | > packet(id=CMD_PREPARE_DATA, data=, reply number=) 77 | > packet(id=CMD_DATA, data=, reply number=) 78 | > packet(id=CMD_ACK_OK, reply number=) 79 | > packet(id=CMD_FREE_DATA, reply number=) 80 | > packet(id=CMD_ACK_OK, reply number=) 81 | > packet(id=CMD_ENABLEDEVICE, reply number=) 82 | > packet(id=CMD_ACK_OK, reply number=) 83 | 84 | ## Sending Large Datasets ## 85 | 86 | When using the SDK, the writing operations may be performed individually(i.e. small datasets), each user's info and each template is modified one at a time. However in tipical sync procedures (used in ZKAccess), large datasets are written in one operation, same result could be obtained by using individual write operations, so in this project writing operations of large datasets aren't considered. 87 | 88 | [Go to Main Page](../protocol.md) 89 | -------------------------------------------------------------------------------- /sections/realtime.md: -------------------------------------------------------------------------------- 1 | # Realtime Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | |SDK function name |Described(X=Yes, O=No) |Notes| 12 | |--- |:---: |---| 13 | |OnConnected |**X** |This can be easily checked with a device info request.| 14 | |OnDisConnected |**X** |This can be easily checked with a device info request.| 15 | |OnAlarm |**X** | | 16 | |OnDoor |**X** |Some tests need to be performed.| 17 | |OnAttTransaction |**O** |Applicable only to BW.| 18 | |OnAttTransactionEx |**X** | | 19 | |OnDeleteTemplate |**O** |Todo.| 20 | |OnEnrollFinger |**X** | | 21 | |OnFinger |**X** | | 22 | |OnFingerFeature |**X** | | 23 | |OnHIDNum |**O** |Todo.| 24 | |OnKeyPress |**O** |Todo.| 25 | |OnNewUser |**O** |Todo.| 26 | |OnVerify |**X** | | 27 | |OnWriteCard |**O** |Todo.| 28 | |OnEmptyCard |**O** |Todo.| 29 | |OnEMData |**O** |Just triggers the event for unknown inputs.| 30 | |RegEvent |**O** |Just checks for several events.| 31 | |ReadRTLog |**O** |Involves reading PC buffer.| 32 | |GetRTLog |**O** |Involves reading PC buffer.| 33 | 34 | ## Realtime Events ## 35 | 36 | The realtime events are useful to monitor the state of doors and to receive alarms of abnormal situations, this type of packets are also used to follow the steps of an enrolling procedure. 37 | 38 | To receive this type of packets a connection needs to be setup, so the idea is to connect to all the devices to be monitored and interpret the incoming packets from the machines. 39 | 40 | This packets are sent without prior request since they depend on external situations, so the general conversation flow is as follows: 41 | 42 | > rtpacket(event=EF_X, data=<...>, reply number=0000) 43 | > packet(id=CMD_ACK_OK, session id=, reply number=0000) 44 | 45 | Where the `session id` of the client reply is the same as the id set from the connection, and the `reply number` is the same of the incoming packet which for realtime packets, happens to be `0000`. 46 | 47 | ## Enable Realtime ## 48 | 49 | To be able to receive realtime packets, you must send a packet with the command `CMD_REG_EVENT` and a fixed data field of 4 bytes: 50 | 51 | > packet(id=CMD_REG_EVENT, data=ffff0000) 52 | > packet(id=CMD_ACK_OK) 53 | 54 | ## Alarm ## 55 | 56 | There may be several causes to trigger the alarm, this info is included in the realtime packet sent to the device, the general form of the packet is given by: 57 | 58 | rtpacket(event=EF_ALARM, data=) 59 | 60 | Where the `alarm info` structure varies according to the event trigger, if the alarm is triggered. 61 | 62 | 1.If the alarm is triggered because of an exit button, tamper or misoperation. 63 | 64 | The `alarm info` is 4 bytes long and the first byte indicates the alarm type, with the following codification: 65 | 66 | |Alarm type |Value[hex] | 67 | |--- |--- | 68 | |Misoperation |3A | 69 | |Tamper |37 | 70 | |Exit button |35 | 71 | 72 | 2.If the alarm is triggered because the door closes the `alarm info` is 8 bytes long and the first byte indicates the door is closing, with the value `0x54`. 73 | 74 | 3.For duress alarms the `alarm info` is 12 bytes long 75 | 76 | |Name |Description |Value[hex] |Size[bytes] |Offset | 77 | |--- |--- |--- |--- |--- | 78 | | |Fixed. |ffffffff |4 |2 | 79 | |alarm type |Alarm type, indicates cause. |varies (<) |2 |4 | 80 | |user sn |User's serial number. |varies (<) |2 |6 | 81 | |match type |Matching way. |varies (<) |4 |8 | 82 | 83 | (<): Little endian format. 84 | 85 | The alarm type indicates what triggered the alarm: 86 | 87 | |Alarm type |Value[hex] | 88 | |--- |--- | 89 | |Duress |20 | 90 | |Passback |22 | 91 | 92 | ## On Door ## 93 | 94 | See Alarm section. 95 | 96 | ## Attendace Realtime Log ## 97 | 98 | |Name |Description |Value[hex] |Size[bytes] |Offset | 99 | |--- |--- |--- |--- |--- | 100 | |user id |User's pin number, stores as a string. |varies |9 |0 | 101 | | |Fixed. |zeros |15 |9 | 102 | |verify type |Verify type. |varies (<) |2 |24 | 103 | |att time |Time given in a special format. |H0H1H2H3H4H5 |6 |26 | 104 | 105 | (<): Little endian format. 106 | 107 | The verify type follows the same codification given on the attendance logs. 108 | 109 | The time of attendance is given with a special format, if the time is given by the sequence: 110 | 111 | H0 H1 H2 H3 H4 H5 112 | 113 | The date 114 | 115 | YEAR/MONTH/DAY HOURS:MINUTES:SECONDS 116 | 117 | can be obtained by extracting each byte as a number, and entering them in the following formula: 118 | 119 | date = 20/

/

:

:

120 | 121 | ### Example ### 122 | 123 | This is a realtime packet of an attendance event: 124 | 125 | 00000000: 50 50 82 7D 28 00 00 00 F4 01 AC 12 01 00 00 00 PP.}(........... 126 | 00000010: 39 39 39 31 31 31 33 33 33 00 00 00 00 00 00 00 999111333....... 127 | 00000020: 00 00 00 00 00 00 00 00 01 00 12 06 19 11 29 05 ..............). 128 | 129 | The user id is "999111333", verified using the fingerprint and the date corresponds to: 130 | 131 | 2018/06/25 17:41:05 132 | 133 | ## Enrolled Finger ## 134 | 135 | After a fingerprint enrolling process the machine returns a structure indicating how the procedure went: 136 | 137 | rtpacket(event=EF_ENROLLFINGER, data=) 138 | 139 | The `enroll result` structure has the following fields: 140 | 141 | |Name |Description |Value[hex] |Size[bytes] |Offset | 142 | |--- |--- |--- |--- |--- | 143 | |result |Error code. |varies (<) |2 |0 | 144 | |fp size |Size of fingerprint template. |varies (<) |2 |2 | 145 | |user id |User's pin number, stores as a string. |varies |9 |4 | 146 | |finger index |Finger index of the template. |varies |1 |13 | 147 | 148 | If the error code is equal to zero, that means the there was no error in the enrolling process, if the value is not zero that means that there was an error, in that case the fields `fp size`, `user id` and `finger index`, aren't even included. 149 | 150 | ## On Finger ## 151 | 152 | After someone puts finger on the machine reader, the machine sends a packet to indicate this, this happens in the enroll procedure and also in normal operation, whether the user is registered or not. 153 | 154 | The packet doesn't carry any additional data. 155 | 156 | rtpacket(event=EF_FINGER) 157 | 158 | ## Finger Score ## 159 | 160 | When performing the enrolling procedure, the machine sends a packet after a fingerprint sample to indicate the score of the given sample: 161 | 162 | rtpacket(event=EF_FPFTR, data=) 163 | 164 | The `score` is a measure of the "quality" of the fingerprint sample, the value is given as number, that may be 0 or 100(0x64). 165 | 166 | ## On Verify ## 167 | 168 | When someone tries to perform verification, the machine sends a packet to the client with the serial number of the user. 169 | 170 | rtpacket(event=EF_VERIFY, data=) 171 | 172 | The returned structure has the following fields: 173 | 174 | |Name |Description |Value[hex] |Size[bytes] |Offset | 175 | |--- |--- |--- |--- |--- | 176 | |user sn |User's serial number. |varies (<) |4 |0 | 177 | | |Fixed. |01 |1 |4 | 178 | 179 | If the user can't be identified, then the user sn equals to `ffffffff` 180 | 181 | [Go to Main Page](../protocol.md) 182 | -------------------------------------------------------------------------------- /sections/other.md: -------------------------------------------------------------------------------- 1 | # Other Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | Here is a list of SDK functions, from **Data-Other.h** and **Other.h** files, that shows which functions can be replicated with the current spec: 12 | 13 | |SDK function name |Described(X=Yes, O=No) |Notes| 14 | |--- |:---: |---| 15 | |TurnOffAlarm |**O** |Applicable to newer devices.| 16 | |SetEventMode |**O** |Applicable to newer devices.| 17 | |GetLastError |**O** |Applicable to newer devices.| 18 | |ClearAdministrators |**X** | | 19 | |EnableDevice |**X** | | 20 | |EnableClock |**X** | | 21 | |DisableDeviceWithTimeOut |**X** | | 22 | |PowerOffDevice |**X** | | 23 | |RestartDevice |**X** | | 24 | |StartEnroll |**O** |Only applicable to BW devices.| 25 | |StartEnrollEx |**X** | | 26 | |StartVerify |**O** | | 27 | |StartIdentify |**X** |Used inside enrolling procedure.| 28 | |CancelOperation |**X** |Used inside enrolling procedure.| 29 | |WriteLCD |**O** |Only applicable to BW devices.| 30 | |ClearLCD |**O** |Only applicable to BW devices.| 31 | |WriteCard |**O** |Todo.| 32 | |EmptyCard |**O** |Todo.| 33 | |GetHIDEventCardNumAsStr |**O** |Todo.| 34 | |CaptureImage |**O** |Todo.| 35 | |UpdateFirmware |**O** |Irrelevant.| 36 | |BeginBatchUpdate |**O** |Batch operations aren't considered.| 37 | |BatchUpdate |**O** |Batch operations aren't considered.| 38 | |CancelBatchUpdate |**O** |Batch operations aren't considered.| 39 | |PlayVoice |**O** |Irrelevant.| 40 | |PlayVoiceByIndex |**O** |Irrelevant.| 41 | |ReadAttRule |**O** |Only applicable to BW devices.| 42 | |SaveTheDataToFile |**O** |Only applicable to BW devices.| 43 | |ReadTurnInfo |**O** |Only applicable to BW devices.| 44 | |SSR_OutPutHTMLRep |**O** |Only applicable to BW devices.| 45 | |Connect_P4P |**O** |Applicable to some P2P devices.| 46 | |GetDeviceStatusEx |**O** |Applicable to some P2P devices.| 47 | |GetConnectStatus |**O** | | 48 | |SetSysOption |**X** |Same as set device info, see [terminal.md](./terminal.md)| 49 | |SearchDevice |**O** |Can be easily replicated.| 50 | |SetCommProType |**O** |Nothing to do with the machine.| 51 | |SSR_DelUserTmpExt |**X** |.| 52 | 53 | ## Clear Admins ## 54 | 55 | This procedure clears all admin privileges, sets the admin level of all users to "common user", this procedure doesn't need any additional data. 56 | 57 | 58 | > packet(id=CMD_CLEAR_ADMIN) 59 | > packet(id=CMD_ACK_OK) 60 | 61 | ## Enable/Disable Device ## 62 | 63 | If the device is disabled the fingerprint, keyboard and the rfid modules are unavailable, this is usually done when reading several parameters or when uploading data to the machine. 64 | 65 | To enable the device send: 66 | 67 | > packet(id=CMD_ENABLEDEVICE) 68 | > packet(id=CMD_ACK_OK) 69 | 70 | To disable the device send: 71 | 72 | > packet(id=CMD_DISABLEDEVICE) 73 | > packet(id=CMD_ACK_OK) 74 | 75 | To disable the device with a timeout, include the time in the data field: 76 | 77 | > packet(id=CMD_DISABLEDEVICE, data=) 78 | > packet(id=CMD_ACK_OK) 79 | 80 | Where the `timeout` is the number of seconds that the device will remain disable, is given as a 4 byte integer stored in little endian format. 81 | 82 | ## Enable Clock ## 83 | 84 | To enable/disable the clock dots on the machine screen, send the command `CMD_ENABLE_CLOCK`. 85 | 86 | > packet(id=CMD_ENABLE_CLOCK) 87 | > packet(id=CMD_ACK_OK) 88 | 89 | ## Power Off ## 90 | 91 | To shut down the device send the command `CMD_POWEROFF` followed by the command `CMD_EXIT`: 92 | 93 | > packet(id=CMD_POWEROFF) 94 | > packet(id=CMD_ACK_OK) 95 | > packet(id=CMD_EXIT) 96 | > packet(id=CMD_ACK_OK) 97 | 98 | Then close the socket. 99 | 100 | ## Restart Device ## 101 | 102 | To restart the device just send the restart command: 103 | 104 | packet(id=CMD_RESTART) 105 | 106 | The machine will not acknowledge this command, close the connection and then wait a few seconds to create a new connection. 107 | 108 | ## Enroll User ## 109 | 110 | Before enrolling a new user a set of values should be requested. 111 | 112 | > packet(id=CMD_OPTIONS_RRQ, data="~PIN2Width\x00") 113 | > packet(id=CMD_ACK_OK, data="~PIN2Width=\x00") 114 | 115 | With this request we may found how long the user id can be, the given result should be converted to int. 116 | 117 | After that the `~IsABCPinEnable` parameter is requested: 118 | 119 | packet(id=CMD_OPTIOS_RRQ, data="~IsABCPinEnable\x00") 120 | 121 | Depending on the device the reply may be a `CMD_ACK_OK` or `CMD_ACK_ERROR`, if the reply is `CMD_ACK_ERROR`, that means that the device doesn't support alphanumeric symbols for user id values. 122 | 123 | The parameter `~T9FunOn` is also requested, but its purpose is still unknown, since the reply is `CMD_ACK_ERROR` for F19 terminals. 124 | 125 | Then send a cancel capture command `CMD_CANCELCAPTURE`, to disable the normal reading from the fingerprint module. 126 | 127 | > packet(id=CMD_CANCELCAPTURE) 128 | > packet(id=CMD_ACK_OK) 129 | 130 | Send enroll parameters with the `CMD_STARTENROLL` command 131 | 132 | > packet(id=CMD_STARTENROLL, data=) 133 | > packet(id=CMD_ACK_OK) 134 | 135 | Where the enroll data field is a structure of 26 bytes 136 | 137 | |Name |Description |Value[hex] |Size[bytes] |Offset | 138 | |--- |--- |--- |--- |--- | 139 | |user id |User's id given as a string. |varies |user-id width |0 | 140 | |zeros |Fixed. | | |user-id width | 141 | |finger index |Fingerprint index. |varies |1 |24 | 142 | |fp flag |Fingerprint flag. |vareis |1 |25 | 143 | 144 | Where the finger index is a number from 0 to 9, and it is stored as a number. 145 | 146 | **Note**: Check if the fingeprint exists for the given index and if so, it should be deleted, before sending the start enroll command. 147 | 148 | The flag may have 3 values 149 | 150 | |Value |Meaning | 151 | |--- |--- | 152 | |0 |Invalid fingerprint | 153 | |1 |Valid fingerprint | 154 | |3 |Duress fingerprint | 155 | 156 | Then send the `CMD_STARTVERIFY` command to prompt the user to place the fingerprints: 157 | 158 | > packet(id=CMD_STARTVERIFY) 159 | > packet(id=CMD_ACK_OK) 160 | 161 | At this point, expect realtime packets from the machine, see [realtime.md](./realtime.md) for more details. 162 | 163 | The device will show messages on screen, asking the user for the fingerprints, which will be three for a valid enrolling. When the user puts the fingerprint on the reader, the machine will send a `EF_FINGER` event, followed by a `EF_FPFTR` event with the score of the given fingerprint: 164 | 165 | > rtpacket(event=EF_FINGER) 166 | > packet(id=CMD_ACK_OK) 167 | > rtpacket(event=EF_FPFTR, data=) 168 | > packet(id=CMD_ACK_OK) 169 | 170 | For a valid fingerprint sample, the score should be 100(0x64) 171 | 172 | After three valid samples or after an invalid sample, the device should send a packet with the event `EF_ENROLLFINGER`, with a data structure: 173 | 174 | > rtpacket(event=EF_ENROLLFINGER, data=) 175 | > packet(id=CMD_ACK_OK) 176 | 177 | The structure enroll result is described on [Realtime/Enrolled Finger](./realtime.md) section. 178 | 179 | ## Start Identify ## 180 | 181 | Put the machine at 1 to N comparison state: 182 | 183 | > packet(id=CMD_STARTVERIFY) 184 | > packet(id=CMD_ACK_OK) 185 | 186 | This procedure is used internally in the enrolling fingerprint procedure. 187 | 188 | ## Cancel Operation ## 189 | 190 | Disable normal verification state of the machine: 191 | 192 | > packet(id=CMD_CANCELCAPTURE) 193 | > packet(id=CMD_ACK_OK) 194 | 195 | This procedure is used internally in the enrolling fingerprint procedure. 196 | 197 | ## Delete User's Fingerprint Template ## 198 | 199 | See [data-user.md](./data-user.md). 200 | 201 | [Go to Main Page](../protocol.md) 202 | -------------------------------------------------------------------------------- /sections/data-record.md: -------------------------------------------------------------------------------- 1 | # Record Data Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | Here is a list of SDK functions, from **Data-Record.h** file, that shows which functions can be replicated with the current spec: 12 | 13 | |SDK function name |Described(X=Yes, O=No) |Notes| 14 | |--- |:---: |---| 15 | |SSR_SetDeviceData |**O** |This is only for newer firmware.| 16 | |SSR_GetDeviceData |**O** |This is only for newer firmware.| 17 | |ReadGeneralLogData |**X** | | 18 | |ReadAllGLogData |**X** |Same as ReadGeneralLogData.| 19 | |GetGeneralLogData |**O** |Applicable only to BW.| 20 | |SSR_GetGeneralLogData |**O** |Only operates on memory.| 21 | |GetAllGLogData |**O** |Applicable only to BW.| 22 | |GetGeneralLogDataStr |**O** |Applicable only to BW.| 23 | |GetGeneralExtLogData |**O** |Applicable only to BW.| 24 | |ClearGLog |**X** | | 25 | |ReadSuperLogData |**X** | | 26 | |ReadAllSLogData |**X** |Same as ReadSuperLogData.| 27 | |GetSuperLogData |**O** |Only operates on memory.| 28 | |GetAllSLogData |**O** |Only operates on memory.| 29 | |ClearSLog |**X** | | 30 | |GetSuperLogData2 |**O** |Only operates on memory.| 31 | |ClearKeeperData |**X** | | 32 | |ClearData |**X** | | 33 | |GetDataFile |**O** | | 34 | |SendFile |**O** |Todo.| 35 | |ReadFile |**O** |Applicable only to BW.| 36 | |RefreshData |**X** | | 37 | |ReadTimeGLogData |**O** |This is only for newer firmware.| 38 | |ReadNewGLogData |**O** |This is only for newer firmware.| 39 | |DeleteAttlogBetweenTheDate |**O** |This is only for newer firmware.| 40 | |DeleteAttlogByTime |**O** |This is only for newer firmware.| 41 | 42 | ## Read Attendance Records ## 43 | 44 | To read the attendance records, first disable the device: 45 | 46 | > packet(id=CMD_DISABLEDEVICE) 47 | > packet(id=CMD_ACK_OK) 48 | 49 | Then send a command with the id `CMD_DATA_WRRQ` and with a fixed payload of 11 bytes, field description for this payload it is still unknown. 50 | 51 | packet(id=CMD_DATA_WRRQ, data=010d000000000000000000) 52 | 53 | Depending of the size of the `att rec` structure, the device may send this info in two ways: 54 | 55 | 1.For "small" structures, the machine would send the info structure immediately 56 | 57 | > packet(id=CMD_DATA_WRRQ, data=010d000000000000000000) 58 | > packet(id=CMD_DATA, data=) 59 | 60 | 2.For bigger structures see the [Exchange of Data](ex_data.md) spec. 61 | 62 | The fields of the `att rec` structure are given in the following table: 63 | 64 | |Name |Description |Value[hex] |Size[bytes] |Offset | 65 | |--- |--- |--- |--- |--- | 66 | |att_size |Total size of user attendance entries. |N*40 (<) |4 |0 | 67 | |att1 entry |Attendance log 1. |varies |40 |4 | 68 | |att2 entry |Attendance log 2. |varies |40 |44 | 69 | |... |... |varies |40 |... | 70 | |attN entry |Attendance log N. |varies |40 |att_size-40+4 | 71 | 72 | (<): Little endian format. 73 | 74 | Each attendance entry has the following fields: 75 | 76 | |Name |Description |Value[hex] |Size[bytes] |Offset | 77 | |--- |--- |--- |--- |--- | 78 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 79 | |user id |User ID, stored as a string. |varies |9 |2 | 80 | | |Fixed. |00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |15 |11 | 81 | |verify type |Verification type. |varies |1 |26 | 82 | |record time |Time of the attendance event. |varies (<) |4 |27 | 83 | |verify state |Verification state. |varies |1 |31 | 84 | | |Fixed. |00 00 00 00 FF 00 00 00 |8 |32 | 85 | 86 | (<): Little endian format. 87 | 88 | Where the time is encoded in the same format used in set/get device time procedure, see [terminal.md](./terminal.md). 89 | 90 | The verification type codification is: 91 | 92 | |Verification type |Value | 93 | |--- |--- | 94 | |Password |0 | 95 | |Fingerprint |1 | 96 | |RF card |2 | 97 | 98 | The verification state codification is: 99 | 100 | |Verification state |Value | 101 | |--- |--- | 102 | |Check in (default) |0 | 103 | |Check out |1 | 104 | |Break out |2 | 105 | |Break in |3 | 106 | |OT in |4 | 107 | |OT out |5 | 108 | 109 | Finally send the enable device command to put the device in normal operation: 110 | 111 | > packet(id=CMD_ENABLEDEVICE) 112 | > packet(id=CMD_ACK_OK) 113 | 114 | ### Example of an Attendance Entry ### 115 | 116 | This is an example of an attendance entry, the user index is `0x000D` and his id number is "999111333", the verification type is 1, and the encoded time is given by `0x2368B36B`. 117 | 118 | 00000000: 0D 00 39 39 39 31 31 31 33 33 33 00 00 00 00 00 ..999111333..... 119 | 00000010: 00 00 00 00 00 00 00 00 00 00 01 6B B3 68 23 00 ...........k.h#. 120 | 00000020: 00 00 00 00 FF 00 00 00 ........ 121 | 122 | ## Clear All Attendance Records ## 123 | 124 | To clear the attendance records, first disable the device, then send a `CMD_CLEAR_ATTLOG` command, refresh the data and finally enable the device. 125 | 126 | > packet(id=CMD_DISABLEDEVICE) 127 | > packet(id=CMD_ACK_OK) 128 | > packet(id=CMD_CLEAR_ATTLOG) 129 | > packet(id=CMD_ACK_OK) 130 | > packet(id=CMD_REFRESHDATA) 131 | > packet(id=CMD_ACK_OK) 132 | > packet(id=CMD_ENABLEDEVICE) 133 | > packet(id=CMD_ACK_OK) 134 | 135 | Note that this will delete all the attendance records, time-interval delete operations are only supported on newer firmware versions. 136 | 137 | ## Read Operation Records ## 138 | 139 | To read the operation records, first disable the device: 140 | 141 | > packet(id=CMD_DISABLEDEVICE) 142 | > packet(id=CMD_ACK_OK) 143 | 144 | Then send a command with the id `CMD_DATA_WRRQ` and with a fixed payload of 11 bytes, field description for this payload it is still unknown. 145 | 146 | packet(id=CMD_DATA_WRRQ, data=0122000000000000000000) 147 | 148 | Depending of the size of the `ops rec` structure, the device may send this info in two ways: 149 | 150 | 1.For "small" structures, the machine would send the info structure immediately 151 | 152 | > packet(id=CMD_DATA_WRRQ, data=0122000000000000000000) 153 | > packet(id=CMD_DATA, data=) 154 | 155 | 2.For bigger structures see the [Exchange of Data](ex_data.md) spec. 156 | 157 | The fields of the `ops rec` structure are given in the following table: 158 | 159 | |Name |Description |Value[hex] |Size[bytes] |Offset | 160 | |--- |--- |--- |--- |--- | 161 | |ops_size |Total size of operation record entries.|N*16 (<) |4 |0 | 162 | |oplog1 entry |Operation log 1. |varies |16 |4 | 163 | |oplog2 entry |Operation log 2. |varies |16 |20 | 164 | |... |... |varies |16 |... | 165 | |oplogN entry |Operation log N. |varies |16 |ops_size-16+4 | 166 | 167 | (<): Little endian format. 168 | 169 | Each operation entry has the following fields: 170 | 171 | |Name |Description |Value[hex] |Size[bytes] |Offset | 172 | |--- |--- |--- |--- |--- | 173 | | |Fixed. |0000 |2 |0 | 174 | |operation id |Operation ID. |varies |1 |2 | 175 | |unknown | |varies |1 |3 | 176 | |record time |Record log time. |varies (<) |4 |4 | 177 | |param1 |Parameter 1. |varies (<) |2 |8 | 178 | |param2 |Parameter 2. |varies (<) |2 |10 | 179 | |param3 |Parameter 3. |varies (<) |2 |12 | 180 | |param4 |Parameter 4. |varies (<) |2 |14 | 181 | 182 | (<): Little endian format. 183 | 184 | Where the time is encoded in the same format used in set/get device time procedure, see [terminal.md](./terminal.md). 185 | 186 | Finally send the enable device command to put the device in normal operation: 187 | 188 | > packet(id=CMD_ENABLEDEVICE) 189 | > packet(id=CMD_ACK_OK) 190 | 191 | **Note**: Codification of operation IDs and corresponding param interpretation, remains as a ToDo. 192 | 193 | ### Example Operation Record Entry ### 194 | 195 | Here the operation id is 6, the encoded time is `0x23689BC2`, param1 is `0x0003`, param2 is `0x0000`, param3 is `0x0007` and param4 is `0x0502`. 196 | 197 | 00000000: 00 00 06 2A C2 9B 68 23 03 00 00 00 07 00 02 05 ...*..h#........ 198 | 199 | ## Clear All Operation Records ## 200 | 201 | To clear the operation records, first disable the device, then send a `CMD_CLEAR_OPLOG` command, refresh the data and finally enable the device. 202 | 203 | > packet(id=CMD_DISABLEDEVICE) 204 | > packet(id=CMD_ACK_OK) 205 | > packet(id=CMD_CLEAR_OPLOG) 206 | > packet(id=CMD_ACK_OK) 207 | > packet(id=CMD_REFRESHDATA) 208 | > packet(id=CMD_ACK_OK) 209 | > packet(id=CMD_ENABLEDEVICE) 210 | > packet(id=CMD_ACK_OK) 211 | 212 | ## Clear Data ## 213 | 214 | To clear data on the device use the command `CMD_CLEAR_DATA`. 215 | 216 | > packet(id=CMD_DISABLEDEVICE) 217 | > packet(id=CMD_ACK_OK) 218 | > packet(id=CMD_CLEAR_DATA, data=) 219 | > packet(id=CMD_ACK_OK) 220 | > packet(id=CMD_REFRESHDATA) 221 | > packet(id=CMD_ACK_OK) 222 | 223 | The `data type` is just one byte with the type of data to delete: 224 | 225 | |Data |Value | 226 | |--- |--- | 227 | |Attendance records |1 | 228 | |Fingerprint templates |2 | 229 | |None |3 | 230 | |Operation records |4 | 231 | |User information |5 | 232 | 233 | If the data type is ommited the device will delete all the info. 234 | 235 | ## Refresh Data ## 236 | 237 | After uploading a fingerprint or changing the users data, send the refresh data command, so the changes take effect. 238 | 239 | > packet(id=CMD_REFRESHDATA) 240 | > packet(id=CMD_ACK_OK) 241 | 242 | -------------------------------------------------------------------------------- /sections/access.md: -------------------------------------------------------------------------------- 1 | # Access Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | Here is a list of SDK functions, from **Access.h** file, that shows which functions can be replicated with the current spec: 12 | 13 | |SDK function name |Described(X=Yes, O=No) |Notes| 14 | |--- |:---: |---| 15 | |GetUserGroup |**X** | | 16 | |SetUserGroup |**X** | | 17 | |GetTZInfo |**X** | | 18 | |SetTZInfo |**X** | | 19 | |GetUnlockGroups |**O** |Only applicable to BW devices.| 20 | |SetUnlockGroups |**O** |Only applicable to BW devices.| 21 | |SSR_SetUnLockGroup |**X** | | 22 | |SSR_GetUnlockGroup |**X** | | 23 | |GetGroupTZs |**O** |Only applicable to BW devices.| 24 | |SetGroupTZs |**O** |Only applicable to BW devices.| 25 | |SSR_GetGroupTZ |**X** | | 26 | |SSR_SetGroupTZ |**X** | | 27 | |GetGroupTZStr |**O** |Only applicable to BW devices.| 28 | |SetGroupTZStr |**O** |Only applicable to BW devices.| 29 | |GetUserTZs |**X** | | 30 | |SetUserTZs |**X** | | 31 | |GetUserTZStr |**X** | | 32 | |SetUserTZStr |**X** | | 33 | |ACUnlock |**X** | | 34 | |GetACFun |**O** |Todo.| 35 | |GetDoorState |**X** | | 36 | |UseGroupTimeZone |**X** |See set/get user timezone| 37 | |GetHoliday |**O** |Only applicable to BW devices.| 38 | |SetHoliday |**O** |Only applicable to BW devices.| 39 | |SSR_GetHoliday |**O** |Todo.| 40 | |SSR_SetHoliday |**O** |Todo.| 41 | |SetDaylight |**O** |Todo.| 42 | |GetDaylight |**O** |Todo.| 43 | 44 | ## Get User Group ## 45 | 46 | New users are by default in group 1, but a user may belong to 1 of 100 possible groups, to get the group to which a user belongs to, send the following command: 47 | 48 | > packet(id=CMD_USERGRP_RRQ, ) 49 | > packet(id=CMD_ACK_OK, ) 50 | 51 | Where `user sn` is a field 4 bytes long, where the first byte stores the user's internal index, as a number. 52 | 53 | The reply data field is 1 byte long, with the number of the group to which the user belongs. 54 | 55 | ## Set User Group ## 56 | 57 | To set a user in a group, send the following command: 58 | 59 | > packet(id=CMD_USERGRP_WRQ, ) 60 | > packet(id=CMD_ACK_OK) 61 | 62 | Where the command data field has the following fields: 63 | 64 | |Name |Description |Value[hex] |Size[bytes] |Offset | 65 | |--- |--- |--- |--- |--- | 66 | |user sn |User's internal index on machine. |varies |1 |0 | 67 | | |Fixed. |zeros |3 |1 | 68 | |group number |Group number, given as a number. |varies |1 |4 | 69 | 70 | 71 | ## Get TZ Info ## 72 | 73 | To request definition of a timezone send the command `CMD_TZ_RRQ`: 74 | 75 | > packet(id=CMD_TZ_RRQ, data=) 76 | > packet(id=CMD_ACK_OK, data=) 77 | 78 | Where the timezone index stores the number of the timezone to read, it is stored as a number of 4 bytes and in little endian format. 79 | 80 | The result,` timezone info`, stores the definition of the timezone: 81 | 82 | |Name |Description |Value[hex] |Size[bytes] |Offset | 83 | |--- |--- |--- |--- |--- | 84 | |timezone index |Stores the number of the requested timezone. |varies (<) |2 |0 | 85 | |sunday tz |Sunday timezone. |varies |4 |2 | 86 | |monday tz |Monday timezone. |varies |4 |6 | 87 | |tuesday tz |Tuesday timezone. |varies |4 |10 | 88 | |wednesday tz |Wednesday timezone. |varies |4 |14 | 89 | |thursday tz |Thursday timezone. |varies |4 |18 | 90 | |friday tz |Friday timezone. |varies |4 |22 | 91 | |saturday tz |Saturday timezone. |varies |4 |26 | 92 | | |Fixed |a71c |2 |30 | 93 | 94 | (<): Little endian format. 95 | 96 | Each timezone is stored in a special format. 97 | 98 | If the sequence is: 99 | 100 | B0 B1 B2 B3 101 | 102 | The timezone: 103 | 104 | (Start hour):(Start minute) TO (End hour):(End minute) 105 | 106 | Will be given by: 107 | 108 | B0:B1 TO B2:B3 109 | 110 | The numbers are given directly as numbers so there is no need for ascii conversion. 111 | 112 | ### Example ### 113 | 114 | This is a reply packet for a get timezone command: 115 | 116 | 00000000: 50 50 82 7D 28 00 00 00 D0 07 2F A5 12 63 27 00 PP.}(...../..c'. 117 | 00000010: 30 00 11 0C 11 0D 11 25 11 25 11 25 11 25 11 25 0......%.%.%.%.% 118 | 00000020: 11 25 11 25 11 25 11 25 11 25 11 23 11 24 A7 1C .%.%.%.%.%.#.$.. 119 | 120 | Here the timezone number is 48, and the sunday timezone is `17:12 TO 17:13`. 121 | 122 | ## Set TZ Info ## 123 | 124 | To change a timezone definition send a `CMD_TZ_WRQ`, with the new timezone definition: 125 | 126 | > packet(id=CMD_TZ_WRQ, data=) 127 | > packet(id=CMD_ACK_OK) 128 | > packet(id=CMD_REFRESHDATA) 129 | > packet(id=CMD_ACK_OK) 130 | 131 | The `new timezone info` structure is very similar to the structure given for a get operation, check the following table: 132 | 133 | |Name |Description |Value[hex] |Size[bytes] |Offset | 134 | |--- |--- |--- |--- |--- | 135 | |timezone index |Stores the number of the requested timezone. |varies (<) |4 |0 | 136 | |sunday tz |Sunday timezone. |varies |4 |4 | 137 | |monday tz |Monday timezone. |varies |4 |8 | 138 | |tuesday tz |Tuesday timezone. |varies |4 |12 | 139 | |wednesday tz |Wednesday timezone. |varies |4 |16 | 140 | |thursday tz |Thursday timezone. |varies |4 |20 | 141 | |friday tz |Friday timezone. |varies |4 |24 | 142 | |saturday tz |Saturday timezone. |varies |4 |28 | 143 | 144 | (<): Little endian format. 145 | 146 | To prohibit access for a whole day just use a start time bigger than the end time. 147 | 148 | ## Get Unlock Combination ## 149 | 150 | Group verification may be used to require that users from different groups verify at same to grant access, by default users use the unlock combination 01 00 00 00 00, which means that only a user of the group 1 (themselves) is needed to grant access. 151 | 152 | There may be 10 unlock combinations, to request an unlock combination send the command `CMD_ULG_RRQ` with the combination number to request. 153 | 154 | > packet(id=CMD_ULG_RRQ, ) 155 | > packet(id=CMD_ACK_OK, ) 156 | 157 | The structure `` has the following fields 158 | 159 | |Name |Description |Value[hex] |Size[bytes] |Offset | 160 | |--- |--- |--- |--- |--- | 161 | |comb no |Combination number. |varies |1 |0 | 162 | | |Fixed. |zeros |7 |1 | 163 | 164 | And the response has the following fields: 165 | 166 | |Name |Description |Value[hex] |Size[bytes] |Offset | 167 | |--- |--- |--- |--- |--- | 168 | |comb no |Combination number. |varies |1 |0 | 169 | |group1 |Group 1 of combination.|varies |1 |1 | 170 | |group2 |Group 2 of combination.|varies |1 |2 | 171 | |group3 |Group 3 of combination.|varies |1 |3 | 172 | |group4 |Group 4 of combination.|varies |1 |4 | 173 | |group5 |Group 5 of combination.|varies |1 |5 | 174 | |valid groups |Number of valid groups.|varies (<) |2 |6 | 175 | 176 | (<): Little endian format. 177 | 178 | The `valid groups` field indicates how many groups are included in the current combianation, if that number is less than 5, then the unused values are set to 0. 179 | 180 | ### Example ### 181 | 182 | This is a reply of a get unlock combination command: 183 | 184 | 00000000: 50 50 82 7D 10 00 00 00 D0 07 B5 93 12 63 5D 00 PP.}.........c]. 185 | 00000010: 07 01 02 00 00 00 02 00 ........ 186 | 187 | The combination 7 only has two groups, 1 and 2. 188 | 189 | ## Set Unlock Combination ## 190 | 191 | To set an unlock combination send the command `CMD_ULG_WRQ`. 192 | 193 | > packet(id=CMD_ULG_WRQ, ) 194 | > packet(id=CMD_ACK_OK) 195 | > packet(id=CMD_REFRESHDATA) 196 | > packet(id=CMD_ACK_OK) 197 | 198 | Where the data field `comb grps`, has the same fields of the response for the get unlock combination command. 199 | 200 | ## Get Group Info ## 201 | 202 | To request parameters of a group, like the timezones, verify style and valid holidays flag, send the `CMD_GRPTZ_RRQ` command: 203 | 204 | > packet(id=CMD_GRPTZ_RRQ, ) 205 | > packet(id=CMD_ACK_OK, ) 206 | 207 | Where the `grp req` has the following fields: 208 | 209 | |Name |Description |Value[hex] |Size[bytes] |Offset | 210 | |--- |--- |--- |--- |--- | 211 | |group no |Group number. |varies |1 |0 | 212 | | |Fixed. |zeros |7 |1 | 213 | 214 | The response data field, `grp settings`, has the following fields: 215 | 216 | |Name |Description |Value[hex] |Size[bytes] |Offset | 217 | |--- |--- |--- |--- |--- | 218 | |group no |Group number. |varies |1 |0 | 219 | |tz 1 |Timezone 1. |varies (<) |2 |1 | 220 | |tz 2 |Timezone 2. |varies (<) |2 |3 | 221 | |tz 3 |Timezone 3. |varies (<) |2 |5 | 222 | |verify+holiday |Sets the verify style and carries the holiday flag. |varies |1 |7 | 223 | 224 | (<): Little endian format. 225 | 226 | The field `verify+holiday` may be further broken down in the following fields: 227 | 228 | |B7 |B6-B0 | 229 | |--- |--- | 230 | |Holiday enable flag |Verify style. | 231 | 232 | If the holiday flag is equal to 1, the holidays are considered. 233 | 234 | The verifiy style is almost the same codification used in the user verification mode, the only difference is the bit `B7`. 235 | 236 | |Verification Mode(x) |Value[base 10] |Value[hex] | 237 | |--- |--- |--- | 238 | |FP+PW+RF |0 |0 | 239 | |FP |1 |1 | 240 | |PIN |2 |2 | 241 | |PW |3 |3 | 242 | |RF |4 |4 | 243 | |FP+PW |5 |5 | 244 | |FP+RF |6 |6 | 245 | |PW+RF |7 |7 | 246 | |PIN&FP |8 |8 | 247 | |FP&PW |9 |9 | 248 | |FP&RF |10 |a | 249 | |PW&RF |11 |b | 250 | |FP&PW&RF |12 |c | 251 | |PIN&FP&PW |13 |d | 252 | |FP&RF+PIN |14 |e | 253 | 254 | ### Example ### 255 | 256 | This is a reply packet of a get group info command: 257 | 258 | 00000000: 50 50 82 7D 10 00 00 00 D0 07 79 F1 12 63 56 00 PP.}......y..cV. 259 | 00000010: 4D 08 00 07 00 06 00 8E M....... 260 | 261 | In this case the group 77 has the timezones 8,7 and 6, the verification style is `FP&RF+PIN` and the holiday flag is set. 262 | ## Set Group Info ## 263 | 264 | To create or modify an existing group send a command `CMD_GRPTZ_WRQ` with the new settings: 265 | 266 | > packet(id=CMD_GRPTZ_WRQ, ) 267 | > packet(id=CMD_ACK_OK) 268 | > packet(id=CMD_REFRESHDATA) 269 | > packet(id=CMD_ACK_OK) 270 | 271 | Where the data field `grp settings` has the same fields given on the get group info procedure. 272 | 273 | ## Get User Timezones ## 274 | 275 | To request the user timezones send a `CMD_USERTZ_RRQ` command with the user index. 276 | 277 | > packet(id=CMD_USERTZ_RRQ, ) 278 | > packet(id=CMD_ACK_OK, ) 279 | 280 | Where the `usertz req` is only the user's internal index on machine, followed by 3 zeros. 281 | 282 | |Name |Description |Value[hex] |Size[bytes] |Offset | 283 | |--- |--- |--- |--- |--- | 284 | |user sn |Users internal index. |varies |1 |0 | 285 | | |Fixed. |zeros |3 |1 | 286 | 287 | The structure `user tz` has the following fields: 288 | 289 | |Name |Description |Value[hex] |Size[bytes] |Offset | 290 | |--- |--- |--- |--- |--- | 291 | |group tz flag |Indicates wheter the user is using the group timezone (yes=1, no=0). |varies (<) |2 |0 | 292 | |tz 1 |Timezone 1 |varies (<) |2 |2 | 293 | |tz 2 |Timezone 2 |varies (<) |2 |4 | 294 | |tz 3 |Timezone 3 |varies (<) |2 |6 | 295 | 296 | (<): Little endian format. 297 | 298 | If the user has less than 3 timezones, the unused fields are set to zero. 299 | 300 | To check if the user is using the group's timezones, just request the user timezones and check the flag `group tz flag`. 301 | 302 | ## Set User Timezones ## 303 | 304 | To set user's timezones use the command `CMD_USERTZ_WRQ`: 305 | 306 | > packet(id=CMD_USERTZ_WRQ, ) 307 | > packet(id=CMD_ACK_OK) 308 | > packet(id=CMD_REFRESHDATA) 309 | > packet(id=CMD_ACK_OK) 310 | 311 | Where the `new tz` structure has the following fields: 312 | 313 | |Name |Description |Value[hex] |Size[bytes] |Offset | 314 | |--- |--- |--- |--- |--- | 315 | |user sn |Users internal index. |varies (<) |4 |0 | 316 | |user tz flag |Indicates wheter the user is using the his own timezones (yes=1, no=0).|varies (<) |4 |4 | 317 | |tz 1 |Timezone 1 |varies (<) |4 |8 | 318 | |tz 2 |Timezone 2 |varies (<) |4 |12 | 319 | |tz 3 |Timezone 3 |varies (<) |4 |16 | 320 | 321 | If there are less than 3 timezones, the unused fields are set to zero. 322 | 323 | To make the user use the group's timezones just sent a `new tz` structure with the `user tz flag` and timezones, set to zero. 324 | 325 | ## Door Unlock ## 326 | 327 | Send the command `CMD_UNLOCK` to open the door, the doors remains open for the specified delay(seconds). 328 | 329 | > packet(id=CMD_UNLOCK, data=) 330 | > packet(id=CMD_ACK_OK) 331 | 332 | Where the delay is given as a 4 byte number stored in little endian format. 333 | 334 | ## Get Door State ## 335 | 336 | To request the door state send the command `CMD_DOORSTATE_RRQ` 337 | 338 | 339 | > packet(id=CMD_DOORSTATE_RRQ) 340 | > packet(id=CMD_ACK_OK, data=) 341 | 342 | Where the `door flag` is just one byte with the value 1 if the door is open, otherwise if the door is closed, the value is 0. 343 | 344 | [Go to Main Page](../protocol.md) 345 | -------------------------------------------------------------------------------- /sections/data-user.md: -------------------------------------------------------------------------------- 1 | # User Data Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | Here is a list of SDK functions, from **Data-User.h** file, that shows which functions can be replicated with the current spec: 12 | 13 | 14 | |SDK function name |Described(X=Yes, O=No) |Notes| 15 | |--- |:---: |---| 16 | |ReadAllUserID |**X** | | 17 | |GetAllUserID |**O** |Applicable only to BW.| 18 | |GetAllUserInfo |**O** |Applicable only to BW.| 19 | |EnableUser |**O** |Applicable only to BW.| 20 | |SSR_EnableUser |**X** | | 21 | |ModifyPrivilege |**O** |Applicable only to BW.| 22 | |SetUserInfo |**O** |Applicable only to BW.| 23 | |GetUserInfo |**O** |Applicable only to BW.| 24 | |SetUserInfoEx |**X** | | 25 | |GetUserInfoEx |**X** | | 26 | |DeleteUserInfoEx |**X** |Same as using SetUserInfoEx with value 0.| 27 | |SSR_GetAllUserInfo |**X** |Operates on the info obtained with ReadAllUserID.| 28 | |SSR_GetUserInfo |**X** |Operates on the info obtained with ReadAllUserID.| 29 | |SSR_SetUserInfo |**X** | | 30 | |GetUserInfoByPIN2 |**O** |Applicable only to BW.| 31 | |GetUserInfoByCard |**O** |Applicable only to BW.| 32 | |GetUserIDByPIN2 |**O** |Applicable only to BW.| 33 | |GetPIN2 |**O** |Applicable only to BW.| 34 | |GetEnrollData |**O** |Applicable only to BW.| 35 | |SetEnrollData |**O** |Applicable only to BW.| 36 | |DeleteEnrollData |**O** |Applicable only to BW.| 37 | |SSR_DeleteEnrollData |**X** |See Delete Enroll Data.| 38 | |SSR_DeleteEnrollDataExt|**X** |See Delete Enroll Data.| 39 | |GetEnrollDataStr |**O** |Applicable only to BW.| 40 | |SetEnrollDataStr |**O** |Applicable only to BW.| 41 | |ReadAllTemplate |**X** | | 42 | |DelUserTmp |**O** |Applicable only to BW.| 43 | |SSR_DelUserTmp |**X** |See Delete Enroll Data.| 44 | |SSR_SetUserTmpExt |**X** | | 45 | |GetUserTmp |**O** |Applicable only to BW.| 46 | |SetUserTmp |**O** |Applicable only to BW.| 47 | |GetUserTmpStr |**O** |Applicable only to BW.| 48 | |SetUserTmpStr |**O** |Applicable only to BW.| 49 | |GetUserTmpEx |**X** |May be done individually(see Get Fingerprint Template) or with all the templates in memory(see Read All Templates).| 50 | |SetUserTmpEx |**X** | | 51 | |GetUserTmpExStr |**X** |See Get Fingerprint Template.| 52 | |SetUserTmpExStr |**X** |See Upload Fingerprint Template.| 53 | |SSR_GetUserTmp |**X** |See Get Fingerprint Template.| 54 | |SSR_GetUserTmpStr |**X** |See Get Fingerprint Template.| 55 | |SSR_SetUserTmp |**X** |See Upload Fingerprint Template.| 56 | |SSR_SetUserTmpStr |**X** |See Upload Fingerprint Template.| 57 | |GetFPTempLength |**O** |Nothing to do with the machine.| 58 | |GetFPTempLengthStr |**O** |Nothing to do with the machine.| 59 | |FPTempConvert |**O** |Nothing to do with the machine.| 60 | |FPTempConvertStr |**O** |Nothing to do with the machine.| 61 | |FPTempConvertNew |**O** |Nothing to do with the machine.| 62 | |FPTempConvertNewStr |**O** |Nothing to do with the machine.| 63 | |SetUserFace |**O** |Applicable only to iFace devices. 64 | |GetUserFace |**O** |Applicable only to iFace devices. 65 | |DelUserFace |**O** |Applicable only to iFace devices. 66 | |GetUserFaceStr |**O** |Applicable only to iFace devices. 67 | |SetUserFaceStr |**O** |Applicable only to iFace devices. 68 | 69 | 70 | ## Read All User IDs ## 71 | 72 | With this procedure the users info can be obtained, except the fingerprint templates. 73 | 74 | First disable the device: 75 | 76 | > packet(id=CMD_DISABLEDEVICE) 77 | > packet(id=CMD_ACK_OK) 78 | 79 | Then send a command with the id `CMD_DATA_WRRQ` and with a fixed payload of 11 bytes, field description for this payload it is still unknown. 80 | 81 | packet(id=CMD_DATA_WRRQ, data=0109000500000000000000) 82 | 83 | Depending of the size of the users info structure, the device may send this info in two ways: 84 | 85 | 1.For "small" structures, the machine would send the info structure immediately 86 | 87 | > packet(id=CMD_DATA_WRRQ, data=0109000500000000000000) 88 | > packet(id=CMD_DATA, data=) 89 | 90 | 2.For bigger structures see the [Exchange of Data](ex_data.md) spec. 91 | 92 | The fields of the `users info` structure are given in the following table: 93 | 94 | |Name |Description |Value[hex] |Size[bytes] |Offset | 95 | |--- |--- |--- |--- |--- | 96 | |size users info|Total size of user info entries. |N*72 (<) |4 |0 | 97 | |user1 entry |Info of user 1. |varies |72 |4 | 98 | |user2 entry |Info of user 2. |varies |72 |76 | 99 | |... |... |varies |72 |... | 100 | |userN entry |info of user N. |varies |72 |info_size-72+4 | 101 | 102 | (<): Little endian format. 103 | 104 | The contents of each user entry, are shown in the next table: 105 | 106 | |Name |Description |Value[hex] |Size[bytes] |Offset | 107 | |--- |--- |--- |--- |--- | 108 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 109 | |permission token |Sets permission for the given user and carries enable flag. |varies |1 |2 | 110 | |password |User password, stored as a string. |varies |8 |3 | 111 | |name(*) |User's name. |varies |24 |11 | 112 | |card number |User's card number, stored as int. |varies (<) |4 |35 | 113 | |group no |Group number to which the user belongs. |varies |1 |39 | 114 | |user tz flag |Indicates if the user is using his own's timezones. |varies (<) |2 |40 | 115 | |tz1 |User's timezone 1, integer. |varies (<)(t) |2 |42 | 116 | |tz2 |User's timezone 2. integer. |varies (<)(t) |2 |44 | 117 | |tz3 |User's timezone 3. integer. |varies (<)(t) |2 |46 | 118 | |user id |User ID, stored as a string. |varies |9 |48 | 119 | | |Fixed zeros. |00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |15 |57 | 120 | 121 | (<): Little endian format. 122 | 123 | (*): The name string should be terminated with the null char `\x00`, so the allowed size for user name is really 23 chars. 124 | 125 | (t): If a timezone it isn't used or the users it is using group's timezone, these values are set to zero. 126 | 127 | The permission token defines the permissions of the user and the also sets the state of the user. 128 | 129 | |Bit Offset |7-4 |3 |2 |1 |0 | 130 | |--- |--- |--- |--- |--- |--- | 131 | |-- |Unused |P2 |P1 |P0 |E0 | 132 | 133 | The number given by `P2P1P0` indicates the user admin level: 134 | 135 | |P2P1P0 |Level | 136 | |--- |--- | 137 | |000 |Common user | 138 | |001 |Enroll user | 139 | |011 |Admin | 140 | |111 |Super admin | 141 | 142 | The `E0` bit only enables/disables the user 143 | 144 | |E0 |State | 145 | |--- |--- | 146 | |0 |Eneabled | 147 | |1 |Disabled | 148 | 149 | Finally send the enable device command to put the device in normal operation: 150 | 151 | > packet(id=CMD_ENABLEDEVICE) 152 | > packet(id=CMD_ACK_OK) 153 | 154 | ### Example of a User Entry ### 155 | 156 | This is an example of user entry: 157 | 158 | 00000000: 0D 00 00 34 34 34 00 C6 9A 80 7C 4E 65 64 00 00 ...444....|Ned.. 159 | 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 160 | 00000020: 00 00 00 DE 00 00 00 02 01 00 01 00 02 00 00 00 ................ 161 | 00000030: 35 35 35 00 00 00 00 00 00 00 00 00 00 00 00 00 555............. 162 | 00000040: 00 00 00 00 00 00 00 00 ........ 163 | 164 | In this case we have that the user's internal index is `0x000D`, the password is "444", and it should be noted that the password field contains non-zero bytes after the termination char, these could bytes are simply ignored. 165 | 166 | From this entry we see that the user's name is "Ned", his card number is `0x000000DE`, he belongs to the group 2, he is using his own timezones, 1 and 2, and his user id is "555". 167 | 168 | ## Enable User ## 169 | 170 | Same as Set User Info procedure, in this case just the bit `E0` should be changed. 171 | 172 | ## Set User Verification Mode ## 173 | 174 | To change the verification style of a given user, use the `CMD_VERIFY_WRQ` command, this packet should be sent with the new verification style, using a specific codification. 175 | 176 | > packet(id=CMD_VERIFY_WRQ, data=) 177 | > packet(id=CMD_ACK_OK) 178 | 179 | Where the `verify info` structure, is 24 bytes long and has the following fields: 180 | 181 | |Name |Description |Value[hex] |Size[bytes] |Offset | 182 | |--- |--- |--- |--- |--- | 183 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 184 | |verification mode |Verification mode to be used, see next table. |varies |1 |2 | 185 | | |Fixed zeros. |zeros |21 |3 | 186 | 187 | (<): Little endian format. 188 | 189 | |Verification Mode(x) |Value[base 10] |Value[hex] | 190 | |--- |--- |--- | 191 | |Group Verify |0 |0 | 192 | |FP+PW+RF |128 |80 | 193 | |FP |129 |81 | 194 | |PIN |130 |82 | 195 | |PW |131 |83 | 196 | |RF |132 |84 | 197 | |FP+PW |133 |85 | 198 | |FP+RF |134 |86 | 199 | |PW+RF |135 |87 | 200 | |PIN&FP |136 |88 | 201 | |FP&PW |137 |89 | 202 | |FP&RF |138 |8a | 203 | |PW&RF |139 |8b | 204 | |FP&PW&RF |140 |8c | 205 | |PIN&FP&PW |141 |8d | 206 | |FP&RF+PIN |142 |8e | 207 | 208 | (x): The symbol "+" is used as a logic **or**, that means the verification may be performed in either way, while the symbol "&" is used as logic **and**, that means the verication needs both methods to be accepted. 209 | 210 | ### Example ### 211 | 212 | In this case the user with the index `0x000D` is set to use the PIN&FP&PW verification style. 213 | 214 | 00000000: 50 50 82 7D 20 00 00 00 4F 00 EA 79 E7 84 45 00 PP.} ...O..y..E. 215 | 00000010: 0D 00 8D 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 216 | 00000020: 00 00 00 00 00 00 00 00 217 | 218 | ## Get User Verification Mode ## 219 | 220 | To get the verification style of a given user, use the `CMD_VERIFY_RRQ` command. 221 | 222 | > packet(id=CMD_VERIFY_RRQ, ) 223 | > packet(id=CMD_ACK_OK, data=) 224 | 225 | Where the `user sn` field identifies the user, the value is stored in a 2 byte field in little endian format. 226 | 227 | The `verify info` is the same structure used for the "Set User Verification Mode" procedure. 228 | 229 | ## Set User Info ## 230 | 231 | This procedure is used to modify info of existing users, if the user doesn't exist, then it will be created. 232 | 233 | Here is a list of the parameters that may be changed with this procedure: 234 | 235 | - User ID. 236 | - User name. 237 | - User password. 238 | - User admin level. 239 | - Enable state. 240 | 241 | The idea is to send a new user entry to overwrite the previous user data, to do this first disable the device, use the `CMD_USER_WRQ` command to send the new user entry, which has the same fields shown in the "Read All User IDs" section. Finally refresh the data and enable the device. 242 | 243 | > packet(id=CMD_DISABLEDEVICE) 244 | > packet(id=CMD_ACK_OK) 245 | > packet(id=CMD_USER_WRQ, data=) 246 | > packet(id=CMD_ACK_OK) 247 | > packet(id=CMD_REFRESHDATA) 248 | > packet(id=CMD_ACK_OK) 249 | > packet(id=CMD_ENABLEDEVICE) 250 | > packet(id=CMD_ACK_OK) 251 | 252 | ### Example ### 253 | 254 | In this example, a `new entry` structure is shown, the user index is `0x000E`, the user is enabled and set with admin permissions `0x06`, is using password "123456", his name is "Nuevo", his card number is `6543`, belongs to group 1, it is using group's timezones, and his id number is "11224488". 255 | 256 | 00000000: 50 50 82 7D 50 00 00 00 08 00 FC 57 9D 8A 5C 00 PP.}P......W..\. 257 | 00000010: 0E 00 06 31 32 33 34 35 36 00 7C 4E 75 65 76 6F ...123456.|Nuevo 258 | 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 259 | 00000030: 00 00 00 8F 19 00 00 01 00 00 00 00 00 00 00 00 ................ 260 | 00000040: 31 31 32 32 34 34 38 38 00 00 00 00 00 00 00 00 11224488........ 261 | 00000050: 00 00 00 00 00 00 00 00 262 | 263 | ## Delete Enroll Data ## 264 | 265 | The SDK provides functions to delete: 266 | 267 | 1. Individual fingerprint templates. 268 | 2. Delete the password and if no fingerprint data or password exist, then also remove the user. 269 | 3. Delete all the fingerprint templates of a given user. 270 | 4. Delete a user. 271 | 272 | These options are based on the following basic operations: 273 | 274 | 1. Delete indivitual fingerprint templates. 275 | 2. Delete password. 276 | 3. Delete all fingerprint templates. 277 | 4. Delete user. 278 | 5. Get fingerprint template. 279 | 280 | These procedures are explained below. 281 | 282 | ### Deleting a Fingerprint Template ### 283 | 284 | To delete one fingerprint of a given user, follow the next procedure: 285 | 286 | > packet(id=CMD_DEL_FPTMP, data=) 287 | > packet(id=CMD_ACK_OK) 288 | > packet(id=CMD_REFRESHDATA) 289 | > packet(id=CMD_ACK_OK) 290 | 291 | Where the `del info` structure includes data about the fingerprint to delete: 292 | 293 | |Name |Description |Value[hex] |Size[bytes] |Offset | 294 | |--- |--- |--- |--- |--- | 295 | |user id |User's id given as a string. |varies |user-id width |0 | 296 | |zeros |Fixed. | | |user-id width | 297 | |finger index |Fingerprint index. |varies |1 |24 | 298 | 299 | ### Delete Password ### 300 | 301 | This can be easily done with the set user info procedure, just overwrite the password with zeros. 302 | 303 | ### Delete All Fingerprint Templates ### 304 | 305 | To delete all fingerprint templates of a given user, follow the next procedure: 306 | 307 | > packet(id=CMD_DELETE_USERTEMP, data=) 308 | > packet(id=CMD_ACK_OK) 309 | > packet(id=CMD_REFRESHDATA) 310 | > packet(id=CMD_ACK_OK) 311 | 312 | Where the `del all info` structure specifies the user: 313 | 314 | |Name |Description |Value[hex] |Size[bytes] |Offset | 315 | |--- |--- |--- |--- |--- | 316 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 317 | | |Fixed. |00 |1 |2 | 318 | 319 | (<): Little endian format. 320 | 321 | ### Delete User ### 322 | 323 | To delete a user, follow the next procedure: 324 | 325 | > packet(id=CMD_DELETE_USER, data=) 326 | > packet(id=CMD_ACK_OK) 327 | > packet(id=CMD_REFRESHDATA) 328 | > packet(id=CMD_ACK_OK) 329 | 330 | Where the` user sn` identifies the user, the value is stored in a 2 byte field in little endian format. 331 | 332 | ### Get Fingerprint Template ### 333 | 334 | The SDK uses this function, when deleting users data, to check if the user has other fingerprint templates, it requests all the fingerprints one by one. 335 | 336 | The procedure uses the command `CMD_USERTEMP_RRQ`, to ask for a template: 337 | 338 | > packet(id=CMD_USERTEMP_RRQ, data=, reply number=) 339 | > packet(id=CMD_PREPARE_DATA, data=, reply number=) 340 | > packet(id=CMD_DATA, data=, reply number=) 341 | > packet(id=CMD_ACK_OK, reply number=) 342 | 343 | Where the `fp tmp req` structure has the following fields: 344 | 345 | |Name |Description |Value[hex] |Size[bytes] |Offset | 346 | |--- |--- |--- |--- |--- | 347 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 348 | |finger index |Fingerprint index, stored as a number (0-9). |varies |1 |2 | 349 | 350 | And `dataset`, is just the binary fingerprint template, without any additional fields. 351 | 352 | If the template doesn't exist, the device would reply with `CMD_ACK_ERROR`. 353 | 354 | > packet(id=CMD_USERTEMP_RRQ, data=) 355 | > packet(id=CMD_ACK_ERROR) 356 | 357 | ## Read All Templates ## 358 | 359 | Follow the next procedure to get all the fingerprint templates. 360 | 361 | First disable the device: 362 | 363 | > packet(id=CMD_DISABLEDEVICE) 364 | > packet(id=CMD_ACK_OK) 365 | 366 | Then send a command with the id `CMD_DATA_WRRQ` and with a fixed payload, field description for this payload it is still unknown. 367 | 368 | packet(id=CMD_DATA_WRRQ, data=0107000200000000000000) 369 | 370 | Depending of the size of the `fp templates` structure, the device may send this info in two ways: 371 | 372 | 1.For "small" structures, the machine would send the info structure immediately 373 | 374 | > packet(id=CMD_DATA_WRRQ, data=0107000200000000000000) 375 | > packet(id=CMD_DATA, data=) 376 | 377 | 2.For bigger structures see the [Exchange of Data](ex_data.md) spec. 378 | 379 | The fields of the `fp templates` structure are given in the following table: 380 | 381 | |Name |Description |Value[hex] |Size[bytes] |Offset | 382 | |--- |--- |--- |--- |--- | 383 | |total size of fptmps |Total size fp template entries.|varies (<) |4 |0 | 384 | |template1 entry |Fingerprint template 1. |varies |varies(+) |4 | 385 | |template2 entry |Fingerprint template 2. |varies |varies(+) |varies | 386 | |... |... |... |... |varies | 387 | |templateN entry |Fingerprint template N. |varies |varies(+) |varies | 388 | 389 | (<): Little endian format. 390 | (+): The size of each template is at the beginning of each template entry. 391 | 392 | The contents of each template entry, are shown in the next table: 393 | 394 | |Name |Description |Value[hex] |Size[bytes] |Offset | 395 | |--- |--- |--- |--- |--- | 396 | |size tmp entry |Size of fp template entry. |(tmp size + 6) (<) |2 |0 | 397 | |user sn |Internal serial number for the user. |varies (<) |2 |2 | 398 | |fp index |Fingerprint index, stored as a number (0-9). |varies |1 |4 | 399 | |fp flag |Fingerprint flag. |varies |1 |5 | 400 | |fp template |The binary fingerprint template. |varies |tmp size |6 | 401 | 402 | (<): Little endian format. 403 | 404 | The fp flag indicates fingerprint type: 405 | 406 | |Fingerprint |Value | 407 | |--- |--- | 408 | |invalid |0 | 409 | |valid |1 | 410 | |duress |3 | 411 | 412 | Finally send the enable device command to put the device in normal operation: 413 | 414 | > packet(id=CMD_ENABLEDEVICE) 415 | > packet(id=CMD_ACK_OK) 416 | 417 | Note that in order to know which user is the owner of a fingerprint you should read all the users info. 418 | 419 | ### Example of a Template Entry ### 420 | 421 | In this example, only the first 24 bytes are shown, the template entry is `0x04C4` bytes long, belongs to the user with index `0x000E`, the finger index is 4 and it is a valid fingerprint. 422 | 423 | 00000000: C4 04 0E 00 04 01 4D FD 53 53 32 31 00 00 04 BE ......M.SS21.... 424 | 00000010: BE 04 08 05 07 09 CE D0 ... 425 | 426 | ## Upload Fingerprint Template ## 427 | 428 | Follow the next procedure to upload a fingerprint template. 429 | 430 | First disable the device: 431 | 432 | > packet(id=CMD_DISABLEDEVICE) 433 | > packet(id=CMD_ACK_OK) 434 | 435 | Upload a fingerprint template with the following sequence: 436 | 437 | > packet(id=CMD_PREPARE_DATA, data=) 438 | > packet(id=CMD_ACK_OK) 439 | > packet(id=CMD_DATA, data=) 440 | > packet(id=CMD_ACK_OK) 441 | > packet(id=CMD_CHECKSUM_BUFFER) 442 | > packet(id=CMD_ACK_OK, data=) 443 | > packet(id=CMD_TMP_WRITE, data=) 444 | > packet(id=CMD_ACK_OK) 445 | > packet(id=CMD_FREE_DATA) 446 | > packet(id=CMD_ACK_OK) 447 | 448 | The `prep struct` indicates the size of the data to send, it has the following fields: 449 | 450 | |Name |Description |Value[hex] |Size[bytes] |Offset | 451 | |--- |--- |--- |--- |--- | 452 | |data size |Size of the data to send. |(fp template size) (<) |2 |0 | 453 | | |Fixed. |0000 |2 |2 | 454 | 455 | (<): Little endian format. 456 | 457 | How the checksum is calculated is unknown, to check for a correct write operation, one may request the written fingerprint and apply a custom checksum to compare both templates. 458 | 459 | The command `CMD_TMP_WRITE` seems to be the command that transfers the buffer contents to the proper location of fingerprint templates. 460 | 461 | The `tmp wreq` structure has the following fields: 462 | 463 | |Name |Description |Value[hex] |Size[bytes] |Offset | 464 | |--- |--- |--- |--- |--- | 465 | |user sn |Internal serial number for the user. |varies (<) |2 |0 | 466 | |fp index |Fingerprint index, stored as a number (0-9). |varies |1 |2 | 467 | |fp flag |Fingerprint flag. |varies |1 |3 | 468 | |fp template size |Size of the fingerprint template. |varies (<) |2 |4 | 469 | 470 | (<): Little endian format. 471 | 472 | The previous sequence should be executed for every upload, if there are no more templates to upload, refresh the data and then enable the device: 473 | 474 | > packet(id=CMD_REFRESHDATA) 475 | > packet(id=CMD_ACK_OK) 476 | > packet(id=CMD_ENABLEDEVICE) 477 | > packet(id=CMD_ACK_OK) 478 | 479 | [Go to Main Page](../protocol.md) 480 | -------------------------------------------------------------------------------- /sections/terminal.md: -------------------------------------------------------------------------------- 1 | # Terminal Operations # 2 | 3 | [Go to Main Page](../protocol.md) 4 | 5 | Author: Alexander Marin 6 | 7 | [TOC] 8 | 9 | ## Current Descriptions ## 10 | 11 | Here is a list of SDK functions, from **Terminal.h** and **Property.h** files, that shows which functions can be replicated with the current spec: 12 | 13 | |SDK function name |Described (X=Yes, O=No)|Notes | 14 | |--- |:---: |--- | 15 | |Connect_Net |**X** |Without communication key. | 16 | |Connect_Com |**O** |The serial communication it isn't considered. | 17 | |Connect_USB |**O** |The USB communication it isn't considered. | 18 | |Disconnect |**X** |Only for TCP/IP. | 19 | |IsTFTMachine |**X** |Same result can be obtained with GetPlatform function. | 20 | |GetDeviceStatus |**X** | | 21 | |GetDeviceInfo |**X** |See Generic Requests section. | 22 | |SetDeviceInfo |**X** |See Generic Requests section. | 23 | |GetDeviceTime |**X** | | 24 | |SetDeviceTime |**X** | | 25 | |GetSerialNumber |**X** |See Generic Requests section. | 26 | |GetProductCode |**X** |See Generic Requests section. | 27 | |GetFirmwareVersion |**X** | | 28 | |GetSDKVersion |**O** |This has nothing to do with the machine. | 29 | |GetDeviceIP |**O** |Irrelevant. | 30 | |SetDeviceIP |**O** |Irrelevant. | 31 | |GetDeviceMAC |**O** |Irrelevant. | 32 | |SetDeviceMAC |**O** |Irrelevant. | 33 | |GetWiegandFmt |**O** |Irrelevant. | 34 | |SetWiegandFmt |**O** |Irrelevant. | 35 | |GetCardFun |**X** |See Generic Requests section. | 36 | |SetDeviceCommPwd |**O** |Connection with commkey is not supported. | 37 | |SetCommPassword |**O** |Connection with commkey is not supported. | 38 | |QueryState |**X** | | 39 | |GetVendor |**X** |See Generic Requests section. | 40 | |GetDeviceStrInfo |**X** |See Generic Requests section. | 41 | |GetPlatform |**X** |See Generic Requests section. | 42 | |GetStrCardNumber |**O** |This is for BW devices. | 43 | |SetStrCardNumber |**O** |This is for BW devices. | 44 | |IsNewFirmwareMachine |**O** |Same result can be obtained with GetPlatform function. | 45 | |GetDeviceFirmwareVersion |**O** |This is only for newer firmware. | 46 | 47 | ## Connection ## 48 | 49 | In this document only connection using TCP/IP is considered. 50 | 51 | ### Without Communication Key ### 52 | 53 | To set a connection with the device we first need de ip address of the device, that can be manually set in the standalone machine. 54 | 55 | First you need to setup a socket connection, using TCP/IP, with the given ip address and with the port 4370. 56 | 57 | Then send a packet with the command `CMD_CONNECT`. 58 | 59 | packet(id=CMD_CONNECT) 60 | 61 | Keep in mind that for this packet the session id and reply number, must be zero, since the session id hasn't been assigned by the machine, and the reply number starts at zero. 62 | 63 | The device should reply with the reply code `CMD_ACK_OK`. 64 | 65 | packet(id=CMD_ACK_OK) 66 | 67 | Keep in mind that the reply number must be the same of the sent packet(zero), but the session id is defined with this packet, the client should parse and store the session id from this reply packet. 68 | 69 | After sending the connection command is acknowledged, set the SDKBuild parameter to 1 using a `CMD_OPTIONS_WRQ` command. 70 | 71 | > packet(id=CMD_OPTIONS_WRQ, data="SDKBuild=1\x00") 72 | > packet(id=CMD_ACK_OK) 73 | 74 | ### With Communication Key ### 75 | 76 | When a communication key is set in the device, and if the device doesn't receive the corresponding key, then it will reply with the reply code `CMD_ACK_UNAUTH`, that means that the connection hasn't been authorized. 77 | 78 | To do this a packet with the command `CMD_AUTH` must be sent, the data field carries the communication key, the problem is that the key appears to be hashed, and the hash function it isn't known yet, but it seems that it depends on the session id of the machine reply, so currently there is no way to reproduce this procedure. Though this feature it isn't very useful, it only prevents other clients to send commands to the machine, but if someone have access to the network, it may still see all the trafic, since the communication it isn't encrypted, given that case, an attacker could capture the hashed value, discover the hashing function through disassembling, get the commkey and then send the correct hash, given a session id, to start a session and then send commands (like unlock door). **Therefore the network used for the system must be dedicated and kept away from intruders**. 79 | 80 | ## Disconnection ## 81 | 82 | To terminate a connection with a device just send packet with command `CMD_EXIT`. 83 | 84 | > packet(id=CMD_EXIT) 85 | > packet(id=CMD_ACK_OK) 86 | 87 | Keep in mind that the session id and reply number must be consistent with previous steps. 88 | 89 | After that you may terminate the socket connection. 90 | 91 | ## Get Device Status ## 92 | 93 | To request status info from device, a disable command `CMD_DISABLEDEVICE` must be sent first, after that the device should reply with the command `CMD_ACK_OK`, then send the command `CMD_GET_FREE_SIZES`. 94 | 95 | The device should reply with a command with the code `CMD_ACK_OK` and a data structure of 92 bytes. 96 | 97 | Finally send the enable command `CMD_ENABLEDEVICE`, the device should reply with the `CMD_ACK_OK` code. 98 | 99 | > packet(id=CMD_DISABLEDEVICE) 100 | > packet(id=CMD_ACK_OK) 101 | > packet(id=CMD_GET_FREE_SIZES) 102 | > packet(id=CMD_ACK_OK, data=) 103 | > packet(id=CMD_ENABLEDEVICE) 104 | > packet(id=CMD_ACK_OK) 105 | 106 | Where **status** is the structure of 92 bytes with the relevant info, which has the following fields: 107 | 108 | |SDK Value |Name |Description |Position | 109 | |--- |--- |--- |--- | 110 | |1 |admin count |Number of administrators. |48 | 111 | |2 |user count |Number of registered users. |16 | 112 | |3 |fp count |Number of fingerprint templates on the machine.|24 | 113 | |4 |pwd count |Number of passwords. |52 | 114 | |5 |oplog count |Number of operation records. |40 | 115 | |6 |attlog count |Number of attendance records. |32 | 116 | |7 |fp capacity |Fingerprint template capacity. |56 | 117 | |8 |user capacity |User capacity. |60 | 118 | |9 |attlog capacity |Attendance record capacity. |64 | 119 | |10 |remaining fp |Remaining fingerprint template capacity. |68 | 120 | |11 |remaining user |Remaining user capacity. |72 | 121 | |12 |remaining attlog |Remaining attendance record capacity. |76 | 122 | |21 |face count |Number of faces. |80 | 123 | |22 |face capacity |Face capacity. |88 | 124 | 125 | **Note**: All the values are 4-Byte wide and stored in little endian format. 126 | 127 | The full data structure looks like this: 128 | 129 | |Offset(base 10) |0 |4 |8 |12 | 130 | |:---: |:---: |:---: |:---: |:---: | 131 | |**0** |0 |0 |0 |0 | 132 | |**16** |user count |0 |fp count |0 | 133 | |**32** |attlog count |0 |oplog count |0 | 134 | |**48** |admin count |pwd count |fp capacity |user capacity | 135 | |**64** |attlog capacity|remaining fp |remaining user |remaining attlog | 136 | |**80** |face count |0 |face capacity | 137 | 138 | The zeroed bytes can be seen as reserved bytes, some of them are actually accessed with the values [13,20] in the SDK function. 139 | 140 | ## Device Time ## 141 | 142 | Time is a very important parameter for access control, if the time is not set correctly the timezone settings will not work as expected. 143 | 144 | ### Get Time ### 145 | 146 | To request the device time send a `CMD_GET_TIME` command. 147 | 148 | packet(id=CMD_GET_TIME) 149 | 150 | The device should reply with `CMD_ACK_OK` code and a 4 byte integer with the device time, stored in little endian format. 151 | 152 | packet(id=CMD_ACK_OK, data=) 153 | 154 | Where `enc_t` is calculated with the following formula: 155 | 156 | ```python 157 | enc_t = ((year%100)*12*31+((month-1)*31)+day-1)*(24*60*60)+(hour*60+minutes)*60+seconds 158 | ``` 159 | Which is approximately the number of seconds since 29 Aug 1999. 160 | 161 | So to decode the date from this number, the following Python snippet may be used: 162 | 163 | ```python 164 | seconds = int(enc_t % 60) 165 | minutes = int((enc_t/60.)%60) 166 | hour = int((enc_t/(3600.))%24) 167 | day = int(((enc_t/(3600.*24.))%31))+1 168 | month = int(((enc_t/(3600.*24.*31.))%12))+1 169 | year = int((enc_t/(3600.*24.)) / 365)+2000 170 | ``` 171 | 172 | ### Set Time ### 173 | 174 | To change time send a packet with the command `CMD_SET_TIME` with a 4 byte integer with the new time, stored in little endian format, in the same format given for the get time function. 175 | 176 | After that the machine should reply with `CMD_ACK_OK`, to make changes take effect send a `CMD_REFRESHDATA` command to load the new value, the machine should reply with `CMD_ACK_OK`. 177 | 178 | This procedure can be summarized as follows: 179 | 180 | > packet(id=CMD_SET_TIME, data=) 181 | > packet(id=CMD_ACK_OK) 182 | > packet(id=CMD_REFRESHDATA) 183 | > packet(id=CMD_ACK_OK) 184 | 185 | ## Generic Requests ## 186 | 187 | The general procedure to read/write a list of parameters, is: 188 | 189 | 1. Disable the device with a `CMD_DISABLEDEVICE` command. 190 | 2. Read/write a set of parameters. 191 | 3. Enable the device with a `CMD_ENABLEDEVICE` command. 192 | 193 | ### Generic Read of Parameters ### 194 | 195 | Some parameters of the device can be requested with a separate command but there is a set of parameters that can be requested with the one command, `CMD_OPTIONS_RRQ`, and an specific argument, which would be the name of the parameter. 196 | 197 | > packet(id=CMD_OPTIONS_RRQ, data="\x00") 198 | > packet(id=CMD_ACK_OK, data="=\x00") 199 | 200 | **Notes**: 201 | 202 | - The param values are given in string format, that means that if a 1 is returned, it actually corresponds to `0x31`. 203 | - Booleans are represented with "1" and "0". 204 | - Integers are given as a string number in base 10. 205 | - Some of these values may not be present on the machine, in that case the machine would reply with `CMD_ACK_ERROR`. 206 | 207 | Here is a list of some parameters that can be requested using that format: 208 | 209 | |Parameter name |Returns | 210 | |--- |--- | 211 | |~Platform |Plaform name | 212 | |~ZKFPVersion |Integer | 213 | |ZKFaceVersion |- | 214 | |~OS |- | 215 | |~ExtendFmt |- | 216 | |ExtendOPLog |- | 217 | |WorkCode |Bool | 218 | |Language |Integer | 219 | |BiometricType |- | 220 | |FingerFunOn |Bool | 221 | |~IsOnlyRFMachine |Bool | 222 | |FaceFunOn |Bool | 223 | |~OEMVendor |Vendor name | 224 | |~DeviceName |Device name | 225 | |MAC |MAC address | 226 | |~SerialNumber |Serial number | 227 | |~ProductTime |Date string | 228 | |~PIN2Width |Integer | 229 | |~IsABCPinEnable |Bool | 230 | |~T9FunOn |Bool | 231 | 232 | ### Examples ### 233 | 234 | 1.Get platform(String): 235 | 236 | 00000000: 50 50 82 7D 12 00 00 00 0B 00 B9 E6 F3 8D 0C 00 PP.}............ 237 | 00000010: 7E 50 6C 61 74 66 6F 72 6D 00 ~Platform. 238 | 239 | The machine may reply: 240 | 241 | 00000000: 50 50 82 7D 1D 00 00 00 D0 07 71 4C F3 8D 0C 00 PP.}......qL.... 242 | 00000010: 7E 50 6C 61 74 66 6F 72 6D 3D 5A 45 4D 37 36 30 ~Platform=ZEM760 243 | 00000020: 5F 54 46 54 00 _TFT. 244 | 245 | 2.Get Worcode(Bool): 246 | 247 | 00000000: 50 50 82 7D 11 00 00 00 0B 00 84 C2 F3 8D 0B 00 PP.}............ 248 | 00000010: 57 6F 72 6B 43 6F 64 65 00 WorkCode. 249 | 250 | The machine may reply: 251 | 252 | 00000000: 50 50 82 7D 13 00 00 00 D0 07 82 8A F3 8D 0B 00 PP.}............ 253 | 00000010: 57 6F 72 6B 43 6F 64 65 3D 30 00 WorkCode=0. 254 | 255 | ### Get Serial Number ### 256 | 257 | To request the serial number of the device, send: 258 | 259 | > packet(id=CMD_OPTIONS_RRQ, data="~SerialNumber\x00") 260 | > packet(id=CMD_ACK_OK, data="~SerialNumber=\x00") 261 | 262 | ### Get Product Code ### 263 | 264 | To request the product code, send: 265 | 266 | > packet(id=CMD_OPTIONS_RRQ, data="~DeviceName\x00") 267 | > packet(id=CMD_ACK_OK, data="~DeviceName=\x00") 268 | 269 | ### Get Card Function ### 270 | 271 | This procedure comprises the request of two parameters: 272 | 273 | > packet(id=CMD_OPTIONS_RRQ, data="~IsOnlyRFMachine\x00") 274 | > packet(id=CMD_ACK_OK, data="~IsOnlyRFMachine=\x00") 275 | > packet(id=CMD_OPTIONS_RRQ, data="~RFCardOn\x00") 276 | > packet(id=CMD_ACK_OK, data="~RFCardOn=\x00") 277 | 278 | Where `is_rf` is a boolean variable, 1-Byte wide, that corresponds to 1 if the machine **only** supports RFID tags and 0 in the opposite case. The variable `card_on` is also a boolean variable, 1-Byte wide, that corresponds to 1 if the machine supports the RFID tags. 279 | 280 | According to the SDK: 281 | 282 | - The function returns 1 if the machine only supports the RF card. 283 | - The function returns 2 if the machine supports the RF card and fingerprints. 284 | - The function returns 0 if the machine doesn't support the RF card. 285 | 286 | That means that the value may be calculated with the next formula: 287 | 288 | return value = card_on * (1 + not(is_rf)) 289 | 290 | ### Get Vendor ### 291 | 292 | Procedure to request the vendor name: 293 | 294 | > packet(id=CMD_OPTIONS_RRQ, data="~OEMVendor\x00") 295 | > packet(id=CMD_ACK_OK, data="~OEMVendor=\x00") 296 | 297 | ### Get Device String Info ### 298 | 299 | Procedure to request the product time: 300 | 301 | > packet(id=CMD_OPTIONS_RRQ, data="~ProductTime\x00") 302 | > packet(id=CMD_ACK_OK, data="~ProductTime=yyyy-mm-dd HH:MM:SS\x00") 303 | 304 | Where the time can be easily parsed, consider the time to be in 24-hour format. 305 | 306 | ### Get Platform ### 307 | 308 | Procedure to request the platform: 309 | 310 | > packet(id=CMD_OPTIONS_RRQ, data="~Platform\x00") 311 | > packet(id=CMD_ACK_OK, data="~Platform=\x00") 312 | 313 | Where the `platform name` specifies the device platform. 314 | 315 | ### Get Device Info ### 316 | 317 | This procedure it is performed in the same way that the Generic Read of Parameters: 318 | 319 | > packet(id=CMD_OPTIONS_RRQ, data="\x00") 320 | > packet(id=CMD_ACK_OK, data="=\x00") 321 | 322 | This table is based on the SDK definitions. 323 | 324 | |SDK Number |Parameter name |Description |Permisions (RW/R) |Notes| 325 | |--- |--- |--- |--- |---| 326 | |1 | |Maximum number of admins. |NA |Fixed value it isn't requested to the machine.| 327 | |2 |DeviceID |Device ID. |RW |Value ranges from 1 to 254.| 328 | |3 |NewLng |Language. |RW |For english it is 97.| 329 | |4 |IdleMinute |The machine will enter standby state or power off, after this time elapses. |RW |Given in minutes.| 330 | |5 |LockOn |Lock control time. |RW |Given in seconds.| 331 | |6 |AlarmAttLog |Attendance record quantity alarm. |RW | | 332 | |7 |AlarmOpLog |Operation record quantity alarm. |RW | | 333 | |8 |AlarmReRec |Minimun time to record the same attendance state. |RW |Units are unknown.| 334 | |9 |RS232BaudRate |Baud rate for RS232/485. |RW |Valid values are 1200, 2400, 4800, 9600, 19200, 38400 57600, 115200.| 335 | |10 |NA |Parity check bit. |NA | Fixed value at 0.| 336 | |11 |NA |Stop bit. |NA | Fixed value at 0.| 337 | |12 |NA |Date separator. |NA | Return value fixed at 1.| 338 | |13 |NetworkOn |Enable flag for network functions. |RW | | 339 | |14 |RS232On |Enable flag for RS232. |RW | | 340 | |15 |RS485On |Enable flag for RS485. |RW | | 341 | |16 |VoiceOn |Enable announcements(voice). |RW | | 342 | |17 |MSpeed |Perform high-speed comparison. |RW |Value codification is unknown.| 343 | |18 |IdlePower |Idle mode. |RW |87 indicates shutdown and 88 indicates hibernation.| 344 | |19 |AutoPowerOff |Automatic shutdown time. |RW |Value 255 indicates the machine to not shutdown automatically.| 345 | |20 |AutoPowerOn |Automatic startup time. |RW |Value 255 indicates the machine to not startup automatically.| 346 | |21 |AutoPowerSuspend |Automatic hibernation time. |RW |Value 255 indicates the machine to not suspend automatically.| 347 | |22 |AutoAlarm1 |Alarm 1 time. |RW |Value 65535 disables the alarm(t).| 348 | |23 |MThreshold |1:N comparison threshold. |RW |Integer.| 349 | |24 |EThreshold |Registration threshold. |RW |Integer.| 350 | |25 |VThreshold |1:1 comparison threshold. |RW |Integer.| 351 | |26 |ShowScore |Display matching score during verification. |RW |Bool.| 352 | |27 |UnlockPerson |Number of people that may unlock the door at the same time. |RW |Integer.| 353 | |28 |OnlyPINCard |Verify only the card number. |RW |Bool.| 354 | |29 |HiSpeedNet |Network speed. |RW |Value correspondence: 1=100M-H, 4=10M-F, 5=100M-F, 8=Auto, others=10M-H.| 355 | |30 |MustEnroll |Accept only registered cards. |RW |Bool.| 356 | |31 |TOState |Timeout to return to the initial state. |RW |Given in seconds.| 357 | |32 |TOState |Timeout to return to the initial state if there are no inputs after entering PIN. |RW |Given in seconds.| 358 | |33 |TOMenu |Timeout to return to the initial state if there are no inputs after entering menu. |RW |Given in seconds.| 359 | |34 |DtFmt |Time format. |NA |Value codification is unknown.| 360 | |35 |Must1To1 |Flag for mandatory 1:1 comparison. |RW |Bool.| 361 | |36 |AutoAlarm2 |Alarm 2 time. |RW |Value 65535 disables the alarm(t).| 362 | |37 |AutoAlarm3 |Alarm 3 time. |RW |Value 65535 disables the alarm(t).| 363 | |38 |AutoAlarm4 |Alarm 4 time. |RW |Value 65535 disables the alarm(t).| 364 | |39 |AutoAlarm5 |Alarm 5 time. |RW |Value 65535 disables the alarm(t).| 365 | |40 |AutoAlarm6 |Alarm 6 time. |RW |Value 65535 disables the alarm(t).| 366 | |41-56 |AS{N} |Automatic status changing times. |? |-1 value indicates that the status will not change automatically.| 367 | |41 |AS1 | |? | | 368 | |42 |AS2 | |? | | 369 | |... |AS{..} | |? | | 370 | |56 |AS16 | |? | | 371 | |57 |WGFailedID |Wiegand failure ID. |? | | 372 | |58 |WGDuressID |Wiegand duress ID. |? | | 373 | |59 |WGSiteCode |Wiegand zone bit. |? | | 374 | |60 |WGPulseWidth |Pulse width of Wiegand outputs. |? | | 375 | |61 |WGPulseInterval |Pulse interval for Wiegand outputs. |? | | 376 | |62 |~RFSStart |ID of the start sector on the Mifare card where fingerprints are stored. |? | | 377 | |63 |~RFSLen |Total number of sectors on the Mifare card where fingerprints are stored. |? | | 378 | |64 |~RFFPC |Number of fingerprints stored on the Mifare card. |? | | 379 | |65 | |Forbidden. |NA | | 380 | |66 |~ShowState |Wheter to display the attendance status. |RW | | 381 | |67 | |Unused |NA | | 382 | |68 | |Unused |NA | | 383 | |69 |TCPPort |TCP Port. |? | | 384 | |70 |UDPPort |UDP Port. |? | | 385 | |71 |~ZKFPVersion |Fingerprint algorithm version. |R | | 386 | |72 |~ZKFaceVersion |Face algorithm version. |R | | 387 | |73 |~ZKFVVersion |Finger vein version. |R | | 388 | |74 |~FaceFunOn |Face function. |R | | 389 | |75 |~PIN2Width |User id max length. |R | | 390 | |76 |IsSupportABCPin |Does the user id support chars. |R | | 391 | |77 |IMEFunOn |? |? | | 392 | |78 |IsSupportAlarmExt |? |? | | 393 | |79 |~DCTZ |? |? | | 394 | |80 |~DOTZ |? |? | | 395 | |81 | |Specify the param with the name. |NA | | 396 | 397 | (t) : To obtain time, convert the string number to bin, then take the 8 most significant bits, the given number will be the hour, the minutes are simply the number given by the 8 least significant bits. 398 | 399 | ? : Stands for unknown. 400 | 401 | NA : Stands for Not Applicable. 402 | 403 | ### Set Device Info ### 404 | 405 | This procedure is used to change parameters of the device (see table of Device Info Parameters). 406 | 407 | > packet(id=CMD_OPTIONS_WRQ, data="=\x00") 408 | > packet(id=CMD_ACK_OK) 409 | > packet(id=CMD_REFRESHOPTION) 410 | > packet(id=CMD_ACK_OK) 411 | 412 | Also, keep in mind that some parameters are read only. 413 | 414 | #### Examples #### 415 | 416 | 1.Changing Lock on timer(Integer): 417 | 418 | 00000000: 50 50 82 7D 11 00 00 00 0C 00 EB BB 84 C5 47 00 PP.}..........G. 419 | 00000010: 4C 6F 63 6B 4F 6E 3D 35 00 LockOn=5. 420 | 421 | The machine may reply with `CMD_ACK_OK`. 422 | 423 | 2.Changing antipassback flag(Bool): 424 | 425 | 00000000: 50 50 82 7D 19 00 00 00 0C 00 60 22 84 C5 43 00 PP.}......`"..C. 426 | 00000010: 41 6E 74 69 50 61 73 73 62 61 63 6B 4F 6E 3D 30 AntiPassbackOn=0 427 | 00000020: 00 . 428 | 429 | The machine may reply with `CMD_ACK_OK`. 430 | 431 | ## Get Firmware Version ## 432 | 433 | To request the firmware version send a `CMD_GET_VERSION` command. 434 | 435 | packet(id=CMD_GET_VERSION) 436 | 437 | The device should reply with a `CMD_ACK_OK` code and a data structure with the version tag and date of the firmware: 438 | 439 | packet(id=CMD_ACK_OK, data="Ver \x00") 440 | 441 | Example: 442 | 443 | packet(id=CMD_ACK_OK, data="Ver 6.81 Apr 28 2015\x00") 444 | 445 | ## Get Device State ## 446 | 447 | To request the device current state send a `CMD_STATE_RRQ` command. 448 | 449 | packet(id=CMD_STATE_RRQ) 450 | 451 | The device should reply with a `CMD_ACK_OK` code and the current device state, stored in the `session id` field in little endian format. 452 | 453 | packet(id=CMD_ACK_OK, session id=) 454 | 455 | Where the state may have one of the following values: 456 | 457 | |Value |Description | 458 | |--- |--- | 459 | |0 |Waiting state. | 460 | |1 |Fingerprint registration state. | 461 | |2 |Fingerprint identification state. | 462 | |3 |Menu access state. | 463 | |4 |Busy. | 464 | |5 |Waiting for card writing. | 465 | 466 | **Example**: 467 | 468 | Reply example 469 | 470 | 00000000: 50 50 82 7D 08 00 00 00 D0 07 F6 F7 02 00 37 00 PP.}..........7. 471 | 472 | In this case the device is at state 2. 473 | 474 | [Go to Main Page](../protocol.md) 475 | -------------------------------------------------------------------------------- /protocol.md: -------------------------------------------------------------------------------- 1 | # Protocol Description of ZKTeco's Standalone Devices # 2 | 3 | Author: Alexander Marin 4 | 5 | [TOC] 6 | 7 | 8 | ## Introduction ## 9 | 10 | ZKTeco is a security company that provides business solutions to manage the attendance and access of employees to restricted areas. 11 | 12 | Their devices may use biometric information like employee's face or fingerprint to grant access, also a PIN or an RFID card may be used. 13 | 14 | They provide the [ZKAccess](https://www.zkteco.com/en/product_detail/158.html) software to manage the standalone terminals. And also and [SDK](https://www.zkteco.com/en/download_catgory.html) for standalone devices, to develop custom applications, but both options are targeted to the Windows platform, so in order to use this devices from a Linux system, a library is needed but to develop such lib, we first need the protocol specification, which can be extracted from some ZKTeco's documents and additional analysis of captured packets between Windows software and attendance terminals. There is currently a python package [zklib](https://pypi.org/project/zklib/) to do basic tasks but the documentation is very poor and the library lacks several functions. 15 | 16 | **Disclaimer**: The protocol extraction was made with only one device(f19, a TFT series device), so the spec may present some flaws (e.g constant fields that aren't constant). 17 | 18 | 19 | ## Terminology ## 20 | 21 | The documentation provided by ZKTeco, sometimes shows acronyms without prior definition, here we provide a list of useful terms that you may found in this wiki and in other documents. 22 | 23 | |Term |Meaning| 24 | |--- |---| 25 | |terminal |Standalone device| 26 | |machine |Standalone device| 27 | |FRT |Fingerprint reader terminal| 28 | |FFR |Fingerprint and facial recognition terminal| 29 | |BW devices |Refers to all the standalone devices with a black & white screen| 30 | |TFT devices |Refers to all the standalone devices with a color TFT screen| 31 | |iFace devices |Refers to all the stantalone devices with face recognition feature, these devices have a touch screen| 32 | |SSR |Self service recorder| 33 | 34 | 35 | ## Managing Attendance ## 36 | 37 | Before going into the actual protocol it would be convenient to clarify the type of things that can be done with ZKAccess Standalone Devices. 38 | 39 | ### User Properties ### 40 | 41 | A user is the model of an employee, an employee has a list of attributes: 42 | 43 | - ID number: This could be the working ID, students ID, license ID, but should be unique. 44 | - Index: This is an internal index associated with the user, it is used in a large set of commands to refer to a given user, a 'common user' doesn't have knowledge of this number, and it may be different across different devices. 45 | - Name: The name of the employee, this is optional. 46 | - Permissions: This sets the level of actions that a user may perform, regular employees are 'common users' while the IT admins may be 'superadmins'. 47 | - Enable flag: A user may be enabled or disabled. 48 | - Card number: This corresponds to the number of an RFID card, this depends on the verify style. 49 | - Password: Password to access, this depends on the verify style. 50 | - Group: New users are by default on group 1, but there may be 100 different groups, a user can only belong to one group, they could inherit permissions and settings from the group to which they belong, at the same time a group may have 3 timezones and a verify style. 51 | - Timezones: A user may have a maximum of three timezones. 52 | - Verify style: Sets the way the user verifies on the machine, e.g. use password and fingerprint, use RFID card or fingerprint. 53 | 54 | ### Granting Access ### 55 | 56 | To grant access there are several tweaks, timezones, group unlock combinations, multiple verification modes and holidays, there is also a daylight correction but this it isn't considered. 57 | 58 | To open door a user must comply with the following conditions: 59 | 60 | - Perform a successful verification. 61 | - Be in a valid timezone. 62 | - Be in a a group for a valid unlock combination. 63 | 64 | #### Verify Style #### 65 | 66 | There are several combinations of allowed verification modes, they are all a subset of the following three options: 67 | 68 | - Fingerprint. 69 | - RFID card. 70 | - Password. 71 | - User ID. 72 | 73 | A user may have a personal verify style or could inherit the verify style from the group. 74 | 75 | To open a door, the user must perform a successful verification, this is a necessary condition but not sufficient. 76 | 77 | #### Timezones #### 78 | 79 | A timezone is just a definition of allowed hours to validate: 80 | 81 | (Start time):(End time) 82 | 83 | For each timezone there is one definition for each day of the week, i.e. per timezone we have 7 time intervals. 84 | 85 | Each device may store a maximum of 50 timezones. 86 | 87 | To open a door is needed that at least one of the timezones is satisfied, that means that the timezones are **ORed**. 88 | 89 | It is possible to make a user use the timezones of the group instead of his own timezones. 90 | 91 | A user is commonly assigned only one timezone. 92 | 93 | ### Unlock Combination ### 94 | 95 | To open a door the user should be in a valid unlock combination, per device there may be 10 unlock combinations, each unlock combination may consist of a maximum of 5 groups: 96 | 97 | combination N: G1 G2 G3 G4 G5 98 | 99 | To open a door at least one unlock combination must be satisfied, that means that users from the 5 different groups G1-G5 must validate at the same time to unlock the door. Though it isn't required that the 5 groups must be defined, so a common unlock combination is: 100 | 101 | 01: 01 00 00 00 00 102 | 103 | This combination indicates that only is needed a user from the group 1 to satisfy the unlock combination 1. 104 | 105 | 106 | ## Protocol Overview ## 107 | 108 | The **standalone** terminals are called in that way because they may be used without any communication with a "coordinator" or "manager", like the ZKAccess software, so the protocol is designed to: 109 | 110 | - **Get info from terminals**: Attendance records, new users(added in the standalone terminal), device model, status, etc. The ZKAccess program, builds a database with this info. 111 | - **Set info in terminals**: Add users, change access permissions, change device settings, etc. 112 | - **Report events**: Corresponds to packets sent from the machine when specific actions take place, they are sent without a previous request. 113 | 114 | Note that the communication can be done through: 115 | 116 | - TCP/IP 117 | - UDP/IP 118 | - Serial 119 | - USB 120 | 121 | Here we consider a communication setup with TCP/IP. 122 | 123 | The terminals are considered a **server**, so when attendance records are requested, this is referred as a **download** operation, in a similar way, when data is sent from PC to the device, this is referred as an **upload** operation. 124 | 125 | When there are "intensive" operations (i.e. too much changes/transactions) the procedures begin with a disable-device command, this could be to prevent undefined behavior in the device. For small tasks, like get-device-time, there is no need for disabling and enabling the device. Simple tasks usually consist of a request followed by a reply. 126 | 127 | Based on the **Standalone SDK** design, a classification of the protocol functions can be made: 128 | 129 | - **Terminal operations**: Includes, procedures to manage communication with the machine, get/set time of device and to request generic information(device type, matching algorithm, etc). 130 | - **Data operations**: Procedures to manage data in the device, they can be further divided according to the data to be modified. 131 | - **User**: Related to the modification of user info/settings. 132 | - **Record**: Related to attendance logs. 133 | - **Shorcut**: Related to configuration of shorcut keys. 134 | - **Workcode**: Related to modification of work codes. 135 | - **SMS**: Procedures to config short messaging options. 136 | - **Bell**: Procedures to config the bell behavior. 137 | - **Photo**: Related to modification of users photos. 138 | - **Voice**: Related to management of announcement settings. 139 | - **Theme**: Related to management of background picture in the device. 140 | - **App**: Related to available functions in the standalone device. 141 | - **Biometric**: Related to management of biometric data stored in the device. 142 | - **Access**: Procedures to manage general access configuration (manage groups, timezones, holidays) 143 | - **Realtime**: Realtime procedures. 144 | - **Misc**: Miscellaneous procedures (take fingerprint picture, restart device, poweroff, etc). 145 | 146 | 147 | ## Packet Fields ## 148 | 149 | All packets have the following fields: 150 | 151 | |Name |Description |Value[hex] |Size[bytes] |Offset | 152 | |--- |--- |--- |--- |--- | 153 | |start |Indicates start of packet. |5050827d |4 |0 | 154 | |payload size |Size of packet payload. |payload_size(<)|4 |4 | 155 | |payload |Packet payload. |varies |payload_size |8 | 156 | 157 | (<): Little endian format. 158 | 159 | The packets can be divided in regular packets and in realtime packets: 160 | 161 | - **Regular packets**: These are the packets used for normal request and reply procedures. 162 | - **Realtime packets**: These are the packets used to report events, the are sent by the machine without a previous reply, if a connection exists. 163 | 164 | Both type of packets follow this general structure. 165 | 166 | **Example of a regular type packet**: 167 | 168 | 00000000: 50 50 82 7D 0C 00 00 00 0B 00 58 EF C5 C0 05 00 PP.}......X..... 169 | 00000010: 7E 4F 53 00 170 | 171 | In this example the size of the payload is: 172 | 173 | 0x0000000C 174 | 175 | And the payload is: 176 | 177 | 0B 00 58 EF C5 C0 05 00 7E 4F 53 00 178 | 179 | ### Regular Packet Payload ### 180 | 181 | For regular packets the payload can be decomposed in the following fields: 182 | 183 | |Name |Description |Value[hex] |Size[bytes] |Offset |Overall Offset | 184 | |--- |--- |--- |--- |--- |--- | 185 | |command id |Command identifier/Reply code. |varies(<) |2 |0 |8 | 186 | |checksum |Checksum. |varies(<) |2 |2 |10 | 187 | |session id |Session id. |varies(<) |2 |4 |12 | 188 | |reply number |Reply number. |varies(<) |2 |6 |14 | 189 | |data |Specific data for the given command/reply. |varies |payload_size-8 |8 |16 | 190 | 191 | (<): Little endian format. 192 | 193 | **Example**: 194 | 195 | Following the previous example 196 | 197 | 0B 00 58 EF C5 C0 05 00 7E 4F 53 00 198 | 199 | The fields contents are: 200 | 201 | |Name |Value[hex] | 202 | |--- |--- | 203 | |command id |000B | 204 | |checksum |EF58 | 205 | |session id |C0C5 | 206 | |reply number |0005 | 207 | |data |[ 7E 4F 53 00 ]| 208 | 209 | #### Command/Reply Identifiers #### 210 | 211 | The command/reply id field may be used for two purposes: 212 | 213 | 1. Instruct the machine to do something. 214 | 2. Return an exit code from a given procedure. 215 | 3. Report events (corresponds to `CMD_REG_EVENT`). 216 | 217 | The command id correspondence is given in the following table: 218 | 219 | |Name |Description |Value[base10] |Value[hex] | 220 | |--- |--- |--- |--- | 221 | |CMD_CONNECT |Begin connection. |1000 |03e8 | 222 | |CMD_EXIT |Disconnect. |1001 |03e9 | 223 | |CMD_ENABLEDEVICE |Change machine state to "normal work". |1002 |03ea | 224 | |CMD_DISABLEDEVICE |Disables fingerprint, rfid reader and keyboard. |1003 |03eb | 225 | |CMD_RESTART |Restart machine. |1004 |03ec | 226 | |CMD_POWEROFF |Shut-down machine. |1005 |03ed | 227 | |CMD_SLEEP |Change machine state to "idle". |1006 |03ee | 228 | |CMD_RESUME |Change machine state to "awaken". |1007 |03ef | 229 | |CMD_CAPTUREFINGER |Capture fingerprint picture. |1009 |03f1 | 230 | |CMD_TEST_TEMP |Test if fingerprint exists. |1011 |03f3 | 231 | |CMD_CAPTUREIMAGE |Capture the entire image. |1012 |03f4 | 232 | |CMD_REFRESHDATA |Refresh the machine stored data. |1013 |03f5 | 233 | |CMD_REFRESHOPTION |Refresh the configuration parameters. |1014 |03f6 | 234 | |CMD_TESTVOICE |Test voice. |1017 |03f9 | 235 | |CMD_GET_VERSION |Request the firmware edition. |1100 |044c | 236 | |CMD_CHANGE_SPEED |Change transmission speed. |1101 |044d | 237 | |CMD_AUTH |Request to begin session using commkey. |1102 |044e | 238 | |CMD_PREPARE_DATA |Prepare for data transmission. |1500 |05dc | 239 | |CMD_DATA |Data packet. |1501 |05dd | 240 | |CMD_FREE_DATA |Release buffer used for data transmission. |1502 |05de | 241 | |CMD_DATA_WRRQ |Read/Write a large data set. |1503 |05df | 242 | |CMD_DATA_RDY |Indicates that it is ready to receive data. |1504 |05e0 | 243 | |CMD_DB_RRQ |Read saved data. |7 |0007 | 244 | |CMD_USER_WRQ |Upload user data. |8 |0008 | 245 | |CMD_USERTEMP_RRQ |Read user fingerprint template. |9 |0009 | 246 | |CMD_USERTEMP_WRQ |Upload user fingerprint template. |10 |000a | 247 | |CMD_OPTIONS_RRQ |Read configuration value of the machine. |11 |000b | 248 | |CMD_OPTIONS_WRQ |Change configuration value of the machine. |12 |000c | 249 | |CMD_ATTLOG_RRQ |Request attendance log. |13 |000d | 250 | |CMD_CLEAR_DATA |Delete data. |14 |000e | 251 | |CMD_CLEAR_ATTLOG |Delete attendance record. |15 |000f | 252 | |CMD_DELETE_USER |Delete user. |18 |0012 | 253 | |CMD_DELETE_USERTEMP |Delete user fingerprint template. |19 |0013 | 254 | |CMD_CLEAR_ADMIN |Clears admins privileges. |20 |0014 | 255 | |CMD_USERGRP_RRQ |Read user group. |21 |0015 | 256 | |CMD_USERGRP_WRQ |Set user group. |22 |0016 | 257 | |CMD_USERTZ_RRQ |Get user timezones. |23 |0017 | 258 | |CMD_USERTZ_WRQ |Set the user timezones. |24 |0018 | 259 | |CMD_GRPTZ_RRQ |Get group timezone. |25 |0019 | 260 | |CMD_GRPTZ_WRQ |Set group timezone. |26 |001a | 261 | |CMD_TZ_RRQ |Get device timezones. |27 |001b | 262 | |CMD_TZ_WRQ |Set device timezones. |28 |001c | 263 | |CMD_ULG_RRQ |Get group combination to unlock. |29 |001d | 264 | |CMD_ULG_WRQ |Set group combination to unlock. |30 |001e | 265 | |CMD_UNLOCK |Unlock door for a specified amount of time. |31 |001f | 266 | |CMD_CLEAR_ACC |Restore access control to default. |32 |0020 | 267 | |CMD_CLEAR_OPLOG |Delete operations log. |33 |0021 | 268 | |CMD_OPLOG_RRQ |Read operations log. |34 |0022 | 269 | |CMD_GET_FREE_SIZES |Request machine status (remaining space). |50 |0032 | 270 | |CMD_ENABLE_CLOCK |Enables the ":" in screen clock. |57 |0039 | 271 | |CMD_STARTVERIFY |Set the machine to authentication state. |60 |003c | 272 | |CMD_STARTENROLL |Start enroll procedure. |61 |003d | 273 | |CMD_CANCELCAPTURE |Disable normal authentication of users. |62 |003e | 274 | |CMD_STATE_RRQ |Query state. |64 |0040 | 275 | |CMD_WRITE_LCD |Prints chars to the device screen. |66 |0042 | 276 | |CMD_CLEAR_LCD |Clear screen captions. |67 |0043 | 277 | |CMD_GET_PINWIDTH |Request max size for users id. |69 |0045 | 278 | |CMD_SMS_WRQ |Upload short message. |70 |0046 | 279 | |CMD_SMS_RRQ |Download short message. |71 |0047 | 280 | |CMD_DELETE_SMS |Delete short message. |72 |0048 | 281 | |CMD_UDATA_WRQ |Set user short message. |73 |0049 | 282 | |CMD_DELETE_UDATA |Delete user short message. |74 |004a | 283 | |CMD_DOORSTATE_RRQ |Get door state. |75 |004b | 284 | |CMD_WRITE_MIFARE |Write data to Mifare card. |76 |004c | 285 | |CMD_EMPTY_MIFARE |Clear Mifare card. |78 |004e | 286 | |CMD_VERIFY_WRQ |Change verification style of a given user. |79 |004f | 287 | |CMD_VERIFY_RRQ |Read verification style of a given user. |80 |0050 | 288 | |CMD_TMP_WRITE |Transfer fp template from buffer. |87 |0057 | 289 | |CMD_CHECKSUM_BUFFER |Get checksum of machine's buffer. |119 |0077 | 290 | |CMD_DEL_FPTMP |Deletes fingerprint template. |134 |0086 | 291 | |CMD_GET_TIME |Request machine time. |201 |00c9 | 292 | |CMD_SET_TIME |Set machine time. |202 |00ca | 293 | |CMD_REG_EVENT |Realtime events. |500 |01f4 | 294 | 295 | See the codification of reply codes in the following table: 296 | 297 | |Name |Description |Value[base10] |Value[hex] | 298 | |--- |--- |--- |--- | 299 | |CMD_ACK_OK |The request was processed sucessfully. |2000 |07d0 | 300 | |CMD_ACK_ERROR |There was an error when processing the request. |2001 |07d1 | 301 | |CMD_ACK_DATA | |2002 |07d2 | 302 | |CMD_ACK_RETRY | |2003 |07d3 | 303 | |CMD_ACK_REPEAT | |2004 |07d4 | 304 | |CMD_ACK_UNAUTH |Connection not authorized. |2005 |07d5 | 305 | |CMD_ACK_UNKNOWN |Received unknown command. |65535 |ffff | 306 | |CMD_ACK_ERROR_CMD | |65533 |fffd | 307 | |CMD_ACK_ERROR_INIT | |65532 |fffc | 308 | |CMD_ACK_ERROR_DATA | |65531 |fffb | 309 | 310 | #### Checksum #### 311 | 312 | The calculated checksum is a 16 bit integer, but it is calculated using a 32 bit integer. 313 | 314 | To calculate the checksum follow this steps: 315 | 316 | 1. Sum all the contents of the payload packet(without the checksum, obviously) as integers of 16 bits in little endian format. 317 | 2. If there is an odd number of bytes then fill the last short with zeros. 318 | 3. Then, from this result, extract a short integer from the positions 31-16 and add this number to the short integer given by 15-0 positions. 319 | 4. Calculate the ones-complement to the number obtained in step 3. 320 | 321 | 322 | The calculation of the checksum is presented with the following code in python: 323 | 324 | ```python 325 | chk_32b = 0 # accumulates short integers to calculate checksum 326 | j = 1 # iterates through payload 327 | 328 | # make odd length packets, even 329 | if len(payload)%2 == 1: 330 | payload += [0x00] 331 | 332 | while j>16) 342 | 343 | # calculate ones complement to get final checksum (in big endian) 344 | chk_16b = chk_32b ^ 0xFFFF 345 | ``` 346 | 347 | **Test Vectors** 348 | 349 | **Note**: The header is not included, these are only payloads. 350 | 351 | **1.** 352 | ``` 353 | 0b005a17f38d03005a4b4661636556657273696f6e00 354 | ``` 355 | After removing the checksum `5a17`. 356 | 357 | ``` 358 | 0b00f38d03005a4b4661636556657273696f6e00 359 | ``` 360 | 361 | The calculation of the checksum should give you `175a`. 362 | 363 | **2.** 364 | 365 | Example packet, with checksum: 366 | ``` 367 | d007296af38d0a0009 368 | ``` 369 | 370 | The checksum should give you `6a29`. 371 | 372 | #### Session ID #### 373 | 374 | The session identifier it is a unique number assigned for every new connection, the machine returns the assigned session id after a connection request. 375 | 376 | The session id seems to be just a seconds counter, but the easiest way to get this number is just to extract the number from the device's connect reply. 377 | 378 | Also it is worth to note that performing a connection after another connection doesn't change the session id, that means that the session is closed only after closing the connection. 379 | 380 | #### Reply Number #### 381 | 382 | After a successful socket connection the counter starts from zero counting the number of replies, a command sent to the machine carries this reply counter and this number is the same for a valid reply from the machine. After receiving a reply from the machine, the counter becomes incremented and this new value is sent in the next request. 383 | 384 | The reply number should evolve like this: 385 | 386 | > command sent with reply number: 0000 387 | > reply received with reply numer: 0000 388 | > command sent with reply number: 0001 389 | > reply received with reply numer: 0001 390 | > command sent with reply number: 0002 391 | > reply received with reply numer: 0002 392 | 393 | **Notes**: 394 | 395 | - For large amounts of data this flow differs a little, see "Exchange of Data". 396 | - The reply number counter is unaffected for realtime packets. 397 | 398 | #### Data #### 399 | 400 | The contents of this field depend on the procedure. See Specific Operations sections. 401 | 402 | ### Realtime Packet Payload ### 403 | 404 | For realtime packets the payload differs a little from a regular packet: 405 | 406 | - The command id is always `CMD_REG_EVENT`. 407 | - The session id field is used to store the event code. 408 | - The reply number is set to zero. 409 | 410 | |Name |Description |Value[hex] |Size[bytes] |Offset |Overall Offset | 411 | |--- |--- |--- |--- |--- |--- | 412 | |command id |Command identifier/Reply code. |0xf401(t) |2 |0 |8 | 413 | |checksum |Checksum. |varies(<) |2 |2 |10 | 414 | |event |Event code identifier. |varies(<) |2 |4 |12 | 415 | |reply number |Reply number. |0x0000 |2 |6 |14 | 416 | |data |Specific data for the given report. |varies |payload_size-8 |8 |16 | 417 | 418 | (<): Little endian format. 419 | (t): This id corresponds to the command `CMD_REG_EVENT`(0x1f4). 420 | 421 | #### Event Codes #### 422 | 423 | The following table shows the codification for realtime events: 424 | 425 | |Name |Description |Value[base10] |Value[hex] | 426 | |--- |--- |--- |--- | 427 | |EF_ATTLOG |Attendance entry. |1 |1 | 428 | |EF_FINGER |Pressed finger. |2 |2 | 429 | |EF_ENROLLUSER |Enrolled user. |4 |4 | 430 | |EF_ENROLLFINGER |Enrolled fingerprint. |8 |8 | 431 | |EF_BUTTON |Pressed keyboard key. |16 |10 | 432 | |EF_UNLOCK | |32 |20 | 433 | |EF_VERIFY |Registered user placed finger. |128 |80 | 434 | |EF_FPFTR |Fingerprint score in enroll procedure. |256 |100 | 435 | |EF_ALARM |Triggered alarm. |512 |200 | 436 | 437 | #### Example #### 438 | 439 | This is an example of a realtime packet: 440 | 441 | 00000000: 50 50 82 7D 09 00 00 00 F4 01 A7 FC 00 01 00 00 PP.}............ 442 | 00000010: 64 443 | 444 | This corresponds to a `EF_FPFTR`(`0x0100`) event, and the data field of the payload has only one byte `0x64`. 445 | 446 | Note how the `session id` field is reused and the reply number is set to zero. 447 | 448 | ## Specific Operations ## 449 | 450 | ### Conventions ### 451 | 452 | In the following descriptions some conventions are used to make protocol descriptions simple but precise. 453 | 454 | #### Regular Packet Creation #### 455 | 456 | The packet formation process was presented in previous sections, the notation: 457 | 458 | packet(id=, data=) 459 | 460 | Is a compact form to refer to a packet with the format: 461 | 462 | |Name |Description |Value[hex] |Size[bytes] |Offset | 463 | |--- |--- |--- |--- |--- | 464 | |start |Indicates start of packet. |5050827d |4 |0 | 465 | |payload size |Size of packet payload. |payload_size(<)|4 |4 | 466 | |**id** |Command identifier/Reply code. |varies(<) |2 |8 | 467 | |checksum |Checksum. |varies(<) |2 |10 | 468 | |session id |Session id. |varies(<) |2 |12 | 469 | |reply number |Reply number. |varies(<) |2 |14 | 470 | |**data** |Specific data for the given command/reply. |varies |payload_size-8 |16 | 471 | 472 | (<): Little endian format. 473 | 474 | Where the others fields, the `payload size`, `checksum`, `session id` and `reply number` are calculated from context and the given packet parameters. 475 | 476 | Sometimes is helpful to explicitly show the values of the other packet fields, to indicate this we use the notation: 477 | 478 | packet(id=, data=, =) 479 | 480 | Example: 481 | 482 | packet(id=CMD_ACK_OK, session id=0000) 483 | 484 | **Notes**: 485 | 486 | - When data parameter is absent, an empty `payload data` field should be assumed. 487 | 488 | - Also, in this notation the hex codes are given in big endian (as seen on the table of command codes), and the data could be given as a textual description or as a sequence of hex numbers. 489 | 490 | - Some type of commands have a data field that it is always terminated in `0x00`, this is a way to indicate the end of a string, in this documentation this value is always shown to prevent ambiguity, it may be shown as `00` if it is a sequence of hex numbers or it may be shown as `\x00`, if a string is used. 491 | 492 | 493 | #### Realtime Packet Creation #### 494 | 495 | What differs from a regular packet and a realtime packets are just the `session id` and `reply number` fields. Beyond that the other fields `payload size` and `checksum`, are calculated same as before. 496 | 497 | This is summarized with the notation: 498 | 499 | rtpacket(event=, data=) 500 | 501 | In this notation the event code is given in big endian (as seen on the table of event codes), and the data could be given as a textual description or as a sequence of hex numbers. 502 | 503 | #### Conversations #### 504 | 505 | For packet conversations the following notation is used: 506 | 507 | > "message from client to machine" 508 | > "message from machine to client" 509 | > "message from client to machine" 510 | > "message from machine to client" 511 | 512 | ### Exchange of Data ### 513 | 514 | For specific steps used to send/receive large amounts of data, see [ex_data.md](./sections/ex_data.md) 515 | 516 | ### Terminal Operations ### 517 | 518 | For operations related to read/write of machine parameters, see [terminal.md](./sections/terminal.md) 519 | 520 | ### Data Operations ### 521 | 522 | For operations to manage users data, see [data-user.md](./sections/data-user.md). 523 | 524 | For operations to manage record data, see [data-record.md](sections/data-record.md) 525 | 526 | ### Access Operations ### 527 | 528 | For operations to manage access settings, see [access.md](./sections/access.md) 529 | 530 | ### Realtime Operations ### 531 | 532 | Realtime events are explained in [realtime.md](./sections/realtime.md) 533 | 534 | ### Other Operations ### 535 | 536 | Other operations can be found in [other.md](./sections/other.md) 537 | 538 | 539 | ## Links and Sources ## 540 | 541 | - [Python zklib repo](https://github.com/dnaextrim/python_zklib) 542 | - ZKTeco Inc, *A series of standalone product: Communication protocol manual* 543 | - [Facial & Fingerprint Recognition Product Series User Manual](https://www.zkteco.eu/uploads/downloads/technical_documents/user_manual/IFace-User-Manual.pdf) 544 | - [2.4 inch Color Screen Series User Manual](http://www.zkteco.co.za/manuals/F18_User_Manual.pdf) 545 | *** 546 | --------------------------------------------------------------------------------