[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: 20000209: pqact.conf question
- Subject: Re: 20000209: pqact.conf question
- Date: Thu, 10 Feb 2000 12:35:04 -0700
>
> Date: Wed, 09 Feb 2000 14:38:00 -0700
> From: Unidata Support <address@hidden>
> Reply-To: address@hidden
> To: address@hidden
> Subject: 20000209: pqact.conf question
>
> >To: address@hidden
> >From: address@hidden
> >Subject: pqact.conf question
> >Organization: .
> >Keywords: 200002092105.OAA09525
>
> I need to separate some GRID mesoeta files to send to a decoder. I found
> in the explanation of the /m in the Unidata Dec 1994 archives, but I my
> acqserver inserts products into the queue differently. My headers look
> like:
>
> NOAAPORT.NWSTG.GRID.YZQI.KWBE.091754.2000090275422100
>
> Is there any way I can use the /mETA to separate the mesoeta files? What
> is looking for the /mETA and what should a header look like that will work?
> If I have an example, I might be able to work around it.
>
> Alan.
>
> ****** Signature Tag ******
>
> National Climatic Data Center
Alan,
The headers alone of the GRIB files do not provide for discriminating across the
models. It is our own pqing (product queue ingest) process that inserts the
/m<model> into the header to allow the LDMs downstream to differentiate models.
Your acqserver probably doesn't do such a thing. In order to use our code to
receive and process your data you'll need to add code to acqserver to do the
same.
I've attached the file wmo_message.c, which is where the /m<model> is inserted
into the header. There is a function in there with the signature:
static const char *pds_ident(const char *cp)
that inserts the /m<model>. It is called by the function:
static const char *grib_ident(size_t remaining, const char *const wmo_msg, const
char *const
ident)
You can use this as a starting point. I hope this helps.
Anne
--
***************************************************
Anne Wilson UCAR Unidata Program
address@hidden P.O. Box 3000
(303) 497-8677 Boulder, CO 80307
----------------------------------------------------
Unidata WWW server http://www.unidata.ucar.edu/
****************************************************
/*
* Copyright 1993, University Corporation for Atmospheric Research
* See ../COPYRIGHT file for copying and redistribution conditions.
*/
/* $Id: wmo_message.c,v 1.66 1998/10/16 19:28:58 steve Exp $ */
/*
* Routines to parse wmo messages.
* Ref: _Manual on the Global Telecommunications System_, Volume 1,
* Global Aspects. WMO-No. 386, 1986
*/
#include <ldmconfig.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "ulog.h"
#include "alloc.h"
#include "tokens.h"
#include "xbuf.h"
#include "wmo_message.h"
#define GRIB_RE_IDENT 1
extern void toClients(timestampt arrival,
unsigned seqno,
const char *ident,
unsigned len,
const char *buf);
/* statistics */
static unsigned long completed = 0;
unsigned long sohetx_missed = 0;
unsigned long bad_cksum = 0;
unsigned long not_wmo = 0;
void
wmo_stats(void)
{
unotice(" WMO Messages seen: %8lu", completed);
unotice(" SOH/ETX missing : %8lu", sohetx_missed);
unotice(" parity/chksum err: %8lu", bad_cksum);
unotice(" WMO format errors: %8lu", not_wmo);
}
/*
* Set time stamp and hook up body of message
*/
static wmo_message *
init_wmo_message(
xbuf *buf, /* should be a clone ! */
wmo_message *mess
)
{
mess->len = buf->cnt;
mess->msg = buf->get;
if(set_timestamp(&mess->arrival) != 0)
return NULL;
return mess;
}
wmo_message *
get_wmo_message(xbuf *buf, wmo_message *mess)
{
init_wmo_message(buf, mess);
#if 0
if(mess->msg == NULL || mess->msg[0] != SOH)
return NULL;
if(mess->len < MIN_WMO_MSG_LEN)
return NULL;
#endif
/* skip SOH CR CR NL */
if(skipline(buf, 4) < 0) return NULL;
if( get_wmo_start(buf, mess->start) == NULL )
return NULL;
if( get_wmo_header(buf, mess->hdr) == NULL )
return NULL;
#if 0
if(mess->msg[mess->len-1] != ETX )
return NULL;
#endif
#if 0 /* DEBUG */
fprint_wmo_header(stderr, mess->hdr);
fputc(' ', stderr);
fprint_wmo_start(stderr, mess->start);
fprintf(stderr," \tplen %-7d ok\n", len);
#endif
return mess;
}
#if GRIB_RE_IDENT
# ifndef KEYSIZE
# define KEYSIZE 255
# endif /*!KEYSIZE */
/* Not very efficient for long anchor strings... */
static const char *
scanFor(const char *anchor, size_t len, const char *const buf)
{
const char *ap;
const char *cp;
const char *start = 0;
ap = anchor;
for(cp = buf; len != 0; cp++, len--)
{
if(*cp == *ap)
{
if(ap == anchor)
start = cp;
ap++;
if(*ap)
{
if(len <= 1)
return 0;
if(*ap != *(cp +1))
{
/* restart */
ap = anchor;
start = 0;
}
continue;
}
/* else *ap == 0, done */
return start;
}
}
return 0;
}
static const char *
s_byte(unsigned char bb)
{
static char buf[4];
memset(buf, 0, sizeof(buf));
sprintf(buf, "%d", bb);
return buf;
}
static const char *
s_pds_model(unsigned char model)
{
/* TODO: what are the NWS abbrevs of these ?*/
switch (model) {
case 5: return "SAT"; /* TODO, use pds octet 41 */
case 10: return "NOW";
case 19: return "LFM";
case 25: return "SNO";
case 39: return "NGM";
case 42: return "GOIAVN";
case 43: return "GOI";
case 44: return "SST";
case 53: return "LFM4";
case 64: return "ROI";
case 68: return "SPEC80AVN";
case 69: return "SPEC80MRF";
case 70: return "QLM";
case 73: return "FOG";
case 74: return "WWMEX";
case 75: return "WWAK";
case 76: return "BMRF";
case 77: return "AVN";
case 78: return "MRF";
case 79: return "BACKUP";
case 80: return "SPEC62MRF";
case 81: return "SSIAVN";
case 82: return "SSI";
case 83: return "ETA";
case 84: return "ETA40";
case 85: return "ETA30";
case 86: return "RUC";
case 87: return "ENSMB";
case 88: return "PWAV";
case 89: return "ETA48";
/*
* ECMF entries seem quite volatile.
* Really should be in different table.
*/
case 121: return "ECMF";
case 131: return "ECMF";
case 132: return "ECMF";
case 141: return "ECMF";
case 150: return "RFS";
case 151: return "FFGS";
case 152: return "RAD2";
case 153: return "RAD3";
}
/* default */
return s_byte(model);
}
/*
* offset
*/
#define IDS_LEN (5)
#define PDS_MODEL (6)
static int
ids_len(const char *cp)
{
const unsigned char *up = (const unsigned char *)cp + IDS_LEN -1 ;
int len = *up++ * 256 *256;
len += *up++ * 256;
len += *up;
return len;
}
static const char *
pds_ident(const char *cp)
{
/* assert (pdsp + 28) is valid, accessable memory */
const unsigned char *pdsp = (const unsigned char *)cp -1;
/* -1 trick for 1 based indexing */
static char idb[80];
memset(idb, 0, sizeof(idb));
sprintf(idb, " /m%s",
s_pds_model(*(pdsp + PDS_MODEL)));
return idb;
}
static const char *
grib_ident(size_t remaining, const char *const wmo_msg, const char *const ident)
{
static const char nada[] = "";
const char *cp;
size_t len;
cp = scanFor("GRIB", remaining, wmo_msg);
if(!cp)
{
udebug("%s: Can't find `GRIB'", ident);
return nada;
}
remaining -= cp - wmo_msg;
if(remaining < (8 + 28 +4))
{
udebug("%s: way too short", ident);
return NULL;
}
len = ids_len(cp);
if(remaining < len)
{
udebug("%s: %d bytes too short", ident, len - remaining);
return NULL;
}
if(remaining > len + 8)
{
udebug("%s: garbled product", ident);
udebug("remaining %d, ids_len %d", remaining, len);
return NULL;
}
if(scanFor("7777", 8, cp + len - 8) == NULL)
{
udebug("%s: no end of product", ident);
return NULL;
}
return pds_ident(cp + 8);
}
#endif /* GRIB_RE_IDENT */
const char *
wmo_err_ident(xbuf *buf)
{
static char identbuf[128];
char *cp = identbuf;
xbuf clone[1];
int conv;
(void) memset(identbuf, 0, sizeof(identbuf));
clone_xbuf(buf, clone, 0);
#if 0
conv = sprintf(cp, "%8u ******************",
(unsigned) clone->cnt);
#else
conv = sprintf(cp, "%8u",
(unsigned) clone->cnt);
#endif
cp += conv;
/* skip SOH CR CR NL */
if(skipline(clone, 4) < 0)
return identbuf;
{
wmo_start_t start;
if( get_wmo_start(clone, &start) == NULL )
return identbuf;
conv = sprintf(cp, " %03d", start.seqno);
cp += conv;
}
{
wmo_header_t hdr;
dtime time;
hdr.time = &time;
if( get_wmo_header(clone, &hdr) == NULL )
return identbuf;
conv = sprintf(cp, " %s", s_wmo_header(&hdr));
cp += conv;
assert(cp < &identbuf[sizeof(identbuf)]);
}
return identbuf;
}
void
wmo_send_buf(
xbuf *buf,
int backoff)
{
xbuf clone[1];
wmo_message mess[1];
wmo_start_t start[1];
wmo_header_t hdr[1];
dtime time[1];
char *ident;
mess->start = start;
mess->hdr = hdr;
mess->hdr->time = time;
/* we have a complete message in the xbuf */
clone_xbuf(buf,clone, backoff);
if( get_wmo_message(clone, mess) == NULL
|| start->seqno < 0
|| start->seqno > 999
|| !isalpha(hdr->TT[0])
|| !isalpha(hdr->TT[1])
|| !isalpha(hdr->AA[0])
|| !isalnum(hdr->AA[1])
)
{
not_wmo++;
uerror("Not a WMO format message. %s",
wmo_err_ident(buf));
return;
}
/* else, we got something */
ident = s_wmo_header(mess->hdr);
#if GRIB_RE_IDENT
if(*ident == 'H' || *ident == 'Y' || *ident == 'Z')
{
const char *ni =
grib_ident(mess->len, (char *)mess->msg, ident);
if(ni == NULL)
{
not_wmo++;
uerror("Not a WMO GRIB format message. %s",
wmo_err_ident(buf));
return;
}
/* else */
if(*ni != 0)
{
size_t len = strlen(ident);
strncat(ident, ni, KEYSIZE - len);
}
}
#endif
completed++;
toClients(mess->arrival,
mess->start->seqno,
ident,
(unsigned) mess->len, (char *)mess->msg);
}