/* $Id: BUFR.cpp,v 1.5 2007/02/19 12:53:34 dhurtma Exp $ $Id: BUFR.cpp,v 1.6 2007/06/10 cboonne $ */ #include #include #include #include #include #include // Usefull Window Definitions typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD,DWORD_PTR,LONG; #define BOOL bool #define TRUE 1 #define FALSE 0 #define MAX_PATH 260 #define MAKEWORD(a, b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) #define MAKELONG(a, b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) #define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) #define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) unsigned long convert24_32(unsigned char *lpData) { unsigned long l_data; l_data=lpData[0]; l_data=(l_data<<8)+lpData[1]; l_data=(l_data<<8)+lpData[2]; return l_data; } unsigned short convert16_16(unsigned char *lpData) { unsigned short l_data; l_data=lpData[0]; l_data=(l_data<<8)+lpData[1]; return l_data; } typedef struct _bufr_section_ptrs { long p0; long p1; long p2; long p3; long p4; long p5; } SECTION_PTR; typedef struct bufr_section_0 { char BUFR[4]; static const unsigned long length=8; unsigned long FileLength; unsigned char edition; } SECTION_0,*LPSECTION_0; typedef enum { DC_Surface_Land=0, DC_Surface_Sea, DC_Vertical, DC_Vertical_Satellite, DC_Single_Level_Upper, DC_Single_Level_Upper_Satellite, DC_Surface_Satellite=12, DC_Oceanographic=31 } DATA_CATEGORY; typedef struct bufr_section_1 { unsigned long length; unsigned char Master_Table_Number; unsigned char Sub_Centre; unsigned char Centre; unsigned char Update_Sequence; bool bOptional; DATA_CATEGORY Data_Category; unsigned char Data_Sub_Category; unsigned char Master_Table_Version; unsigned char Local_Table_Version; unsigned short Year; unsigned char Month; unsigned char Day; unsigned char Hour; unsigned char Minute; unsigned char *lpADP_Reserved; } SECTION_1,*LPSECTION_1; typedef struct bufr_section_2 { unsigned long length; unsigned char dummy; unsigned char *lpADP_Reserved; } SECTION_2,*LPSECTION_2; typedef struct bufr_descriptor { unsigned char X : 6; // F=0,3 Class; F=1 # of parameters, F=2 unsigned char F : 2; // 0 --> Element Table B, 1 --> Replicator, 2 --> Operator Table C, 3 --> Sequence Table D unsigned char Y; // F=0,3 Entry within class, F=1 times to replicate if 0 read in data } DESCRIPTOR,*LPDESCRIPTOR; typedef struct bufr_section_3 { unsigned long length; unsigned char dummy; unsigned short Number_Subsets; bool bObserved; bool bCompressed; unsigned long Number_Descriptors; LPDESCRIPTOR lpDescriptors; } SECTION_3,*LPSECTION_3; typedef struct bufr_section_4 { unsigned long length; unsigned char dummy; unsigned char *lpData; } SECTION_4,*LPSECTION_4; typedef struct bufr_3_40_002 { unsigned short Start_Channel; // 14 bits unsigned short End_Channel; // 14 bits unsigned char Channel_Scale_Factor; // 6 bits }DESCR_3_40_002; typedef struct bufr_3_40_003 { unsigned short Channel_Number[100]; // 14 bits unsigned short Scaled_Iasi_Radiance[100];// 16 bits }DESCR_3_40_003; typedef struct bufr_3_40_004 { unsigned long Y_angular_position; // 24 bits unsigned long Z_angular_position; // 24 bits unsigned char Fraction_clear_pixels_HIRS;// 7 bits unsigned char Channel_Number[6]; // 6 bits unsigned char Channel_Scale_Factor_1[6]; // 6 bits unsigned long Scaled_Mean_AVHRR_Rad[6]; // 31 bits unsigned char Channel_Scale_Factor_2[6]; // 6 bits unsigned long Scaled_Std_AVHRR_Rad[6]; // 31 bits }DESCR_3_40_004; typedef struct bufr_3_40_001 { unsigned short Satellite_Identifier; // 10 bits unsigned short Originating_Centre; // 16 bits unsigned short Satellite_Instruments_1; // 11 bits unsigned short Satellite_Classification; // 9 bits unsigned short Year; // 12 bits unsigned char Month; // 4 bits unsigned char Day; // 6 bits unsigned char Hour; // 5 bits unsigned char Minute; // 6 bits unsigned short Second; // 16 bits unsigned long Latitude; // 25 bits unsigned long Longitude; // 26 bits unsigned short Satellite_Zenith_Angle; // 15 bits unsigned short Azimuth; // 16 bits unsigned short Solar_Zenith_Angle; // 15 bits unsigned short Solar_Azimuth; // 16 bits unsigned char FOV_Number; // 8 bits unsigned long Orbit_Number; // 24 bits unsigned short Scan_Line_Number; // 13 bits unsigned char Major_Frame_Count; // 8 bits unsigned short Height_of_Station; // 15 bits unsigned char GQisFlagQual; // 2 bits unsigned char QGisQualIndex; // 7 bits unsigned char QGisQualIndexLoc; // 7 bits unsigned char QGisQualIndexRad; // 7 bits unsigned char QGisQualIndexSpect; // 7 bits unsigned long GQisQualIndexTexSondQual; // 24 bits DESCR_3_40_002 Band_Description[10]; DESCR_3_40_003 Channels_Sequence[87]; unsigned short Satellite_Instruments_2; // 11 bits unsigned char AVHRR_channel_combination;// 7 bits DESCR_3_40_004 AVHRR_Scene_Sequence[7]; }DESCR_3_40_001; typedef struct iasi_amp { char szMagic[16]; // AMP_IASI_V1 double date; double Latitude; double Longitude; unsigned char QualFlag; double Satellite_Zenith_Angle; double Azimuth; double Solar_Zenith_Angle; double Solar_Azimuth; unsigned long Orbit_Number; double Height_of_Station; double Cloud_Free_Fraction[7]; double AVHRR_Mean[6][7]; double AVHRR_Std[6][7]; double nu_start; double nu_end; long nbp; double Radiance[8700]; } IASI_AMP,*LPIASI_AMP; IASI_AMP specs[120]; BOOL ProcessCompressedIasiLevel1CData(SECTION_1 s1,SECTION_3 s3,SECTION_4 s4,LPIASI_AMP specs); void bufr_parse_section_4(unsigned char *lpData,SECTION_4 &s4) { unsigned short offset=3; unsigned long length_Data; s4.length=convert24_32(lpData); s4.dummy=lpData[offset++]; length_Data=s4.length-offset; s4.lpData=(unsigned char*)malloc(length_Data); memcpy(s4.lpData,lpData+offset,length_Data); } void bufr_free_s4(SECTION_4 &s4) { if (s4.lpData) free(s4.lpData); } void bufr_parse_section_3(unsigned char *lpData,SECTION_3 &s3) { unsigned short offset=3; unsigned long length_Descriptor; s3.length=convert24_32(lpData); s3.dummy=lpData[offset++]; s3.Number_Subsets=convert16_16(lpData+offset) ; offset=6; s3.bObserved=((lpData[offset]&128)==128); s3.bCompressed=((lpData[offset]&64)==64); offset=7; length_Descriptor=s3.length-offset; s3.Number_Descriptors=length_Descriptor/2; s3.lpDescriptors=(LPDESCRIPTOR)malloc(length_Descriptor); memcpy(s3.lpDescriptors,lpData+offset,length_Descriptor); } void bufr_free_s3(SECTION_3 &s3) { if (s3.lpDescriptors) free(s3.lpDescriptors); } void bufr_parse_section_2(unsigned char *lpData,SECTION_2 &s2) { unsigned short offset=4; unsigned long length_Reserved; s2.length=convert24_32(lpData); s2.dummy=lpData[3]; length_Reserved=s2.length-offset; s2.lpADP_Reserved=(unsigned char*)malloc(length_Reserved); memcpy(s2.lpADP_Reserved,lpData+offset,length_Reserved); } void bufr_free_s2(SECTION_2 &s2) { if (s2.lpADP_Reserved) free(s2.lpADP_Reserved); } void bufr_parse_section_1(unsigned char *lpData,SECTION_1 &s1) { unsigned short offset=3; unsigned long length_Reserved; s1.length=convert24_32(lpData); s1.Master_Table_Number=lpData[offset++]; s1.Sub_Centre=lpData[offset++]; s1.Centre=lpData[offset++]; s1.Update_Sequence=lpData[offset++]; s1.bOptional=((lpData[offset++]&128)==128); s1.Data_Category=(DATA_CATEGORY)lpData[offset++]; s1.Data_Sub_Category=lpData[offset++]; s1.Master_Table_Version=lpData[offset++]; s1.Local_Table_Version=lpData[offset++]; s1.Year=2000+lpData[offset++]; s1.Month=lpData[offset++]; s1.Day=lpData[offset++]; s1.Hour=lpData[offset++]; s1.Minute=lpData[offset++]; length_Reserved=s1.length-offset; s1.lpADP_Reserved=(unsigned char*)malloc(length_Reserved); memcpy(s1.lpADP_Reserved,lpData+offset,length_Reserved); } void bufr_free_s1(SECTION_1 &s1) { if (s1.lpADP_Reserved) free(s1.lpADP_Reserved); } void bufr_parse_section_0(unsigned char *lpData,SECTION_0 &s0) { memcpy(s0.BUFR,lpData,4); s0.FileLength=convert24_32(lpData+4); s0.edition=lpData[7]; } int main(int argc, char* argv[]) { FILE *fin; unsigned char *lpData; unsigned long DataAllocated; unsigned long length; SECTION_0 s0={0}; SECTION_1 s1={0}; SECTION_2 s2={0}; SECTION_3 s3={0}; SECTION_4 s4={0}; long it=0; long filelength; unsigned long i,j,k; SECTION_PTR sp; BOOL bAnswer; fin=fopen(argv[1],"rb"); DataAllocated=8; lpData=(unsigned char*)malloc(DataAllocated); fseek(fin,0,SEEK_END); filelength=ftell(fin); sp.p0=0; L_AGAIN: it++; // Add preamble sp.p0+=34; //Orbit, hour,...? // Section 0 if (fseek(fin,sp.p0,SEEK_SET)>0) goto L_FIN; // Section 0 is always 8 bytes long length=8; // Read & parse if (fread(lpData,length,1,fin)<1) goto L_FIN; bufr_parse_section_0(lpData,s0); sp.p1=sp.p0+s0.length; // Section 1 fseek(fin,sp.p1,SEEK_SET); // Get length fread(lpData,3,1,fin); length=convert24_32(lpData); // Reallocate buffer if needed if (length>DataAllocated) { DataAllocated=length; lpData=(unsigned char*)realloc(lpData,length); } // Read & parse fseek(fin,sp.p1,SEEK_SET); fread(lpData,length,1,fin); bufr_parse_section_1(lpData,s1); if (s1.bOptional) { sp.p2=sp.p1+s1.length; // Section 2 fseek(fin,sp.p2,SEEK_SET); // Get length fread(lpData,3,1,fin); length=convert24_32(lpData); // Reallocate buffer if needed if (length>DataAllocated) { DataAllocated=length; lpData=(unsigned char*)realloc(lpData,length); } // Read & parse fseek(fin,sp.p2,SEEK_SET); fread(lpData,length,1,fin); bufr_parse_section_2(lpData,s2); sp.p3=sp.p2+s2.length; } else { sp.p2=-1; sp.p3=sp.p1+s1.length; } // Section 3 fseek(fin,sp.p3,SEEK_SET); // Get length fread(lpData,3,1,fin); length=convert24_32(lpData); // Reallocate buffer if needed if (length>DataAllocated) { DataAllocated=length; lpData=(unsigned char*)realloc(lpData,length); } // Read & parse fseek(fin,sp.p3,SEEK_SET); fread(lpData,length,1,fin); bufr_parse_section_3(lpData,s3); sp.p4=sp.p3+s3.length; // Section 4 fseek(fin,sp.p4,SEEK_SET); // Get length fread(lpData,3,1,fin); length=convert24_32(lpData); // Reallocate buffer if needed if (length>DataAllocated) { DataAllocated=length; lpData=(unsigned char*)realloc(lpData,length); } // Read & parse fseek(fin,sp.p4,SEEK_SET); memset(lpData,0xff,length); fread(lpData,1,length,fin); bufr_parse_section_4(lpData,s4); sp.p5=sp.p4+s4.length; /* for (i=0;i %.1d %.2d %.3d\n",it,i,s3.lpDescriptors[i].F,s3.lpDescriptors[i].X,s3.lpDescriptors[i].Y); } */ //Check section 5 is 7777 fseek(fin,sp.p5,SEEK_SET); fread(lpData,4,1,fin); if (strncmp((char*)lpData,"7777",4)!=0) printf("Error\n"); // Process lpdata bAnswer=ProcessCompressedIasiLevel1CData(s1,s3,s4,specs); /* if (bAnswer) printf("AVHRR status : Seems OK\n"); else printf("AVHRR status : Seems Corrupt\n"); */ // Save spectra... for (k=0;k<120;++k) { char szFName[MAX_PATH]; FILE *fSpec; sprintf(szFName,"%15.6lf_%.3d_%.5d_%.5d.asc",specs[k].date,k+1,int((specs[k].Latitude+90)*100),int((specs[k].Longitude+180)*100)); fSpec=fopen(szFName,"w"); fprintf(fSpec,"==========================================================\n"); { struct tm *newTime; time_t szClock; // Get time in seconds time( &szClock ); // Convert time to struct tm form newTime = localtime( &szClock ); // Note: asctime is deprecated; consider using asctime_s instead fprintf(fSpec,"IASI file converted on %s", asctime(newTime)) ; } fprintf(fSpec,"==========================================================\n"); fprintf(fSpec,"%15.9lf : Date\n",specs[k].date); fprintf(fSpec,"%.08d : Orbit Number\n",specs[k].Orbit_Number); switch (specs[k].QualFlag) { case 0: fprintf(fSpec,"good : Quality Flag\n"); break; case 1: fprintf(fSpec,"bad : Quality Flag\n"); break; case 2: fprintf(fSpec,"reserved : Quality Flag\n"); break; case 3: fprintf(fSpec,"missing : Quality Flag\n"); break; } /* if (bAnswer) fprintf(fSpec,"AVHRR status : Seems OK\n"); else fprintf(fSpec,"AVHRR status : Seems Corrupt\n"); */ printf("%+7.5lf,%+7.5lf,%5.2lf,%5.1lf,%15.9lf,%.08d,%s,%.1d\n",specs[k].Latitude,specs[k].Longitude,specs[k].Satellite_Zenith_Angle, specs[k].Height_of_Station,specs[k].date,specs[k].Orbit_Number,szFName,specs[k].QualFlag); fprintf(fSpec,"%+7.5lf : Latitude(?)\n",specs[k].Latitude); fprintf(fSpec,"%+7.5lf : Longitude(?)\n",specs[k].Longitude); fprintf(fSpec,"%5.2lf : Sat ZA(?)\n",specs[k].Satellite_Zenith_Angle); fprintf(fSpec,"%5.2lf : Sat AZ(?)\n",specs[k].Azimuth); fprintf(fSpec,"%5.2lf : Sun ZA(?)\n",specs[k].Solar_Zenith_Angle); fprintf(fSpec,"%5.2lf : Sun AZ(?)\n",specs[k].Solar_Azimuth); fprintf(fSpec,"%5.1lf : Altitude(km)\n",specs[k].Height_of_Station); fprintf(fSpec," "); for (i=0;i<7;++i) fprintf(fSpec,"%+2.0lf ",specs[k].Cloud_Free_Fraction[i]); fprintf(fSpec," : Cloud Free(%%)\n"); for (j=0;j<6;++j) { fprintf(fSpec,"AVHRR Pixel : %.1d\n",j+1); fprintf(fSpec," Mean : "); for (i=0;i<7;++i) fprintf(fSpec,"%.4le ",specs[k].AVHRR_Mean[j][i]); fprintf(fSpec,"\n"); fprintf(fSpec," Std : "); for (i=0;i<7;++i) fprintf(fSpec,"%.4le ",specs[k].AVHRR_Std[j][i]); fprintf(fSpec,"\n"); } fprintf(fSpec,"%7.2lf : nu start(cm-1)\n",specs[k].nu_start); fprintf(fSpec,"%7.2lf : nu end(cm-1)\n",specs[k].nu_end); fprintf(fSpec,"%.3d : nbp\n",specs[k].nbp); fprintf(fSpec,"==========================================================\n"); for (int i=0;i<8700;++i) fprintf(fSpec,"%+.4le\n",specs[k].Radiance[i]); fclose(fSpec); } // Cleanup and free bufr_free_s1(s1); bufr_free_s2(s2); bufr_free_s3(s3); bufr_free_s4(s4); sp.p0=sp.p5+4; // size of section 5 sp.p0+=4; // End of message post bytes if (sp.p00); // Transfer from lpData to Buffer with byte reversing for (int i=0;i>=Shift_8; // Align bits to the window Work&=Mask; // Apply the mask ByteTempBuffer[0]=Work; // Save Work back in buffer break; } case 2: { char Shift_16; unsigned short Mask; unsigned short Work; Shift_16=(16-BitPos)-NbBits; Mask=((unsigned short)1<>=Shift_16; // Align bits to the window Work&=Mask; // Apply the mask ByteTempBuffer[0]=LOBYTE(Work); // Save Work back in buffer with proper "endianness" ByteTempBuffer[1]=HIBYTE(Work); break; } case 3: { char Shift_24; unsigned long Mask; // Work in 4 bytes as there is no 3 bytes types unsigned long Work; unsigned short W1,W2; Shift_24=(24-BitPos)-NbBits; Mask=((unsigned long)1<>=Shift_24; // Align bits to the window Work&=Mask; // Apply the mask W1=LOWORD(Work); W2=HIWORD(Work); ByteTempBuffer[0]=LOBYTE(W1); // Save Work back in buffer with proper "endianness" ByteTempBuffer[1]=HIBYTE(W1); ByteTempBuffer[2]=LOBYTE(W2); ByteTempBuffer[3]=0; break; } case 4: { char Shift_32; unsigned long Mask; unsigned long Work; unsigned short W1,W2; Shift_32=(32-BitPos)-NbBits; Mask=((unsigned long)1<>=Shift_32; // Align bits to the window Work&=Mask; // Apply the mask W1=LOWORD(Work); W2=HIWORD(Work); ByteTempBuffer[0]=LOBYTE(W1); // Save Work back in buffer with proper "endianness" ByteTempBuffer[1]=HIBYTE(W1); ByteTempBuffer[2]=LOBYTE(W2); ByteTempBuffer[3]=HIBYTE(W2); break; } case 5: unsigned char Shift_40; unsigned long Mask; // Use more than 4 bytes but store only on 4 unsigned long Work; unsigned char WorkLSB; unsigned char ShiftLSB; unsigned short W1,W2; Shift_40=BitPos+NbBits-32; Mask=((unsigned long)1<>=ShiftLSB; Work|=WorkLSB; // Join the shifted LSB bits to Work Work&=Mask; // Apply the mask W1=LOWORD(Work); W2=HIWORD(Work); ByteTempBuffer[0]=LOBYTE(W1); // Save Work back in buffer with proper "endianness" ByteTempBuffer[1]=HIBYTE(W1); ByteTempBuffer[2]=LOBYTE(W2); ByteTempBuffer[3]=HIBYTE(W2); break; } // Set return value memcpy(lpTempReturn,ByteTempBuffer,ReturnSize); // Update position BitPos+=NbBits; BytePos+=BitPos/8; BitPos%=8; } BOOL ProcessCompressedIasiLevel1CData(SECTION_1 s1,SECTION_3 s3,SECTION_4 s4,LPIASI_AMP specs) { unsigned char NbBits; DESCR_3_40_002 LocalChannel[120*10]; DESCR_3_40_001 LocalBufr; for (int k=0;k<120;++k) { specs[k].nbp=8700; specs[k].nu_start=645.; specs[k].nu_end=2819.75; strcpy(specs[k].szMagic,"AMP_IASI_V1"); } GetNextBits(0,0,0,0,true); GetNextBits(s4.lpData,10,sizeof(LocalBufr.Satellite_Identifier),&LocalBufr.Satellite_Identifier,false); GetNextBits(s4.lpData,6,sizeof(NbBits),&NbBits,false); if (NbBits>0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k0) { for (long k=0;k24) { return FALSE; } if (NbBits>0) { for (long k=0;k24) { return FALSE; } if (NbBits>0) { for (long k=0;k7) { return FALSE; } if (NbBits>0) { for (long k=0;k6) { return FALSE; } if (NbBits>0) { for (long k=0;k6) { return FALSE; } if (NbBits>0) { for (long k=0;k31) { return FALSE; } if (NbBits>0) { for (long k=0;k6) { return FALSE; } if (NbBits>0) { for (long k=0;k31) { return FALSE; } if (NbBits>0) { for (long k=0;k