root/driver/wwsr3.c

Revision 11, 16.4 KB (checked in by pzitny, 2 years ago)
Line 
1/*
2 * wwsr - Wireless Weather Station Reader
3 * 2007 dec 19, Michael Pendec (michael.pendec@gmail.com)
4 * Version 0.5
5 * 2008 jan 24 Svend Skafte (svend@skafte.net)
6 * 2008 sep 28 Adam Pribyl (covex@lowlevel.cz)
7 * Modifications for different firmware version(?)
8 * 2009 feb 1 Bradley Jarvis (bradley.jarvis@dcsi.net.au)
9 *  major code cleanup
10 *  update read to access device discretly
11 *  added user formatted output
12 *  added log function and fixed debug messaging
13 * 2009 mar 28 Lukas Zvonar (lukic@mag-net.sk)
14 *  added relative pressure formula (need to compile with -lm switch)
15 * 2009 apr 16 Petr Zitny (petr@zitny.net)
16 *  added XML output (-x)
17 *  fixed new line in help
18 *  fixed negative temperature
19 */
20#include <stdio.h>
21#include <string.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <usb.h>
26#include <time.h>
27#include <math.h>
28
29#define PACKAGE "wwsr"
30#define DEFAULT_VENDOR    0x1941
31#define DEFAULT_PRODUCT   0x8021
32#define DEFAULT_FORMAT    (char *)"time:                  %N\nin humidity:           %h %%\nout humidity:          %H %%\nin temperature:        %t C\nout temperature:       %T C\nout dew temperature:   %C C\nwindchill temperature: %c C\nwind speed:            %W m/s\nwind gust:             %G m/s\nwind direction:        %D\npressure:              %P hPa\nrel. pressure:         %p hPa\nrain:                  %R mm\n"
33
34#define WS_CURRENT_ENTRY  30
35
36int ws_open(usb_dev_handle **dev,uint16_t vendor,uint16_t product);
37int ws_close(usb_dev_handle *dev);
38
39int ws_read(usb_dev_handle *dev,uint16_t address,uint8_t *data,uint16_t size);
40int ws_reset(usb_dev_handle *dev);
41int ws_print(char *format,uint8_t *buffer);
42int ws_dump(uint16_t address,uint8_t *buffer,uint16_t size,uint8_t width);
43
44int altitude=0; //default altitude is sea level - change it if you need, or use -A parameter
45
46typedef enum log_event
47{
48        LOG_DEBUG=1,
49        LOG_WARNING=2,
50        LOG_ERROR=4,
51        LOG_INFO=8
52} log_event;
53FILE *_log_debug=NULL,*_log_warning=NULL,*_log_error=NULL,*_log_info=NULL;
54
55void logger(log_event event,char *function,char *msg,...);
56
57
58
59int main(int argc, char **argv)
60{
61        usb_dev_handle *dev;
62  int rv,c;
63  uint16_t vendor,product;
64  uint8_t help;
65 
66  rv=0;
67  dev=NULL;
68  vendor=DEFAULT_VENDOR;
69  product=DEFAULT_PRODUCT;
70  help=0;
71 
72  _log_error=stderr;
73  _log_info=stdout;
74 
75        while (rv==0 && (c=getopt(argc,argv,"hf:v?d:a:A:x"))!=-1)
76        {
77                switch (c)
78                {
79                        case 'a': // set device id
80                                sscanf(optarg,"%X:%X",&vendor,&product);
81                                logger(LOG_DEBUG,"main","USB device set to vendor=%04X product=%04X",vendor,product);
82                                break;
83
84                        case 'A': // set altitude
85                                sscanf(optarg,"%d",&altitude);
86                                logger(LOG_DEBUG,"main","altitude set to %d",altitude);
87                                break;
88                       
89                        case 'v': // Verbose messages
90                                _log_debug=_log_warning=stdout;
91                                logger(LOG_DEBUG,"main","Verbose messaging turned on");
92                                break;
93                               
94                        case 'x': // XML export
95                                optarg = "<data>\
96\n\t<temp>\n\t\t<indoor>\n\t\t\t<data>%t</data>\n\t\t\t<unit>C</unit>\n\t\t</indoor>\n\t\t<outdoor>\n\t\t\t<data>%T</data>\n\t\t\t<unit>C</unit>\n\t\t</outdoor>\n\t\t<windchill>\n\t\t\t<data>%c</data>\n\t\t\t<unit>C</unit>\n\t\t</windchill>\n\t\t<dewpoint>\n\t\t\t<data>%C</data>\n\t\t\t<unit>C</unit>\n\t\t</dewpoint>\n\t</temp>\
97\n\t<wind>\n\t\t<speed>\n\t\t\t<data>%W</data>\n\t\t\t<unit>m/s</unit>\n\t\t</speed>\n\t\t<gust>\n\t\t\t<data>%G</data>\n\t\t\t<unit>m/s</unit>\n\t\t</gust>\n\t\t<direct>\n\t\t\t<data>%d</data>\n\t\t\t<unit>degrees</unit>\n\t\t</direct>\n\t\t<direct_str>\n\t\t\t<data>%D</data>\n\t\t\t<unit>Str</unit>\n\t\t</direct_str>\n\t</wind>\
98\n\t<pressure>\n\t\t<abs>\n\t\t\t<data>%P</data>\n\t\t\t<unit>hPa</unit>\n\t\t</abs>\n\t\t<rel>\n\t\t\t<data>%p</data>\n\t\t\t<unit>hPa</unit>\n\t\t</rel>\n\t</pressure>\
99\n\t<rain>\n\t\t<total>\n\t\t\t<data>%R</data>\n\t\t\t<unit>mm</unit>\n\t\t</total>\n\t</rain>\
100\n\t<humidity>\n\t\t<indoor>\n\t\t\t<data>%h</data>\n\t\t\t<unit>%%</unit>\n\t\t</indoor>\n\t\t<outdoor>\n\t\t\t<data>%H</data>\n\t\t\t<unit>%%</unit>\n\t\t</outdoor>\n\t</humidity>\
101\n</data>\n";
102                       
103                        case 'f': // Format output
104                                logger(LOG_DEBUG,"main","Format output using '%s'",optarg);
105                               
106                                if (dev==NULL)
107                                {
108                                        rv=ws_open(&dev,vendor,product);
109                                }
110                               
111                                if (dev)
112                                {
113                                        uint16_t address;
114                                        uint8_t buffer[0x10];
115                                       
116                                        ws_read(dev,WS_CURRENT_ENTRY,(unsigned char *)&address,sizeof(address));
117                                        ws_read(dev,address,buffer,sizeof(buffer));
118                                        ws_print(optarg,buffer);
119                                }
120                                break;
121                       
122                        case 'd': // Dump raw data from weather station
123                        {
124                                uint16_t a,s,w;
125                               
126                                a=0;
127                                s=0x100;
128                                w=16;
129                               
130                                if (sscanf(optarg,"0x%X:0x%X",&a,&s)<2)
131                                if (sscanf(optarg,"0x%X:%u",&a,&s)<2)
132                                if (sscanf(optarg,"%u:0x%X",&a,&s)<2)
133                                if (sscanf(optarg,"%u:%u",&a,&s)<2)
134                                if (sscanf(optarg,":0x%X",&s)<1)
135                                        sscanf(optarg,":%u",&s);
136                               
137                                logger(LOG_DEBUG,"main","Dump options address=%u size=%u",a,s);
138                               
139                                if (dev==NULL)
140                                {
141                                        rv=ws_open(&dev,vendor,product);
142                                }
143                               
144                                if (dev)
145                                {
146                                        uint8_t *b;
147                                       
148                                        logger(LOG_DEBUG,"main","Allocating %u bytes for read buffer",s);
149                                        b=malloc(s);
150                                        if (!b) logger(LOG_ERROR,"main","Could not allocate %u bytes for read buffer",s);
151                                       
152                                        if (b)
153                                        {
154                                                logger(LOG_DEBUG,"main","Allocated %u bytes for read buffer",s);
155                                               
156                                                ws_read(dev,a,b,s);
157                                                ws_dump(a,b,s,w);
158                                               
159                                                free(b);
160                                        }
161                                }
162                                break;
163                        }
164                       
165                        case '?':
166                                help=1;
167                                printf("Wireless Weather Station Reader v0.1\n");
168                                printf("(C) 2007 Michael Pendec\n\n");
169                                printf("options\n");
170                                printf(" -? Display help\n");
171                                printf(" -a v:p Change the vendor:product address of the usb device from the default\n");
172                                printf(" -A <alt in m> Change altitude\n");
173                                printf(" -v Verbose output, enable debug and warning messages\n");
174                                printf(" -x XML output\n");
175                                printf(" -f Format output to user defined string\n");
176                                printf("    %%h - inside humidity\n");
177                                printf("    %%H - outside humidity\n");
178                                printf("    %%t - inside temperature\n");
179                                printf("    %%T - outside temperature\n");
180                                printf("    %%C - outside dew temperature\n");
181                                printf("    %%c - outside wind chill temperature\n");
182                                printf("    %%W - wind speed\n");
183                                printf("    %%G - wind gust\n");
184                                printf("    %%D - wind direction - named\n");
185                                printf("    %%d - wind direction - degrees\n");
186                                printf("    %%P - pressure\n");
187                                printf("    %%p - relative pressure\n");
188                                printf("    %%R - rain\n");
189                                printf("    %%N - now - date/time string\n");
190                                printf(" -d [address]:[length] Dump length bytes from address\n");
191                }
192        }
193       
194        if (rv==0 && dev==NULL && help==0)
195        {
196                uint16_t address;
197                uint8_t buffer[0x10];
198               
199                rv=ws_open(&dev,vendor,product);
200               
201                if (rv==0) rv=ws_read(dev,WS_CURRENT_ENTRY,(unsigned char *)&address,sizeof(address));
202                if (rv==0) rv=ws_read(dev,address,buffer,sizeof(buffer));
203                if (rv==0) rv=ws_print(DEFAULT_FORMAT,buffer);
204        }
205       
206        if (dev)
207        {
208                ws_close(dev);
209        }
210       
211        return rv;
212}
213
214int ws_open(usb_dev_handle **dev,uint16_t vendor,uint16_t product)
215{
216        int rv;
217        struct usb_bus *bus;
218       
219        rv=0;
220        *dev=NULL;
221       
222        logger(LOG_DEBUG,"ws_open","Initialise usb");
223        usb_init();
224        usb_set_debug(0);
225        usb_find_busses();
226        usb_find_devices();
227       
228        logger(LOG_DEBUG,"ws_open","Scan for device %04X:%04X",vendor,product);
229        for (bus=usb_get_busses(); bus && *dev==NULL; bus=bus->next)
230        {
231                struct usb_device *device;
232               
233                for (device=bus->devices; device && *dev==NULL; device=device->next)
234                {
235                        if (device->descriptor.idVendor == vendor
236                                && device->descriptor.idProduct == product)
237                        {
238                                logger(LOG_DEBUG,"ws_open","Found device %04X:%04X",vendor,product);
239                                *dev=usb_open(device);
240                        }
241                }
242        }
243       
244        if (rv==0 && *dev)
245        {
246                char buf[100];
247               
248                switch (usb_get_driver_np(*dev,0,buf,sizeof(buf)))
249                {
250                        case 0:
251                                logger(LOG_WARNING,"ws_open","Interface 0 already claimed by driver \"%s\", attempting to detach it", buf);
252                                rv=usb_detach_kernel_driver_np(*dev,0);
253                }
254               
255                if (rv==0)
256                {
257                        logger(LOG_DEBUG,"ws_open","Claim device");
258                        rv=usb_claim_interface(*dev,0);
259                }
260               
261                if (rv==0)
262                {
263                        logger(LOG_DEBUG,"ws_open","Set alt interface");
264                        rv=usb_set_altinterface(*dev,0);
265                }
266        }
267        else
268        {
269                logger(LOG_ERROR,"ws_open","Device %04X:%04X not found",vendor,product);
270                rv=1;
271        }
272       
273        if (rv==0)
274        {
275                logger(LOG_DEBUG,"ws_open","Device %04X:%04X opened",vendor,product);
276        }
277        else
278        {
279                logger(LOG_ERROR,"ws_open","Device %04X:%04X: could not open, code:%d",vendor,product,rv);
280        }
281       
282        return rv;
283}
284
285int ws_close(usb_dev_handle *dev)
286{
287        int rv;
288
289        if (dev)
290        {
291                rv=usb_release_interface(dev, 0);
292                if (rv!=0) logger(LOG_ERROR,"ws_close","Could not release interface, code:%d", rv);
293               
294                rv=usb_close(dev);
295                if (rv!=0) logger(LOG_ERROR,"ws_close","Error closing interface, code:%d", rv);
296        }
297       
298        return rv;
299}
300
301int ws_read(usb_dev_handle *dev,uint16_t address,uint8_t *data,uint16_t size)
302{
303        uint16_t i,c;
304        int rv;
305        uint8_t s,tmp[0x20];
306       
307        memset(data,0,size);
308       
309        logger(LOG_DEBUG,"ws_read","Reading %d bytes from 0x%04X",size,address);
310       
311        i=0;
312        c=sizeof(tmp);
313        s=size-i<c?size-i:c;
314       
315        for (;i<size;i+=s, s=size-i<c?size-i:c)
316        {
317                uint16_t a;
318                char cmd[9];
319               
320                a=address+i;
321               
322                logger(LOG_DEBUG,"ws_read","Send read command: Addr=0x%04X Size=%u",a,s);
323                sprintf(cmd,"\xA1%c%c%c\xA1%c%c%c",a>>8,a,c,a>>8,a,c);
324                rv=usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,cmd,sizeof(cmd)-1,1000);
325                logger(LOG_DEBUG,"ws_read","Sent %d of %d bytes",rv,sizeof(cmd)-1); 
326                rv=usb_interrupt_read(dev,0x81,tmp,c,1000);
327                logger(LOG_DEBUG,"ws_read","Read %d of %d bytes",rv,c); 
328               
329                memcpy(data+i,tmp,s);
330        }
331       
332        return 0;
333}
334
335int ws_reset(usb_dev_handle *dev)
336{
337        printf("Resetting WetterStation history\n");
338       
339        usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,"\xA0\x00\x00\x20\xA0\x00\x00\x20",8,1000);
340        usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,"\x55\x55\xAA\xFF\xFF\xFF\xFF\xFF",8,1000);
341        //_send_usb_msg("\xa0","\x00","\x00","\x20","\xa0","\x00","\x00","\x20");
342        //_send_usb_msg("\x55","\x55","\xaa","\xff","\xff","\xff","\xff","\xff");
343        usleep(28*1000);
344       
345        usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",8,1000);
346        //_send_usb_msg("\xff","\xff","\xff","\xff","\xff","\xff","\xff","\xff");
347        usleep(28*1000);
348       
349        //_send_usb_msg("\x05","\x20","\x01","\x38","\x11","\x00","\x00","\x00");
350        usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,"\x05\x20\x01\x38\x11\x00\x00\x00",8,1000);
351        usleep(28*1000);
352       
353        //_send_usb_msg("\x00","\x00","\xaa","\x00","\x00","\x00","\x20","\x3e");
354        usb_control_msg(dev,USB_TYPE_CLASS+USB_RECIP_INTERFACE,9,0x200,0,"\x00\x00\xAA\x00\x00\x00\x20\x3E",8,1000);
355        usleep(28*1000);
356       
357        return 0;
358}
359
360int ws_print(char *format,uint8_t *buffer)
361{
362        char *dir[]=
363        {
364                "N","NNE","NE","ENE","E","ESE","SE","SSE",
365                "S","SSW","SW","WSW","W","WNW","NW","NNW"
366        };
367        char *dirdeg[]=
368        {
369                "0","23","45","68","90","113","135","158",
370                "180","203","225","248","270","293","315","338"
371        };
372/*      char *dirslovak[]=              {"S","SSV","SV","VSV","V","VJV","JV","JJV",
373                                         "J","JJZ","JZ","ZJZ","Z","ZSZ","SZ","SSZ"};   
374*/
375        time_t basictime;
376        char datestring[50]; 
377        float p,temp,m,windspeed,tw,hum,gama;
378
379        for (;*format;format++)
380        {
381                if (*format=='%')
382                {
383                        switch (*++format)
384                        {
385                                case 'h': // inside humidity
386                                        printf("%d",buffer[0x01]);
387                                        break;
388                               
389                                case 'H': // outside humidity
390                                        printf("%d",buffer[0x04]);
391                                        break;
392                               
393                                case 't': // inside temperature
394                                        if ((buffer[0x03] & 128) > 0) { //fix negative temperature
395                                            printf("-%0.1f",(float)((buffer[0x02]+(buffer[0x03]<<8))& 32767)/10);
396                                        } else {
397                                            printf("%0.1f",(float)((buffer[0x02]+(buffer[0x03]<<8))& 32767)/10);
398                                        };     
399                                        break;
400                               
401                                case 'T': // outside temperature
402                                        if ((buffer[0x06] & 128) > 0) { //fix negative temperature
403                                            printf("-%0.1f",(float)((buffer[0x05]+(buffer[0x06]<<8))& 32767)/10);
404                                        } else {
405                                            printf("%0.1f",(float)((buffer[0x05]+(buffer[0x06]<<8))& 32767)/10);
406                                        };
407                                        break; 
408
409                                case 'C': // dew point based on outside temperature (formula from wikipedia)
410                                        temp=(float)(buffer[0x05]+(buffer[0x06]<<8))/10; //out temp celsius
411                                        hum=(float)buffer[0x04]/100;                     //humidity / 100
412                                        if (hum == 0) hum=0.001;                         //in case of 0% humidity
413                                        gama=(17.271*temp)/(237.7+temp) + log (hum);     //gama=aT/(b+T) + ln (RH/100)
414                                        tw= (237.7 * gama) / (17.271 - gama);            //Tdew= (b * gama) / (a - gama)
415                                        printf("%0.1f",tw);
416                                        break;
417
418                                case 'c': // windchill temperature
419                                        temp=(float)(buffer[0x05]+(buffer[0x06]<<8))/10; //out temp celsius
420                                        windspeed=(float)(buffer[0x09])/10 * 3.6;        //in km/h
421                                        if (( windspeed > 4.8 ) && (temp < 10)) //formula from wikipedia only at condition
422                                        tw=13.12 + 0.6215 * temp - 11.37*pow(windspeed,0.16) + 0.3965*temp*pow(windspeed,0.16);
423                                        else tw=temp;                           //else nothing..
424                                        printf("%0.1f",tw);
425                                        break;
426                               
427                                case 'W': // wind speed
428                                        printf("%0.1f",(float)(buffer[0x09])/10);
429                                        break;
430                               
431                                case 'G': // wind gust
432                                        printf("%0.1f",(float)(buffer[0x0A])/10);
433                                        break;
434                               
435                                case 'D': // wind direction - named
436                                        printf(dir[buffer[0x0C]<sizeof(dir)/sizeof(dir[0])?buffer[0x0C]:0]);
437                                        break;
438
439                                case 'd': // wind direction - degrees
440                                        printf(dirdeg[buffer[0x0C]<sizeof(dir)/sizeof(dir[0])?buffer[0x0C]:0]);
441                                        break;
442                               
443                                case 'P': // pressure
444                                        printf("%0.1f",(float)(buffer[0x07]+(buffer[0x08]<<8))/10);
445                                        break;
446                               
447                                case 'p': // rel. pressure
448                                        p=(float)(buffer[0x07]+(buffer[0x08]<<8))/10; //abs. pressure
449                                        temp=(float)(buffer[0x05]+(buffer[0x06]<<8))/10; //out temp
450                                        m=altitude / (18429.1 + 67.53 * temp + 0.003 * altitude); //power exponent to correction function
451                                        p=p * pow(10,m); //relative pressure * correction
452                                        printf("%0.1f",p);
453                                        break;
454                               
455                                case 'R': // rain
456                                        printf("%0.1f",(float)(buffer[0x0D]+(buffer[0x0E]<<8))*0.3);
457                                        break;
458
459                                case 'N': // date
460                                        time(&basictime);
461                                        strftime(datestring,sizeof(datestring),"%Y-%m-%d %H:%M:%S",
462                                         localtime(&basictime));
463                                        // Print out and leave
464                                        printf("%s",datestring);
465                                        break;
466                                case '%': // percents
467                                        printf("%%");
468                                        break;
469                        }
470                }
471                else if (*format=='\\')
472                {
473                        switch (*++format)
474                        {
475                                case 'n':
476                                        printf("\n");
477                                        break;
478                               
479                                case 'r':
480                                        printf("\r");
481                                        break;
482                               
483                                case 't':
484                                        printf("\t");
485                                        break;
486                               
487                        }
488                }
489                else
490                {
491                        printf("%c",*format);
492                }
493        }
494/*      printf("rain?:           %0.1f (this is always zero)\n",(float)(buffer[253])/10);
495        printf("rain:            %0.1f (24h?)\n",(float)(buffer[254]+(buffer[255]<<8))/10);
496        printf("rain1:           %d\n",buffer[254]);
497        printf("rain2:           %d\n",buffer[253]);
498        printf("other 1:         %d\n",buffer[251]);
499        printf("other 2:         %d\n",buffer[255]);
500        printf("\n");*/
501       
502        return 0;
503}
504
505int ws_dump(uint16_t address,uint8_t *data,uint16_t size,uint8_t w)
506{
507        uint16_t i,j,s;
508        char *buf;
509       
510        s=8+(w*5)+1;
511        logger(LOG_DEBUG,"ws_dump","Allocate %u bytes for temporary buffer",s);
512        buf=malloc(s);
513        if (!buf) logger(LOG_WARNING,"ws_dump","Could not allocate %u bytes for temporary buffer, verbose dump enabled",s);
514       
515        logger(LOG_INFO,"ws_dump","Dump %u bytes from address 0x%04X",size,address);
516        for (i=0;i<size && buf && data;)
517        {
518                if (buf) sprintf(buf,"0x%04X:",address+i);
519                for (j=0;j<w && i<size;i++,j++)
520                {
521                        if (buf)
522                        {
523                                sprintf(buf,"%s 0x%02X",buf,data[i]);
524                        } else
525                        {
526                                logger(LOG_INFO,"ws_dump","0x%04X: 0x%02X",address+i,data[i]);
527                        }
528                }
529                if (buf) logger(LOG_INFO,"ws_dump",buf);
530        }
531       
532        return 0;
533}
534
535void logger(log_event event,char *function,char *msg,...)
536{
537        va_list args;
538       
539        va_start(args,msg);
540        switch (event)
541        {
542                case LOG_DEBUG:
543                        if (_log_debug)
544                        {
545                                fprintf(_log_debug,"message: wwsr.%s - ",function);
546                                vfprintf(_log_debug,msg,args);
547                                fprintf(_log_debug,"\n");
548                        }
549                        break;
550               
551                case LOG_WARNING:
552                        if (_log_warning)
553                        {
554                                fprintf(_log_warning,"warning: wwsr.%s - ",function);
555                                vfprintf(_log_warning,msg,args);
556                                fprintf(_log_warning,"\n");
557                        }
558                        break;
559               
560                case LOG_ERROR:
561                        if (_log_error)
562                        {
563                                fprintf(_log_error,"error: wwsr.%s - ",function);
564                                vfprintf(_log_error,msg,args);
565                                fprintf(_log_error,"\n");
566                        }
567                        break;
568               
569                case LOG_INFO:
570                        if (_log_info)
571                        {
572                                fprintf(_log_info,"info: wwsr.%s - ",function);
573                                vfprintf(_log_info,msg,args);
574                                fprintf(_log_info,"\n");
575                        }
576                        break;
577        }
578        va_end(args);
579}
580
Note: See TracBrowser for help on using the browser.