bufr2synop 0.24.0
bufrnoaa.c
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013-2017 by Guillermo Ballester Valor *
3 * gbv@ogimet.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20/*! \file bufrnoaa.c
21 \brief This file includes the code to extract BUFR messages from NOAA bin files
22
23 <pre>
24 *.bin files have the following sequence
25 header: in the form '****NNNNNNN****
26 new line
27 Name: This is taken as name
28 \r\r\n
29 bufr report
30 \r\r\n
31
32 First, it parses bufr reports from file with path included with argument -i
33
34 Then for every report several decisions are taken depending on arguments
35 1) Select or discard depending on the type of BUFR
36 To select we have to set our choice with the aid of argument -T.
37 The argument supplied with '-t' will have one or more chars matching with T2 indexes (see below).
38 As example, '-T USO' will select all the BUFR messages with T2 as U (upper level), S (surface) or
39 O (oceanographic)
40 If no '-t' argument is set it means NO SELECCTION i.e. we almost do nothing
41
42 2) For every selected BUFR message we can do any of these task, (they are not excluyent)
43 - To write individual files, one per bufr message, with names as 'YYYYMMDDHHmmss_ISIE06_SBBR_012100_RRB.bufr'.
44 Date and time are source file timestamp and other items from bufr header.
45 To do this we have to use '-f' option.
46 - To write an archive file as the original NOAA bin file, but just with selected messages. The option
47 is '-F prefix' where prefix is the string to add. Resulting file names are in the form prefix_original_nane
48 if no -F option then no archive bin file is generated. timestamp of resulting file is the same than the input
49 file. In case of no bufr selected it just create a void file.
50
51 Second item of resulting name file is 6 characters long:
52
53 For observed data T1 is 'I'
54
55 Possible values for T2 when T1 = 'I'
56 O Oceanographic/limnographic (water properties)
57 P Pictorial
58 S Surface/sea level
59 T Text (plain language information)
60 U Upper air
61 X Other data types
62 Z Mixed data types
63
64 When T1T2 = 'IS' values for A1:
65
66 IS A 01–29 Routinely scheduled observations for n/a 000/006
67 distribution from automatic (fixed or mobile)
68 land stations (e.g. 0000, 0100, … or 0220, 0240,
69 0300, …, or 0715, 0745, ... UTC)
70 IS A 30–59 N-minute observations from automatic (fixed n/a 000/007
71 or mobile) land stations
72 IS B Radar reports (parts A and B) RADOB 006/003
73 IS C 01–45 Climatic observations from land stations CLIMAT 000/020
74 IS C 46–59 Climatic observations from marine stations CLIMAT SHIP 001/0202009 edition
75 ATTACHmENT II-5 I
76 IS D Radiological observation RADREP 010/001
77 IS E Ozone measurement at surface n/a 008/000
78 IS F Source of atmospherics SFAZI, SFLOC, SFAZU 000/030
79 IS I 01–45 Intermediate synoptic observations from fixed SYNOP (SIxx) 000/001
80 land stations 000/051
81 IS I 46–59 Intermediate synoptic observations from mobile SYNOP mOBIL 000/004
82 land stations
83 IS M 01–45 Main synoptic observations from fixed land SYNOP (SMxx) 000/002
84 stations 000/052
85 IS M 46–59 Main synoptic observations from mobile land SYNOP mOBIL 000/005
86 stations
87 IS N 01–45 Synoptic observations from fixed land stations SYNOP (SNxx) 000/000
88 at non-standard time (i.e. 0100, 0200, 0400, 000/050
89 0500, ... UTC)
90 IS N 46–59 Synoptic observations from mobile land stations SYNOP mOBIL 000/003
91 at non-standard time (i.e. 0100, 0200, 0400,
92 0500, ... UTC)
93 IS R Hydrologic reports HYDRA 000/040
94 IS S 01–19 Synoptic observations from marine stations SHIP 001/000
95 IS S 20–39 One-hour observations from automatic marine n/a 001/006
96 stations
97 IS S 40–59 N-minute observations from automatic marine n/a 001/007
98 stations
99 IS T 01–19 Tide gauge observations n/a 001/030
100 IS T 20–39 Observed water level time series n/a 001/031
101 IS V Special aeronautical observations (SPECI) SPECI 000/011
102 IS W Aviation routine weather observations (mETAR) mETAR 000/010
103 IS X Other surface data IAC, IAC FLEET
104
105 When T1T2 = 'IU' valores for A1:
106 IU A Single level aircraft reports (automatic) AmDAR 004/000
107 IU A Single level aircraft reports (manual) AIREP/PIREP 004/001
108 IU B Single level balloon reports n/a
109 IU C (used for single level satellite-derived SAREP/SATOB 005/000
110 reports – see Note 3)
111 IU D Dropsonde/Dropwindsondes TEmP DROP 002/007
112 IU E Ozone vertical sounding n/a 008/001
113 IU I Dispersal and transport analysis n/a 009/000
114 IU J 01–19 Upper wind from fixed land stations (entire PILOT (parts A, 002/001
115 sounding) B, C, D)
116 IU J 20–39 Upper wind from mobile land stations (entire PILOT mOBIL 002/003
117 sounding) (parts A, B, C, D)
118 IU J 40–59 Upper wind from marine stations (entire PILOT SHIP 002/002
119 sounding) (parts A, B, C, D)
120 IU K 01–19 Radio soundings from fixed land stations TEmP (parts A, B) 002/004
121 (up to 100 hPa)
122 IU K 20–39 Radio soundings from mobile land stations TEmP mOBIL 002/006
123 (up to 100 hPa) (parts A, B)
124 IU K 40–59 Radio soundings from marine stations TEmP SHIP (parts A, B) 002/005
125 (up to 100 hPa)
126 IU M Model derived sondes
127 IU N Rocketsondes
128 IU O Profiles of aircraft observations in ascending/ AmDAR 002/020
129 descending
130 IU P Profilers PILOT 002/010
131 IU Q RASS temperature profilers TEmP 002/011
132 IU R (used for radiance data – see Note 3)
133 IU S 01–19 Radiosondes/pibal reports from fixed land TEmP (parts A, B, C, D) 002/004
134 stations (entire sounding)
135 IU S 20–39 Radio soundings from mobile land stations TEmP mOBIL (parts A, 002/006
136 (entire sounding) B, C, D)
137 IU S 40–59 Radio soundings from marine stations TEmP SHIP (parts A, 002/005
138 (entire sounding) B, C, D)
139 IU T (used for satellite-derived sondes – see Note 3) SATEm, SARAD, SATOB
140 IU U 01–45 Monthly statistics of data from upper-air stations CLImAT TEmP 002/025
141 IU U 46–59 Monthly statistics of data from marine stations CLImAT TEmP, SHIP 002/026
142 IU W 01–19 Upper wind from fixed land stations (up to PILOT (parts A, B) 002/001
143 100 hPa)
144 IU W 20–39 Upper wind from mobile land stations (up to PILOT mOBIL 002/003
145 100 hPa) (parts A, B)
146 IU W 40–59 Upper wind from marine stations (up to PILOT SHIP 002/002
147 100 hPa) (parts A, B)
148 IU X Other upper-air reports
149
150 for T1T2 = 'IO' values for A1:
151 IO B Buoy observations BUOY 001/025
152 IO I Sea ice
153 IO P Sub-surface profiling floats TESAC 031/004
154 IO R Sea surface observations TRACKOB 031/001
155 IO S Sea surface and below soundings BATHY, TESAC 031/005
156 IO T Sea surface temperature
157 IO W Sea surface waves WAVEOB 031/002
158 IO X Other sea environmental
159
160 About A2
161
162 A 0 - 90W northern hemisphere
163 B 90W - 180 northern hemisphere
164 C 180 - 90E northern hemisphere
165 D 90E - 0 northern hemisphere
166 E 0 - 90W tropical belt
167 F 90W - 180 tropical belt
168 G 180 - 90E tropical belt
169 H 90E - 0 tropical belt
170 I 0 - 90W southern hemisphere
171 J 90W - 180 southern hemisphere
172 K 180 - 90E southern hemisphere
173 L 90E - 0 southern hemisphere
174 M Lower left 10S 100E/upper right 70N 110W
175 N Northern hemisphere
176 P Area between 64.69N - 136.76W, 55.61N - 13.43W
177 64.69N - 156.76W, 55.61N - 33.43W
178 S Southern hemisphere
179 T 45W - 180 northern hemisphere
180 U Area between 21.0N - 128.1W, 36.0N - 130.9W
181 21.1N - 113.0W, 36.2N - 110.5W
182 V Area between 30.3N - 83.7W, 51.0N - 68.9W
183 19.8N - 64.5W, 33.3N - 47.1W
184 X Global Area (area not definable)
185
186
187
188 </pre>
189*/
190#include "bufrnoaa.h"
191
193int LISTF; /*!< if != then a list of messages in bin file is generated */
194unsigned char BUFR[BUFRLEN];
195unsigned char BUF[BLEN];
196char ENTRADA[256];
197char SEL[64]; /*!< Selection string for argument -T according with T1 */
198char SELS[64]; /*!< Selection string for A1 when T2='S' (argument -S) */
199char SELU[64]; /*!< Selection string for A1 when T2='U' (argument -U) */
200char SELO[64]; /*!< Selection string for A1 when T2='O' (argument -O) */
201char PREFIX[64];
202char HEADER_MARK; /*!< Header mark character who is repeated four times at the begining */
203
204struct stat INSTAT;
205char OWN[] = "bufrnoaa";
206char SEP[] = "\r\r\n";
207char FINAL_SEP[4];
208
209
210int main ( int argc, char *argv[] )
211{
212 size_t nb = 0, nc, nx = 0, nbuf = 0, nsel = 0, nerr = 0, i, nh = 0, nw;
213 FILE* ficin;
214 FILE* ficout = NULL;
215 FILE* ficol = NULL;
216 unsigned char b[4], header[256];
217 unsigned int expected = 0;
218 char name[256], namex[256], namec[256];
219 double tx;
220 struct timeval tini, tfin, tt;
221
222 // Initial time
223 gettimeofday ( &tini, NULL );
224
225 // read args from stdio
226 if ( read_args ( argc, argv ) < 0 )
227 {
228 exit ( EXIT_FAILURE );
229 }
230
231 // Check input
232 if ( stat ( ENTRADA, &INSTAT ) )
233 {
234 printf ( "%s: Cannot stat %s\n", OWN, ENTRADA );
235 exit ( EXIT_FAILURE );
236 }
237
238 // Open output file
239 if ( ( ficin = fopen ( ENTRADA,"r" ) ) == NULL )
240 {
241 printf ( "%s: Cannot open %s\n", OWN, ENTRADA );
242 exit ( EXIT_FAILURE );
243 }
244
245 if ( COLECT )
246 {
247 // To make an archive
248
249 // build a name
250 strcpy ( namec, PREFIX );
251 strcat ( namec, ENTRADA );
252
253 // open the file
254 if ( ( ficol = fopen ( namec, "w" ) ) == NULL )
255 {
256 printf ( "%s: Cannot open %s\n", OWN, namec );
257 exit ( EXIT_FAILURE );
258 }
259 }
260
261
262 STAGE = 0;
263
264 memset ( &b, 0, 4 * sizeof ( unsigned char ) );
265
266 while ( ( nc = fread ( &BUF[0], sizeof ( unsigned char ), BLEN, ficin ) ) > 0 )
267 {
268 for ( i = 0; i < nc ; i++ )
269 {
270 // ingest a byte
271 b[3] = b[2];
272 b[2] = b[1];
273 b[1] = b[0];
274 b[0] = BUF[i];
275
276 switch ( STAGE )
277 {
278 case 0: // begining, searching header init
279 if ( is_head_custom ( &b[0] , HEADER_MARK ) )
280 {
281 memset ( &header[0], 0, 64 * sizeof ( unsigned char ) );
282 header[0] = HEADER_MARK;
283 header[1] = HEADER_MARK;
284 header[2] = HEADER_MARK;
285 header[3] = HEADER_MARK;
286 nh = 4;
287 STAGE = 1;
288 }
289 break;
290 case 1: // header found, filling
291 if ( nh < 255 )
292 header[nh++] = b[0];
293 else
294 {
295 STAGE = 0;
296 nerr++;
297 break;
298 }
299 if ( is_head_custom ( &b[0] , HEADER_MARK ) )
300 {
301 STAGE = 2;
302 //header[nh++] = '\0';
303 //printf("Header: '%s'\n",header);
304 }
305 break;
306 case 2: // header already finished
307 if ( nh < 255 )
308 header[nh++] = b[0];
309 else
310 {
311 STAGE = 0;
312 nerr++;
313 break;
314 }
315 if ( b[0] != 0x0a && b[0] != 0x0d )
316 {
317 STAGE = 3;
318 memset ( &name[0], 0, 128 * sizeof ( unsigned char ) );
319 name[0] = b[0];
320 nx = 1;
321 }
322 break;
323 case 3: // name already inited
324 if ( nh < 255 )
325 header[nh++] = b[0];
326 else
327 {
328 STAGE = 0;
329 nerr++;
330 break;
331 }
332 if ( nx >= 255 )
333 {
334 STAGE = 0;
335 break;
336 }
337 if ( b[0] == 0x01a || b[0] == 0x0d )
338 {
339 STAGE = 4;
340 name[nx++] = '\0';
341 //printf("Name: '%s'\n",name);
342 }
343 else if ( b[0] == ' ' )
344 name[nx++] = '_'; // substitute a space by '_'
345 else
346 name[nx++] = b[0];
347 break;
348 case 4: // Waiting BUFR message begin
349 if ( nh < 255 )
350 header[nh++] = b[0];
351 else
352 {
353 STAGE = 0;
354 nerr++;
355 break;
356 }
357 if ( is_bufr ( &b[0] ) )
358 {
359 STAGE = 5;
360 expected = 0;
361 // printf("Leyendo BUFR\n");
362 memset ( &BUFR[0], 0, BUFRLEN );
363 nb = 4;
364 BUFR[0]='B';
365 BUFR[1]='U';
366 BUFR[2]='F';
367 BUFR[3]='R';
368 nh -= 4;
369 header[nh] = '\0';
370 }
371 break;
372 case 5: // Filling BUFR message till final '7777'
373 if ( nb < ( BUFRLEN - 1 ) )
374 BUFR[nb++] = b[0];
375 else
376 {
377 printf ( "Error: Bufr message length > %d", BUFRLEN );
378 fclose ( ficin );
379 exit ( EXIT_FAILURE );
380 }
381 // check expected length
382 if ( nb == 7 )
383 {
384 expected = ( unsigned int ) b[0] + ( unsigned int ) b[1] * 256 + ( unsigned int ) b[2] * 65536;
385 }
386
387 // Has been detected some void and fakes bufr
388 if ( b[0] == HEADER_MARK &&
389 b[1] == HEADER_MARK &&
390 b[2] == HEADER_MARK
391 )
392 {
393 // Ooops. a fake bufr
394 // it seems a new header has been found before '7777'
395 STAGE = 0;
396 nerr++;
397 break;
398 }
399 if ( nb == expected )
400 {
401 if ( is_endb ( &b[0] ) )
402 {
403 STAGE = 0;
404 nbuf++;
405 if ( LISTF )
406 printf ( "%s\n", name );
407 if ( bufr_is_selected ( name ) )
408 {
409 nsel++;
410 if ( INDIVIDUAL )
411 {
412 // prefix with input file timestamp
413 date_mtime_from_stat ( namex, &INSTAT );
414 strcat ( namex,"_" );
415 strcat ( namex, name );
416 strcat ( namex, ".bufr" );
417 if ( ( ficout = fopen ( namex, "w" ) ) == NULL )
418 {
419 printf ( "Error: cannot open %s\n", name );
420 fclose ( ficin );
421 exit ( EXIT_FAILURE );
422 }
423 if ( ( nw = fwrite ( &BUFR[0], sizeof ( unsigned char ), nb, ficout ) ) != nb )
424 {
425 printf ( "Error: Writen %lu bytes instead of %lu in %s file\n", nw, nb, namex );
426 fclose ( ficin );
427 fclose ( ficout );
428 exit ( EXIT_FAILURE );
429 }
430 // close an individual fileq
431 fclose ( ficout );
432 // change individual file timestamp
433 mtime_from_stat ( namex, &INSTAT );
434 }
435 if ( COLECT )
436 {
437 // first write header
438 if ( ( nw = fwrite ( &header[0], sizeof ( char ), nh, ficol ) ) != nh )
439 {
440 printf ( "%s: Error: Writen %lu bytes instead of %lu in %s file\n", OWN, nw, nh, namec );
441 fclose ( ficin );
442 fclose ( ficol );
443 exit ( EXIT_FAILURE );
444 }
445
446 // then bufr message
447 if ( ( nw = fwrite ( &BUFR[0], sizeof ( unsigned char ), nb, ficol ) ) != nb )
448 {
449 printf ( "%s: Error: Writen %lu bytes instead of %lu in %s file\n", OWN, nw, nb, namex );
450 fclose ( ficin );
451 fclose ( ficout );
452 exit ( EXIT_FAILURE );
453 }
454 // finally \r\r\n
455 if (FINAL_SEP[0])
456 {
457 if ( ( nw = fwrite ( &FINAL_SEP[0], sizeof ( char ), 3, ficol ) ) != 3 )
458 {
459 printf ( "%s: Error: Writen %lu bytes instead of 3 chars separing messages in %s\n", OWN, nw, namex );
460 fclose ( ficin );
461 fclose ( ficout );
462 exit ( EXIT_FAILURE );
463 }
464 }
465 }
466 }
467 }
468 else
469 {
470 // reached the expected end of BUFR without a '7777'
471 STAGE = 0;
472 nerr++;
473 break;
474 }
475 }
476 }
477 }
478 }
479
480 if ( COLECT )
481 {
482 fclose ( ficol );
483 // change archive file timestamp
484 mtime_from_stat ( namec, &INSTAT );
485 }
486
487 // Final time
488 gettimeofday ( &tfin, NULL );
489 fclose ( ficin );
490
491 // A brief stat output
492 if ( VERBOSE )
493 {
494 printf ( "Found %lu bufr reports. Selected: %lu. Wrong: %lu\n", nbuf, nsel, nerr );
495 timeval_substract ( &tt, &tfin, &tini );
496 tx = ( double ) tt.tv_sec + ( double ) tt.tv_usec *1e-6;
497 printf ( "%lf seg. ", tx );
498 if ( nbuf && tx != 0.0 )
499 printf ( "%lf reports/sec.\n", ( double ) nbuf / tx );
500 else
501 printf ( "\n" );
502 }
503 exit ( EXIT_SUCCESS );
504}
505
int read_args(int _argc, char *_argv[])
read the arguments from stdio
Definition: bufrdeco_json.c:63
char SEP[]
Definition: bufrnoaa.c:206
int main(int argc, char *argv[])
Definition: bufrnoaa.c:210
struct stat INSTAT
Definition: bufrnoaa.c:204
int SELECT
Definition: bufrnoaa.c:192
char ENTRADA[256]
Definition: bufrnoaa.c:196
char HEADER_MARK
Definition: bufrnoaa.c:202
char SELU[64]
Definition: bufrnoaa.c:199
char FINAL_SEP[4]
Definition: bufrnoaa.c:207
int INDIVIDUAL
Definition: bufrnoaa.c:192
unsigned char BUFR[BUFRLEN]
Definition: bufrnoaa.c:194
char OWN[]
Definition: bufrnoaa.c:205
unsigned char BUF[BLEN]
Definition: bufrnoaa.c:195
char PREFIX[64]
Definition: bufrnoaa.c:201
char SELS[64]
Definition: bufrnoaa.c:198
int STAGE
Definition: bufrnoaa.c:192
int LISTF
Definition: bufrnoaa.c:193
int VERBOSE
Definition: bufrnoaa.c:192
char SELO[64]
Definition: bufrnoaa.c:200
int COLECT
Definition: bufrnoaa.c:192
inclusion file for binary bufrnoaa
int bufr_is_selected(char *name)
returns 1 if selected message 0 otherwise
int is_head_custom(unsigned char *b, char mark)
checks if an unsigned char from an array is the first char of repeated mark char four times
int is_endb(unsigned char *b)
checks if an unsigned char from an array is the first char of '7777'
int mtime_from_stat(char *filename, struct stat *st)
modifies a file update time from a struct stat
int date_mtime_from_stat(char *date, struct stat *st)
get a string with date and time from a struct stat
int is_bufr(unsigned char *b)
checks if an unsigned char from an array is the first char of 'BUFR'
#define BUFRLEN
Definition: bufrnoaa.h:36
#define BLEN
Definition: bufrnoaa.h:34
int timeval_substract(struct timeval *result, struct timeval *x, struct timeval *y)
Subtract the ‘struct timeval’ values X and Y, storing the result in RESULT.