RaspberrPi project source code
guowenxue
2024-03-12 cbbab621e5e5d3b1407bd898544ab8b7487563a3
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2023 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  gpsd.c
6  *    Description:  This file is GPS location parser program
7  *
8  *        Version:  1.0.0(07/10/23)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "07/10/23 09:49:55"
11  *
12  ********************************************************************************/
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17
18 #include "logger.h"
19 #include "comport.h"
20 #include "util_proc.h"
21
22 typedef struct gps_fix_s
23 {
24     char       time[32];  /* GPS UTC time, formt: hhmmss */
25     char       status;    /* A: Valid  V:Invalid */
26     float      latitude;  /* Latitude */
27     char       lat;       /* N: North  S: South */
28     float      longitude; /* Longitude */
29     char       lon;       /* E: East   W: West */
30     float      speed;     /* Speed over ground, meters/sec */
31     float      track;     /* Course made good (relative to true north) */
32 } gps_fix_t;
33
34
35 int proc_gprmc(char *buf, int size, gps_fix_t *info);
36
37 static inline void banner(const char *progname)
38 {
39     printf("%s program Version v1.0.0 Build on (%s)\n", progname, __DATE__);
40     printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
41 }
42
43 static void program_usage(const char *progname)
44 {
45     banner(progname);
46
47     printf("Usage: %s [OPTION]...\n", progname);
48     printf(" %s is a MQTT subscribe daemon program to control relay. \n", progname);
49
50     printf("\nMandatory arguments to long options are mandatory for short options too:\n");
51     printf(" -D[device  ]  Set GPS connect serial port device\n");
52     printf(" -d[debug   ]  Running in debug mode\n");
53     printf(" -l[level   ]  Set the log level as [0..%d]\n", LOG_LEVEL_MAX-1);
54     printf(" -h[help    ]  Display this help information\n");
55     printf(" -v[version ]  Display the program version\n");
56
57     return;
58 }
59
60 int main (int argc, char **argv)
61 {
62     const char             *progname=NULL;
63     int                     opt = 0;
64     int                     rv = 0;
65     int                     debug = 0;
66     char                    pid_file[64] = { 0 }; /*   The file used to record the PID */
67     char                   *log_file = "/tmp/gpsd.log";
68     int                     log_level = LOG_LEVEL_INFO;
69     int                     log_size = 10;
70
71     char                    buf[4096];
72     char                   *dev=NULL;
73     comport_t               comport;
74     gps_fix_t               info;
75
76     struct option long_options[] = {
77         {"device", required_argument, NULL, 'D'},
78         {"debug", no_argument, NULL, 'd'},
79         {"level", required_argument, NULL, 'l'},
80         {"version", no_argument, NULL, 'v'},
81         {"help", no_argument, NULL, 'h'},
82         {NULL, 0, NULL, 0}
83     };
84
85     progname = basename(argv[0]);
86     /*  Parser the command line parameters */
87     while ((opt = getopt_long(argc, argv, "D:dl:vh", long_options, NULL)) != -1)
88     {
89         switch (opt)
90         {
91             case 'D':  /*  Set serial port device */
92                 dev = optarg;
93                 break;
94
95             case 'd': /*  Set debug running */
96                 debug = 1;
97                 log_file = "console";
98                 log_level = LOG_LEVEL_DEBUG;
99                 log_size = ROLLBACK_NONE;
100                 break;
101
102             case 'l': /*  Set the log level */
103                 rv = atoi(optarg);
104                 log_level = rv>LOG_LEVEL_MAX ? LOG_LEVEL_MAX-1 : rv;
105                 break;
106
107             case 'v':  /*  Get software version */
108                 banner(progname); /*  Defined in version.h */
109                 return EXIT_SUCCESS;
110
111             case 'h':  /*  Get help information */
112                 program_usage(progname);
113                 return 0;
114
115             default:
116                 break;
117         } /*   end of "switch(opt)" */
118     }
119
120     if( !dev )
121     {
122         program_usage(progname);
123         return 0;
124     }
125
126     if( (rv=log_open(log_file, log_level, log_size, LOG_LOCK_DISABLE)) < 0 )
127     {
128         fprintf(stderr, "open logger failed, rv=%d\n", rv);
129         return 1;
130     }
131
132     if( !debug )
133     {
134         snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname);
135         log_info("check program running in daemon or not by pidfile [%s]\n", pid_file);
136         if( check_daemon_running(pid_file) )
137         {
138             printf("Programe already running, exit now.\n");
139             return 3;
140         }
141
142         if( set_daemon_running(pid_file) < 0 )
143         {
144             printf("Programe already running, exit now.\n");
145             return 3;
146         }
147     }
148
149     if( (rv=comport_open(&comport, dev, 4800, "8N1N")) < 0 )
150     {
151         log_error("Open serial port \"%s\" failed, rv=%d\n", dev, rv);
152         return 2;
153     }
154     log_info("Open serial port \"%s\" successfully\n", dev);
155
156     while(1)
157     {
158         memset(buf, 0, sizeof(buf));
159         rv = comport_recv(&comport, buf, sizeof(buf), 3000);
160         if( rv > 0 )
161         {
162             proc_gprmc(buf, strlen(buf), &info);
163         }
164     }
165
166     comport_close(&comport);
167     return 0;
168 }
169
170 /*
171  * $GPRMC,024216.000,A,3029.6651,N,11423.6251,E,0.08, 156.95,100723,,,A*65
172  * 1     024216.000    UTC time format: HHMMSS, 10:42:16(BeiJing)
173  * 2     A             Status of Fix:
174  *                      A = Autonomous, valid;
175  *                      D = Differential, valid;
176  *                      V = invalid
177  *
178  * 3,4   3029.6651,N   Latitude format: ddmm.mmmm, Latitude 30 deg. 29.6651 min North
179  * 5,6   11423.6251,E  Longitude: dddmm.mmmm, Longitude 114 deg. 23.6251 min East
180  * 7     0.08          Speed over ground, Knots
181  * 8     156.95        Course Made Good, True north
182  * 9     100723        Date of fix ddmmyy. 2023-07-10
183  * 10,11 ,,            Magnetic variation
184  * 12    A             FAA mode indicator (NMEA 2.3 and later)
185  *                      A=autonomous,
186  *                      D=differential,
187  *                      E=Estimated,
188  *                      M=Manual input mode,
189  *                      N=not valid,
190  *                      S=Simulator,
191  *                      V=Valid
192  * 13   *68            mandatory nmea_checksum
193  */
194
195 #define DD(s)   ((int)((s)[0]-'0')*10+(int)((s)[1]-'0'))
196 int proc_gprmc(char *buf, int size, gps_fix_t *info)
197 {
198     char           *ptr_start=NULL;
199     char           *ptr_end=NULL;
200     char            hhmmss[12]={0x0};
201     char            ddmmyy[12]={0x0};
202
203     if( !buf || size<=0 || !info )
204     {
205         log_error("Invalid input arguments\n");
206         return -1;
207     }
208
209     log_trace("GPS receive raw data\n:%s\n", buf);
210
211     if( !(ptr_start=strstr(buf, "$GPRMC")) )
212     {
213         log_warn("$GPRMC keywords not matched\n");
214         return -2;
215     }
216
217     if( !(ptr_end=strchr(ptr_start, 0x0D)) )
218     {
219         log_warn("$GPRMC data not integrated\n");
220     }
221
222     *ptr_end = '\0';
223
224     memset(info, 0, sizeof(*info));
225     sscanf(ptr_start, "$GPRMC,%[^,],%c,%f,%c,%f,%c,%f,%f,%[^,]",
226             hhmmss, &info->status, &info->latitude, &info->lat,
227             &info->longitude, &info->lon, &info->speed, &info->track, ddmmyy);
228
229     snprintf(info->time, sizeof(info->time), "%04d-%02d-%02d %02d:%02d:%02d",
230             DD(ddmmyy+4)+2000, DD(ddmmyy+2), DD(ddmmyy),
231             DD(hhmmss)+8, DD(hhmmss+2), DD(hhmmss+4));
232
233     if( info->status == 'A' )
234     {
235         log_info("NMEA0183: %s lat=%.2f(%c) lon=%.2f(%c) speed=%.2f, track=%.2f\n",
236                 info->time, info->latitude, info->lat,
237                 info->longitude, info->lon, info->speed, info->track);
238     }
239     else if( info->status == 'V' )
240     {
241         log_info("NMEA0183: Invalid data\n");
242     }
243
244     return 0;
245 }