c2b24d7f19350f53fdd5ada62cadfd2b204891b0
[rfid/librfid.git] / gemtag / gemtag.c
1 /*
2  *  (C) 2006 by Frank Zirkelbach <hackbard@hackdaworld.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 
6  *  as published by the Free Software Foundation
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include <usb.h>
25 #include "gemtag.h"
26
27 int asciidump(unsigned char *data,int len) {
28         int i;
29
30         for(i=0;i<len;i++)
31                 if((data[i]>0x19)&&(data[i]<0x7f)) printf("%c",data[i]);
32                 else printf("_");
33         printf("\n");
34
35         return 0;
36 }
37
38 int hexdump(unsigned char *data,int len) {
39         int i;
40
41         for(i=0;i<len;i++) printf("%02x ",data[i]);
42         printf("\n");
43
44         return 0;
45 }
46
47 struct usb_device *find_device(unsigned short vendor,unsigned short device) {
48         
49         struct usb_bus *bus;
50         struct usb_device *dev;
51
52         bus=usb_get_busses();
53         while(bus) {
54                 dev=bus->devices;
55                 while(dev) {
56                         if(dev->descriptor.idVendor==vendor &&
57                            dev->descriptor.idProduct==device)
58                                 return dev;
59                         dev=dev->next;
60                 }
61                 bus=bus->next;
62         }
63         return NULL;
64 }
65
66 u_int16_t gemtag_calc_crc(unsigned char *data,u_int16_t len) {
67
68         u_int16_t crc_polynom;
69         u_int16_t crc_preset;
70         u_int16_t crc;
71         int i,j;
72                 
73         crc_polynom=0x8408;
74         crc_preset=0xffff;
75         crc=0xffff;
76
77         for(i=0;i<len;i++) {
78                 crc^=data[i];
79                 for(j=0;j<8;j++) {
80                         if(crc&0x0001)
81                                 crc=(crc>>1)^crc_polynom;
82                         else
83                                 crc=(crc>>1);
84                 }
85         }
86         return crc;
87 }
88
89 int gemtag_transcieve(struct gemtag_handle *gh,unsigned char cmd,
90                          unsigned char *tx,unsigned int tx_len,
91                          unsigned char *rx,unsigned int *rx_len) {
92
93         unsigned char txbuf[256];
94         unsigned char rxbuf[256];
95         struct gemtag_cmd_hdr *txhdr;
96         struct gemtag_cmd_hdr *rxhdr;
97         u_int16_t crc,*crcptr;
98         int i,ret,size,rest;
99
100         txhdr=(struct gemtag_cmd_hdr *)txbuf;
101         rxhdr=(struct gemtag_cmd_hdr *)rxbuf;
102
103         txhdr->start=0xa5;
104         txhdr->seq=++(gh->seq);
105         txhdr->cmd=cmd;
106         txhdr->len=tx_len;
107         size=sizeof(struct gemtag_cmd_hdr);
108         memcpy(txbuf+size,tx,tx_len);
109         size+=tx_len;
110
111         /* crc check */
112         if(gh->caps&GEMTAG_CAP_CRC) {
113                 crcptr=(u_int16_t *)(txbuf+size);
114                 crc=gemtag_calc_crc(txbuf,size);
115                 //*crcptr=(crc>>8)|(crc<<8);
116                 *crcptr=crc;
117                 size+=2;
118         }
119
120         /* usb write */
121         if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT) {
122                 printf("(%02d) -> ",size);
123                 hexdump(txbuf,size);
124         }
125         ret=usb_interrupt_write(gh->handle,0x02,txbuf,size,0);
126         if(ret<=0) {
127                 perror("usb interrupt write");
128                 return ret;
129         }
130
131         /* usb read */
132         ret=usb_interrupt_read(gh->handle,0x81,rxbuf,32,0);
133         if(ret<=0) {
134                 perror("usb interrupt read");
135                 return ret;
136         }
137         if(ret<5) {
138                 if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT)
139                         printf("short answer (%d)\n",ret);
140                 return -SHORT_ANSWER;
141         }
142
143         *rx_len=rxbuf[3]|(rxbuf[4]<<8);
144         size=*rx_len+sizeof(struct gemtag_cmd_hdr); 
145         if(gh->caps&GEMTAG_CAP_CRC) size+=2;
146
147         i=1;
148         rest=size-ret;
149         while(rest>=0) {
150                 ret=usb_interrupt_read(gh->handle,0x81,rxbuf+i*32,32,0);
151                 if(ret<=0) {
152                         perror("usb interrupt read (missing bytes)");
153                         return ret;
154                 }
155                 i++;
156                 rest-=ret;
157         }
158
159         if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT) {
160                 printf("(%02d) <- ",size);
161                 hexdump(rxbuf,size);
162         }
163
164         /* crc check */
165         if(gh->caps&GEMTAG_CAP_CRC) {
166                 size-=2;
167                 crcptr=(u_int16_t *)(rxbuf+size);
168                 crc=gemtag_calc_crc(rxbuf,size);
169                 if(((crc>>8)!=rxbuf[size+1])||((crc&0xff)!=rxbuf[size])) {
170                         printf("bad crc! (%04x)\n",crc);
171                         return -BAD_CRC;
172                 }
173         }
174
175         /* check sequence number */     
176         if(rxhdr->seq!=txhdr->seq) {
177                 puts("transmitted/recieved sequence number do not match");
178                 return -SEQ_MISMATCH;
179         }
180
181         memcpy(rx,rxbuf+sizeof(struct gemtag_cmd_hdr),*rx_len);
182
183         return 0;
184 }
185
186 struct gemtag_handle *gemtag_open(void) {
187         struct usb_device *gemtag;
188         unsigned int i;
189         struct gemtag_handle *gh;
190         char info[64];
191
192         usb_init();
193         usb_find_busses();
194         usb_find_devices();
195
196         gemtag=find_device(USB_VENDOR_GEMTAG,USB_DEVICE_X501);
197         if(!gemtag) return NULL;
198
199         gh=malloc(sizeof(struct gemtag_handle));
200         if(!gh) return NULL;
201
202         memset(gh,0,sizeof(struct gemtag_handle));
203
204         gh->handle=usb_open(gemtag);
205         if(!gh->handle)
206                 goto out_free;
207
208         for(i=1;i<4;i++) {
209                 memset(info,0,sizeof(info));
210                 usb_get_string_simple(gh->handle,i,info,sizeof(info));
211                 printf("%s ",info);
212         }
213         printf("opened successfully\n");
214
215         if(usb_set_configuration(gh->handle,1)) {
216                 perror("set config");
217                 goto out_free;
218         }
219         printf("set configuration 1, ");
220
221         if(usb_claim_interface(gh->handle,0)) {
222                 perror("claim interface");
223                 goto out_free;
224         }
225         printf("claimed interface 0, ");
226
227         if(usb_set_altinterface(gh->handle,0))
228                 perror("set alt interface");
229         printf("activated alt setting 0\n");
230
231         return gh;
232
233 out_free:
234         free(gh);
235         return NULL;
236 }
237
238 int gemtag_close(struct gemtag_handle *gh) {
239
240         if(gh->handle) usb_close(gh->handle);
241         if(gh) free(gh);
242
243         return 0;
244 }
245
246         
247 int main(int argc, char **argv) {
248
249         struct gemtag_handle *gh;
250         unsigned char buf[256];
251         unsigned int buflen;
252
253         gh=gemtag_open();
254
255         gh->caps|=GEMTAG_CAP_CRC;
256         gh->caps|=GEMTAG_CAP_VERB_TRANSMIT;
257
258         printf("Device:\n");
259         gemtag_transcieve(gh,GEMTAG_CMD_GET_FW_VERSION,
260                           NULL,0,buf,&buflen);
261         asciidump(buf,buflen);
262         printf("\n");
263
264         printf("Serial Number:\n");
265         gemtag_transcieve(gh,GEMTAG_CMD_GET_SERIAL_NUMBER,
266                           NULL,0,buf,&buflen);
267         printf("Snr: %d (%04x)\n",buf[1]<<8|buf[0],buf[1]<<8|buf[0]);
268         printf("\n");
269
270         printf("RC632 Version:\n");
271         gemtag_transcieve(gh,GEMTAG_CMD_GET_RIC_VERSION,
272                           NULL,0,buf,&buflen);
273         printf("\n");
274
275         printf("Switching off the LED!\n");
276         buf[0]=GEMTAG_LED_OFF;
277         gemtag_transcieve(gh,GEMTAG_CMD_SWITCH_LED,
278                           buf,1,buf,&buflen);
279         printf("\n");
280
281         printf("Detecting Card ...\n");
282         gemtag_transcieve(gh,GEMTAG_CMD_DETECT_CARD,
283                           NULL,0,buf,&buflen);
284         asciidump(buf,buflen);
285         printf("\n");
286
287         gemtag_close(gh);
288
289         return 1;
290 }
291