bufr2synop 0.24.0
bufrdeco_wmo.c
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013-2022 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/*!
21 \file bufrdeco_wmo.c
22 \brief This file has the code to read bufr files from WMO csv files
23*/
24#include "bufrdeco.h"
25
26/*!
27 And these are the default directories when using WMO csv table files
28*/
29const char DEFAULT_BUFRTABLES_WMO_CSV_DIR1[] = "/usr/local/share/bufr2synop/";
30const char DEFAULT_BUFRTABLES_WMO_CSV_DIR2[] = "/usr/share/bufr2synop/";
31
32/*!
33 \fn int get_wmo_tablenames ( struct bufrdeco *b)
34 \brief Get the complete pathnames for WMO csv table files needed by a bufr message
35 \param b pointer for a struct \ref bufrdeco
36 \return if success return 0, otherwise 1
37
38 For WMO files this format is adopted
39 BUFR_XX_Y_Z_TableB_en for table B
40 BUFR_XX_Y_Z_CodeFlag for Code table and Flag table. This is equivalent to table C in ECMWF package
41 BUFR_XX_Y_Z_TableD_en for table D
42
43 XX is the Version number of master table used
44 Y is the revision (currently ignored)
45 Z is minor revision (currently ignored)
46*/
48{
49 struct stat st;
50 char aux[BUFRDECO_PATH_LENGTH - 32];
51
52 bufrdeco_assert ( b != NULL );
53
54 if ( b->bufrtables_dir[0] == '\0' )
55 {
56 // try to guess directory
57 if ( stat ( DEFAULT_BUFRTABLES_WMO_CSV_DIR1, &st ) )
58 {
59 if ( stat ( DEFAULT_BUFRTABLES_WMO_CSV_DIR2, &st ) )
60 {
61 return 1;
62 }
63 else
64 {
65 if ( S_ISDIR ( st.st_mode ) )
66 {
67 strcpy ( aux, DEFAULT_BUFRTABLES_WMO_CSV_DIR2 );
68 }
69 }
70 }
71 else
72 {
73 if ( S_ISDIR ( st.st_mode ) )
74 {
75 strcpy ( aux, DEFAULT_BUFRTABLES_WMO_CSV_DIR1 );
76 }
77 }
78 }
79 else
80 {
81 strcpy ( aux, b->bufrtables_dir );
82 }
83
84 switch ( b->sec1.master_version )
85 {
86 case 4:
87 case 5:
88 case 6:
89 case 7:
90 case 8:
91 case 9:
92 case 10:
93 case 11:
94 case 12:
95 case 13:
96 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_13_0_0_TableB_en.csv", aux );
97 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_13_0_0_TableC_en.csv", aux );
98 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_13_0_0_TableD_en.csv", aux );
99 break;
100 case 18:
101 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_18_1_0_TableB_en.csv", aux );
102 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_18_1_0_TableC_en.csv", aux );
103 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_18_1_0_TableD_en.csv", aux );
104 break;
105 case 19:
106 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_19_1_1_TableB_en.csv", aux );
107 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_19_1_1_TableC_en.csv", aux );
108 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_19_1_1_TableD_en.csv", aux );
109 break;
110 case 22:
111 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_22_0_1_TableB_en.csv", aux );
112 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_22_0_1_TableC_en.csv", aux );
113 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_22_0_1_TableD_en.csv", aux );
114 break;
115 case 14:
116 case 15:
117 case 16:
118 case 17:
119 case 20:
120 case 21:
121 case 23:
122 case 24:
123 case 25:
124 case 26:
125 case 27:
126 case 28:
127 case 29:
128 case 30:
129 case 31:
130 case 32:
131 case 33:
132 case 34:
133 case 35:
134 case 36:
135 case 37:
136 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_%d_0_0_TableB_en.csv", aux, b->sec1.master_version );
137 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_%d_0_0_TableC_en.csv", aux, b->sec1.master_version );
138 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_%d_0_0_TableD_en.csv", aux, b->sec1.master_version );
139 break;
140 case 38:
141 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_%d_1_0_TableB_en.csv", aux, b->sec1.master_version );
142 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_%d_1_0_TableC_en.csv", aux, b->sec1.master_version );
143 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_%d_1_0_TableD_en.csv", aux, b->sec1.master_version );
144 break;
145 default:
146 snprintf ( b->tables->b.path, sizeof ( b->tables->b.path ),"%sBUFR_38_1_0_TableB_en.csv", aux );
147 snprintf ( b->tables->c.path, sizeof ( b->tables->c.path ),"%sBUFR_38_1_0_TableC_en.csv", aux );
148 snprintf ( b->tables->d.path, sizeof ( b->tables->d.path ),"%sBUFR_38_1_0_TableD_en.csv", aux );
149 break;
150 }
151 return 0;
152}
153
154/*!
155 \fn int bufr_read_tables (struct bufrdeco *b)
156 \brief Read the tables according with bufr file data from a bufr table directory
157 \param b basic struct with needed data
158 \return if success return 0, otherwise 1
159
160 The default directories where to search bufr tables are stored in \ref DEFAULT_BUFRTABLES_WMO_CSV_DIR1 and \ref DEFAULT_BUFRTABLES_WMO_CSV_DIR2
161*/
162int bufr_read_tables ( struct bufrdeco *b )
163{
164 int index;
165 buf_t i;
166 bufrdeco_assert ( b != NULL );
167 struct bufr_tableB *tb;
168
170 {
171 // When using cache, member b->tables is actually a pointer in array b->cache.tab[]
172
173 if ( ( index = bufrdeco_cache_tables_search ( & ( b->cache ), b->sec1.master_version ) ) >= 0 )
174 {
175#ifdef __DEBUG
176 printf ( "# Found tables in cache for version %u index %d\n", b->sec1.master_version, index );
177#endif
178 // hit cache, then the only task is to change member b->tables, and restore original values from item im tableB
179 b->tables = b->cache.tab[index];
180 tb = & ( b->tables->b );
181
182 for ( i = 0; i < tb->nlines ; i++ )
183 {
184 tb->item[i].scale = tb->item[i].scale_ori;
185 tb->item[i].reference = tb->item[i].reference_ori;
186 tb->item[i].nbits = tb->item[i].nbits_ori;
187 tb->item[i].changed = 0;
188 }
189
190 // all done
191 return 0;
192 }
193 else
194 {
195#ifdef __DEBUG
196 printf ( "# Tables for version %u not found in cache. Stored in index %d\n", b->sec1.master_version, b->cache.next );
197#endif
198 // If not in cache, the new master version tables has to be stored. This implies that
199 bufrdeco_store_tables ( & ( b->tables ), & ( b->cache ), b->sec1.master_version );
200
201 // get tablenames
202 if ( get_wmo_tablenames ( b ) )
203 {
204 snprintf ( b->error, sizeof ( b->error ),"%s(): Cannot find bufr tables\n", __func__ );
205 return 1;
206 }
207
208 // Missed cache
209 if ( bufr_read_tableB ( b ) )
210 {
211 return 1;
212 }
213
214 if ( bufr_read_tableC ( b ) )
215 {
216 return 1;
217 }
218
219 if ( bufr_read_tableD ( b ) )
220 {
221 return 1;
222 }
223
224 }
225 }
226 else
227 {
228 // If tables still not initialized then do it
229 if ( b->tables == NULL && bufrdeco_init_tables ( & ( b->tables ) ) )
230 {
231 snprintf ( b->error, sizeof ( b->error ), "%s(): Cannot allocate memory for tables\n", __func__ );
232 return 1;
233 }
234 // get tablenames
235 if ( get_wmo_tablenames ( b ) )
236 {
237 snprintf ( b->error, sizeof ( b->error ),"%s(): Cannot find bufr tables\n", __func__ );
238 return 1;
239 }
240
241 // And now read tables
242 if ( bufr_read_tableB ( b ) )
243 {
244 return 1;
245 }
246
247 if ( bufr_read_tableC ( b ) )
248 {
249 return 1;
250 }
251
252 if ( bufr_read_tableD ( b ) )
253 {
254 return 1;
255 }
256 }
257 return 0;
258}
259
260/*!
261 * \fn int bufrdeco_store_tables ( struct bufr_tables **t, struct bufr_tables_cache *c, uint8_t ver )
262 * \brief Init an element of array c->tab[] if still not allocated. If allocated clean it and set *t pointing to this element
263 * \param t pointer to array of struct \ref bufr_tables
264 * \param c pointer ti struct \ref bufr_tables_cache
265 * \param ver version of tables acting as key
266 * \return if success return 0
267 *
268 */
269int bufrdeco_store_tables ( struct bufr_tables **t, struct bufr_tables_cache *c, uint8_t ver )
270{
271 if ( c->tab[c->next] == NULL )
272 {
273 // Init the array element
274 bufrdeco_init_tables ( & ( c->tab[c->next] ) );
275
276 // increase the counter of allocated elements
277 ( c->nt )++;
278 }
279 else
280 {
281 // Clean the element in array with zeroes
282 memset ( c->tab[c->next], 0, sizeof ( struct bufr_tables ) );
283
284 // sets the proper version as a key of element
285 c->ver[c->next] = ver;
286 }
287
288 // t will point to array element
289 *t = c->tab[c->next];
290
291 // Set the member 'next'. It marks the next element in array it will be modified when failing a search in future
292 c->next = ( c->next + 1 ) % BUFRDECO_TABLES_CACHE_SIZE;
293 return 0;
294}
295
296/*!
297 * \fn int bufrdeco_cache_tables_search ( struct bufr_tables_cache *c, uint8_t ver )
298 * \brief Search a struct \ref bufr_tables in \ref bufr_tables_cache
299 * \param c pointer to the struct \ref bufr_tables_cache where to search
300 * \param ver small int with the master version acting as a key in the seardch
301 *
302 * \return The index of found struct. If no struct found returns -1
303 */
305{
306 buf_t i = 0;
307
308 for ( i = 0; i < BUFRDECO_TABLES_CACHE_SIZE ; i++ )
309 {
310 if ( c->ver[i] == ver )
311 return i; // found
312 }
313 return -1; // Not found
314}
315
316/*!
317 * \fn int bufrdeco_free_cache_tables (struct bufr_tables_cache *c)
318 * \brief deallocate and clean a \ref bufr_tables_cache
319 * \param c pointer to the struct to clean
320 * \return 0 if success
321 */
323{
324 buf_t i;
325
326 for ( i = 0; i < BUFRDECO_TABLES_CACHE_SIZE; i++ )
327 {
328 if ( c->tab[i] )
329 {
330 free ( ( void * ) c->tab[i] );
331 }
332 }
333 // then clean
334 memset ( c, 0, sizeof ( struct bufr_tables_cache ) );
335 return 0;
336}
Include header file for bufrdeco library.
int bufrdeco_init_tables(struct bufr_tables **t)
Init a struct bufr_tables allocating space.
uint32_t buf_t
Type to set offsets and dimension of arrays or counters used in bufrdeco.
Definition: bufrdeco.h:346
#define bufrdeco_assert(__my_expr__)
Check a expression and exit if it fails.
Definition: bufrdeco.h:374
int bufr_read_tableC(struct bufrdeco *b)
Reads a file with table C content (Code table and bit flags) according with csv WMO format.
#define BUFRDECO_TABLES_CACHE_SIZE
Max number of structs bufr_tables in a bufr_tables_cache.
Definition: bufrdeco.h:341
int bufr_read_tableD(struct bufrdeco *b)
Reads a file with table D content according with WMO csv format.
#define BUFRDECO_PATH_LENGTH
Length for files/directory path strings.
Definition: bufrdeco.h:335
#define BUFRDECO_USE_TABLES_CACHE
Bit mask to the member mask of struct bufrdeco to mark the use of bufr_tables cache.
Definition: bufrdeco.h:268
int bufr_read_tableB(struct bufrdeco *b)
const char DEFAULT_BUFRTABLES_WMO_CSV_DIR2[]
Definition: bufrdeco_wmo.c:30
int bufrdeco_free_cache_tables(struct bufr_tables_cache *c)
deallocate and clean a bufr_tables_cache
Definition: bufrdeco_wmo.c:322
int bufr_read_tables(struct bufrdeco *b)
Read the tables according with bufr file data from a bufr table directory.
Definition: bufrdeco_wmo.c:162
int get_wmo_tablenames(struct bufrdeco *b)
Get the complete pathnames for WMO csv table files needed by a bufr message.
Definition: bufrdeco_wmo.c:47
int bufrdeco_store_tables(struct bufr_tables **t, struct bufr_tables_cache *c, uint8_t ver)
Init an element of array c->tab[] if still not allocated. If allocated clean it and set *t pointing t...
Definition: bufrdeco_wmo.c:269
const char DEFAULT_BUFRTABLES_WMO_CSV_DIR1[]
Definition: bufrdeco_wmo.c:29
int bufrdeco_cache_tables_search(struct bufr_tables_cache *c, uint8_t ver)
Search a struct bufr_tables in bufr_tables_cache.
Definition: bufrdeco_wmo.c:304
uint8_t master_version
Definition: bufrdeco.h:782
Store a table B readed from a file formated and named as ECMWF bufrdc package.
Definition: bufrdeco.h:859
struct bufr_tableB_decoded_item item[BUFR_MAXLINES_TABLEB]
Definition: bufrdeco.h:867
buf_t nlines
Definition: bufrdeco.h:863
char path[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:861
char path[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:893
char path[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:922
Struct to store the cache of structs bufr_tables.
Definition: bufrdeco.h:951
int8_t ver[BUFRDECO_TABLES_CACHE_SIZE]
Definition: bufrdeco.h:954
struct bufr_tables * tab[BUFRDECO_TABLES_CACHE_SIZE]
Definition: bufrdeco.h:955
Contains all tables needed to parse a bufr file.
Definition: bufrdeco.h:938
struct bufr_tableD d
Definition: bufrdeco.h:941
struct bufr_tableB b
Definition: bufrdeco.h:939
struct bufr_tableC c
Definition: bufrdeco.h:940
This struct contains all needed data to parse and decode a BUFR file.
Definition: bufrdeco.h:965
uint32_t mask
Definition: bufrdeco.h:966
struct bufr_tables_cache cache
Definition: bufrdeco.h:974
struct bufr_tables * tables
Definition: bufrdeco.h:973
char bufrtables_dir[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:982
char error[1024]
Definition: bufrdeco.h:983
struct bufr_sec1 sec1
Definition: bufrdeco.h:969