/* ** Return a pointer to a specific glyph's data. */ BYTE *find_glyph_data(struct TTFONT *font, int charindex) { ULONG off; ULONG length; /* Read the glyph offset from the index to location table. */ if (font->indexToLocFormat == 0) { off = getUSHORT( font->loca_table + (charindex * 2) ); off *= 2; length = getUSHORT( font->loca_table + ((charindex+1) * 2) ); length *= 2; length -= off; } else { off = getULONG( font->loca_table + (charindex * 4) ); length = getULONG( font->loca_table + ((charindex+1) * 4) ); length -= off; } if (length > 0) { return font->glyf_table + off; } else { return (BYTE*)NULL; } } /* end of find_glyph_data() */
/* ** This routine is called by the one below. ** It is also called from pprdrv_tt2.c */ const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) { int GlyphIndex; static char temp[80]; char *ptr; ULONG len; GlyphIndex = (int)getUSHORT( font->post_table + 34 + (charindex * 2) ); if ( GlyphIndex <= 257 ) /* If a standard Apple name, */ { return Apple_CharStrings[GlyphIndex]; } else /* Otherwise, use one */ { /* of the pascal strings. */ GlyphIndex -= 258; /* Set pointer to start of Pascal strings. */ ptr = (char*)(font->post_table + 34 + (font->numGlyphs * 2)); len = (ULONG)*(ptr++); /* Step thru the strings */ while (GlyphIndex--) /* until we get to the one */ { /* that we want. */ ptr += len; len = (ULONG)*(ptr++); } if ( len >= sizeof(temp) ) { throw TTException("TrueType font file contains a very long PostScript name"); } strncpy(temp,ptr,len); /* Copy the pascal string into */ temp[len]=(char)NULL; /* a buffer and make it ASCIIz. */ return temp; } } /* end of ttfont_CharStrings_getname() */
/* ** Some of the given glyph ids may refer to composite glyphs. ** This function adds all of the dependencies of those composite ** glyphs to the glyph id vector. Michael Droettboom [06-07-07] */ void ttfont_add_glyph_dependencies(struct TTFONT *font, std::vector<int>& glyph_ids) { std::sort(glyph_ids.begin(), glyph_ids.end()); std::stack<int> glyph_stack; for (std::vector<int>::iterator i = glyph_ids.begin(); i != glyph_ids.end(); ++i) { glyph_stack.push(*i); } while (glyph_stack.size()) { int gind = glyph_stack.top(); glyph_stack.pop(); BYTE* glyph = find_glyph_data( font, gind ); if (glyph != (BYTE*)NULL) { int num_ctr = getSHORT(glyph); if (num_ctr <= 0) // This is a composite glyph { glyph += 10; USHORT flags = 0; do { flags = getUSHORT(glyph); glyph += 2; gind = (int)getUSHORT(glyph); glyph += 2; std::vector<int>::iterator insertion = std::lower_bound(glyph_ids.begin(), glyph_ids.end(), gind); if (*insertion != gind) { glyph_ids.insert(insertion, gind); glyph_stack.push(gind); } if (flags & ARG_1_AND_2_ARE_WORDS) { glyph += 4; } else { glyph += 2; } if (flags & WE_HAVE_A_SCALE) { glyph += 2; } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { glyph += 4; } else if (flags & WE_HAVE_A_TWO_BY_TWO) { glyph += 8; } } while (flags & MORE_COMPONENTS); } } } }
/* ** Emmit PostScript code for a composite character. */ void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph) { USHORT flags; USHORT glyphIndex; int arg1; int arg2; USHORT xscale; USHORT yscale; USHORT scale01; USHORT scale10; /* Once around this loop for each component. */ do { flags = getUSHORT(glyph); /* read the flags word */ glyph += 2; glyphIndex = getUSHORT(glyph); /* read the glyphindex word */ glyph += 2; if (flags & ARG_1_AND_2_ARE_WORDS) { /* The tt spec. seems to say these are signed. */ arg1 = getSHORT(glyph); glyph += 2; arg2 = getSHORT(glyph); glyph += 2; } else /* The tt spec. does not clearly indicate */ { /* whether these values are signed or not. */ arg1 = *(signed char *)(glyph++); arg2 = *(signed char *)(glyph++); } if (flags & WE_HAVE_A_SCALE) { xscale = yscale = getUSHORT(glyph); glyph += 2; scale01 = scale10 = 0; } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { xscale = getUSHORT(glyph); glyph += 2; yscale = getUSHORT(glyph); glyph += 2; scale01 = scale10 = 0; } else if (flags & WE_HAVE_A_TWO_BY_TWO) { xscale = getUSHORT(glyph); glyph += 2; scale01 = getUSHORT(glyph); glyph += 2; scale10 = getUSHORT(glyph); glyph += 2; yscale = getUSHORT(glyph); glyph += 2; } else { xscale = yscale = scale01 = scale10 = 0; } /* Debugging */ #ifdef DEBUG_TRUETYPE stream.printf("%% flags=%d, arg1=%d, arg2=%d, xscale=%d, yscale=%d, scale01=%d, scale10=%d\n", (int)flags,arg1,arg2,(int)xscale,(int)yscale,(int)scale01,(int)scale10); #endif if (pdf_mode) { if ( flags & ARGS_ARE_XY_VALUES ) { /* We should have been able to use 'Do' to reference the subglyph here. However, that doesn't seem to work with xpdf or gs (only acrobat), so instead, this just includes the subglyph here inline. */ stream.printf("q 1 0 0 1 %d %d cm\n", topost(arg1), topost(arg2)); } else { stream.printf("%% unimplemented shift, arg1=%d, arg2=%d\n",arg1,arg2); } GlyphToType3(stream, font, glyphIndex, true); if ( flags & ARGS_ARE_XY_VALUES ) { stream.printf("\nQ\n"); } } else { /* If we have an (X,Y) shif and it is non-zero, */ /* translate the coordinate system. */ if ( flags & ARGS_ARE_XY_VALUES ) { if ( arg1 != 0 || arg2 != 0 ) stream.printf("gsave %d %d translate\n", topost(arg1), topost(arg2) ); } else { stream.printf("%% unimplemented shift, arg1=%d, arg2=%d\n",arg1,arg2); } /* Invoke the CharStrings procedure to print the component. */ stream.printf("false CharStrings /%s get exec\n", ttfont_CharStrings_getname(font,glyphIndex)); /* If we translated the coordinate system, */ /* put it back the way it was. */ if ( flags & ARGS_ARE_XY_VALUES && (arg1 != 0 || arg2 != 0) ) { stream.puts("grestore "); } } } while (flags & MORE_COMPONENTS); } /* end of do_composite() */
/* ** Load the simple glyph data pointed to by glyph. ** The pointer "glyph" should point 10 bytes into ** the glyph data. */ void GlyphToType3::load_char(TTFONT* font, BYTE *glyph) { int x; BYTE c, ct; /* Read the contour endpoints list. */ epts_ctr = (int *)calloc(num_ctr,sizeof(int)); for (x = 0; x < num_ctr; x++) { epts_ctr[x] = getUSHORT(glyph); glyph += 2; } /* From the endpoint of the last contour, we can */ /* determine the number of points. */ num_pts = epts_ctr[num_ctr-1]+1; #ifdef DEBUG_TRUETYPE debug("num_pts=%d",num_pts); stream.printf("%% num_pts=%d\n",num_pts); #endif /* Skip the instructions. */ x = getUSHORT(glyph); glyph += 2; glyph += x; /* Allocate space to hold the data. */ tt_flags = (BYTE *)calloc(num_pts,sizeof(BYTE)); xcoor = (FWord *)calloc(num_pts,sizeof(FWord)); ycoor = (FWord *)calloc(num_pts,sizeof(FWord)); /* Read the flags array, uncompressing it as we go. */ /* There is danger of overflow here. */ for (x = 0; x < num_pts; ) { tt_flags[x++] = c = *(glyph++); if (c&8) /* If next byte is repeat count, */ { ct = *(glyph++); if ( (x + ct) > num_pts ) { throw TTException("Error in TT flags"); } while (ct--) { tt_flags[x++] = c; } } } /* Read the x coordinates */ for (x = 0; x < num_pts; x++) { if (tt_flags[x] & 2) /* one byte value with */ { /* external sign */ c = *(glyph++); xcoor[x] = (tt_flags[x] & 0x10) ? c : (-1 * (int)c); } else if (tt_flags[x] & 0x10) /* repeat last */ { xcoor[x] = 0; } else /* two byte signed value */ { xcoor[x] = getFWord(glyph); glyph+=2; } } /* Read the y coordinates */ for (x = 0; x < num_pts; x++) { if (tt_flags[x] & 4) /* one byte value with */ { /* external sign */ c = *(glyph++); ycoor[x] = (tt_flags[x] & 0x20) ? c : (-1 * (int)c); } else if (tt_flags[x] & 0x20) /* repeat last value */ { ycoor[x] = 0; } else /* two byte signed value */ { ycoor[x] = getUSHORT(glyph); glyph+=2; } } /* Convert delta values to absolute values. */ for (x = 1; x < num_pts; x++) { xcoor[x] += xcoor[x-1]; ycoor[x] += ycoor[x-1]; } for (x=0; x < num_pts; x++) { xcoor[x] = topost(xcoor[x]); ycoor[x] = topost(ycoor[x]); } } /* end of load_char() */
/*-------------------------------------------------------------------- ** Load the 'name' table, get information from it, ** and store that information in the font structure. ** ** The 'name' table contains information such as the name of ** the font, and it's PostScript name. --------------------------------------------------------------------*/ void Read_name(struct TTFONT *font) { BYTE *table_ptr,*ptr2; int numrecords; /* Number of strings in this table */ BYTE *strings; /* pointer to start of string storage */ int x; int platform,encoding; /* Current platform id, encoding id, */ int language,nameid; /* language id, name id, */ int offset,length; /* offset and length of string. */ #ifdef DEBUG_TRUETYPE debug("Read_name()"); #endif table_ptr = NULL; /* Set default values to avoid future references to undefined * pointers. Allocate each of PostName, FullName, FamilyName, * Version, and Style separately so they can be freed safely. */ for (char **ptr = &(font->PostName); ptr != NULL; ) { *ptr = (char*) calloc(sizeof(char), strlen("unknown")+1); strcpy(*ptr, "unknown"); if (ptr == &(font->PostName)) ptr = &(font->FullName); else if (ptr == &(font->FullName)) ptr = &(font->FamilyName); else if (ptr == &(font->FamilyName)) ptr = &(font->Version); else if (ptr == &(font->Version)) ptr = &(font->Style); else ptr = NULL; } font->Copyright = font->Trademark = (char*)NULL; table_ptr = GetTable(font, "name"); /* pointer to table */ try { numrecords = getUSHORT( table_ptr + 2 ); /* number of names */ strings = table_ptr + getUSHORT( table_ptr + 4 ); /* start of string storage */ ptr2 = table_ptr + 6; for (x=0; x < numrecords; x++,ptr2+=12) { platform = getUSHORT(ptr2); encoding = getUSHORT(ptr2+2); language = getUSHORT(ptr2+4); nameid = getUSHORT(ptr2+6); length = getUSHORT(ptr2+8); offset = getUSHORT(ptr2+10); #ifdef DEBUG_TRUETYPE debug("platform %d, encoding %d, language 0x%x, name %d, offset %d, length %d", platform,encoding,language,nameid,offset,length); #endif /* Copyright notice */ if ( platform == 1 && nameid == 0 ) { font->Copyright = (char*)calloc(sizeof(char),length+1); strncpy(font->Copyright,(const char*)strings+offset,length); font->Copyright[length]=(char)NULL; replace_newlines_with_spaces(font->Copyright); #ifdef DEBUG_TRUETYPE debug("font->Copyright=\"%s\"",font->Copyright); #endif continue; } /* Font Family name */ if ( platform == 1 && nameid == 1 ) { free(font->FamilyName); font->FamilyName = (char*)calloc(sizeof(char),length+1); strncpy(font->FamilyName,(const char*)strings+offset,length); font->FamilyName[length]=(char)NULL; replace_newlines_with_spaces(font->FamilyName); #ifdef DEBUG_TRUETYPE debug("font->FamilyName=\"%s\"",font->FamilyName); #endif continue; } /* Font Family name */ if ( platform == 1 && nameid == 2 ) { free(font->Style); font->Style = (char*)calloc(sizeof(char),length+1); strncpy(font->Style,(const char*)strings+offset,length); font->Style[length]=(char)NULL; replace_newlines_with_spaces(font->Style); #ifdef DEBUG_TRUETYPE debug("font->Style=\"%s\"",font->Style); #endif continue; } /* Full Font name */ if ( platform == 1 && nameid == 4 ) { free(font->FullName); font->FullName = (char*)calloc(sizeof(char),length+1); strncpy(font->FullName,(const char*)strings+offset,length); font->FullName[length]=(char)NULL; replace_newlines_with_spaces(font->FullName); #ifdef DEBUG_TRUETYPE debug("font->FullName=\"%s\"",font->FullName); #endif continue; } /* Version string */ if ( platform == 1 && nameid == 5 ) { free(font->Version); font->Version = (char*)calloc(sizeof(char),length+1); strncpy(font->Version,(const char*)strings+offset,length); font->Version[length]=(char)NULL; replace_newlines_with_spaces(font->Version); #ifdef DEBUG_TRUETYPE debug("font->Version=\"%s\"",font->Version); #endif continue; } /* PostScript name */ if ( platform == 1 && nameid == 6 ) { free(font->PostName); font->PostName = (char*)calloc(sizeof(char),length+1); strncpy(font->PostName,(const char*)strings+offset,length); font->PostName[length]=(char)NULL; replace_newlines_with_spaces(font->PostName); #ifdef DEBUG_TRUETYPE debug("font->PostName=\"%s\"",font->PostName); #endif continue; } /* Trademark string */ if ( platform == 1 && nameid == 7 ) { font->Trademark = (char*)calloc(sizeof(char),length+1); strncpy(font->Trademark,(const char*)strings+offset,length); font->Trademark[length]=(char)NULL; replace_newlines_with_spaces(font->Trademark); #ifdef DEBUG_TRUETYPE debug("font->Trademark=\"%s\"",font->Trademark); #endif continue; } } } catch (TTException& ) { free(table_ptr); throw; } free(table_ptr); } /* end of Read_name() */
/* ** We may have to break up the 'glyf' table. That is the reason ** why we provide this special routine to copy it into the sfnts ** array. */ void sfnts_glyf_table(TTStreamWriter& stream, struct TTFONT *font, ULONG oldoffset, ULONG correct_total_length) { ULONG off; ULONG length; int c; ULONG total=0; /* running total of bytes written to table */ int x; bool loca_is_local=false; #ifdef DEBUG_TRUETYPE debug("sfnts_glyf_table(font,%d)", (int)correct_total_length); #endif if (font->loca_table == NULL) { font->loca_table = GetTable(font,"loca"); loca_is_local = true; } /* Seek to proper position in the file. */ fseek( font->file, oldoffset, SEEK_SET ); /* Copy the glyphs one by one */ for (x=0; x < font->numGlyphs; x++) { /* Read the glyph offset from the index-to-location table. */ if (font->indexToLocFormat == 0) { off = getUSHORT( font->loca_table + (x * 2) ); off *= 2; length = getUSHORT( font->loca_table + ((x+1) * 2) ); length *= 2; length -= off; } else { off = getULONG( font->loca_table + (x * 4) ); length = getULONG( font->loca_table + ((x+1) * 4) ); length -= off; } #ifdef DEBUG_TRUETYPE debug("glyph length=%d",(int)length); #endif /* Start new string if necessary. */ sfnts_new_table( stream, (int)length ); /* ** Make sure the glyph is padded out to a ** two byte boundary. */ if ( length % 2 ) { throw TTException("TrueType font contains a 'glyf' table without 2 byte padding"); } /* Copy the bytes of the glyph. */ while ( length-- ) { if ( (c = fgetc(font->file)) == EOF ) { throw TTException("TrueType font may be corrupt (reason 6)"); } sfnts_pputBYTE(stream, c); total++; /* add to running total */ } } if (loca_is_local) { free(font->loca_table); font->loca_table = NULL; } /* Pad out to full length from table directory */ while ( total < correct_total_length ) { sfnts_pputBYTE(stream, 0); total++; } } /* end of sfnts_glyf_table() */
void read_font(const char *filename, font_type_enum target_type, std::vector<int>& glyph_ids, TTFONT& font) { BYTE *ptr; /* Decide what type of PostScript font we will be generating. */ font.target_type = target_type; if (font.target_type == PS_TYPE_42) { bool has_low = false; bool has_high = false; for (std::vector<int>::const_iterator i = glyph_ids.begin(); i != glyph_ids.end(); ++i) { if (*i > 255) { has_high = true; if (has_low) break; } else { has_low = true; if (has_high) break; } } if (has_high && has_low) { font.target_type = PS_TYPE_42_3_HYBRID; } else if (has_high && !has_low) { font.target_type = PS_TYPE_3; } } /* Save the file name for error messages. */ font.filename=filename; /* Open the font file */ if ( (font.file = fopen(filename,"rb")) == (FILE*)NULL ) { throw TTException("Failed to open TrueType font"); } /* Allocate space for the unvarying part of the offset table. */ assert(font.offset_table == NULL); font.offset_table = (BYTE*)calloc( 12, sizeof(BYTE) ); /* Read the first part of the offset table. */ if ( fread( font.offset_table, sizeof(BYTE), 12, font.file ) != 12 ) { throw TTException("TrueType font may be corrupt (reason 1)"); } /* Determine how many directory entries there are. */ font.numTables = getUSHORT( font.offset_table + 4 ); #ifdef DEBUG_TRUETYPE debug("numTables=%d",(int)font.numTables); #endif /* Expand the memory block to hold the whole thing. */ font.offset_table = (BYTE*)realloc( font.offset_table, sizeof(BYTE) * (12 + font.numTables * 16) ); /* Read the rest of the table directory. */ if ( fread( font.offset_table + 12, sizeof(BYTE), (font.numTables*16), font.file ) != (font.numTables*16) ) { throw TTException("TrueType font may be corrupt (reason 2)"); } /* Extract information from the "Offset" table. */ font.TTVersion = getFixed( font.offset_table ); /* Load the "head" table and extract information from it. */ ptr = GetTable(&font, "head"); try { font.MfrRevision = getFixed( ptr + 4 ); /* font revision number */ font.unitsPerEm = getUSHORT( ptr + 18 ); font.HUPM = font.unitsPerEm / 2; #ifdef DEBUG_TRUETYPE debug("unitsPerEm=%d",(int)font.unitsPerEm); #endif font.llx = topost2( getFWord( ptr + 36 ) ); /* bounding box info */ font.lly = topost2( getFWord( ptr + 38 ) ); font.urx = topost2( getFWord( ptr + 40 ) ); font.ury = topost2( getFWord( ptr + 42 ) ); font.indexToLocFormat = getSHORT( ptr + 50 ); /* size of 'loca' data */ if (font.indexToLocFormat != 0 && font.indexToLocFormat != 1) { throw TTException("TrueType font is unusable because indexToLocFormat != 0"); } if ( getSHORT(ptr+52) != 0 ) { throw TTException("TrueType font is unusable because glyphDataFormat != 0"); } } catch (TTException& ) { free(ptr); throw; } free(ptr); /* Load information from the "name" table. */ Read_name(&font); /* We need to have the PostScript table around. */ assert(font.post_table == NULL); font.post_table = GetTable(&font, "post"); font.numGlyphs = getUSHORT( font.post_table + 32 ); /* If we are generating a Type 3 font, we will need to */ /* have the 'loca' and 'glyf' tables arround while */ /* we are generating the CharStrings. */ if (font.target_type == PS_TYPE_3 || font.target_type == PDF_TYPE_3 || font.target_type == PS_TYPE_42_3_HYBRID) { BYTE *ptr; /* We need only one value */ ptr = GetTable(&font, "hhea"); font.numberOfHMetrics = getUSHORT(ptr + 34); free(ptr); assert(font.loca_table == NULL); font.loca_table = GetTable(&font,"loca"); assert(font.glyf_table == NULL); font.glyf_table = GetTable(&font,"glyf"); assert(font.hmtx_table == NULL); font.hmtx_table = GetTable(&font,"hmtx"); } if (glyph_ids.size() == 0) { glyph_ids.clear(); glyph_ids.reserve(font.numGlyphs); for (int x = 0; x < font.numGlyphs; ++x) { glyph_ids.push_back(x); } } else if (font.target_type == PS_TYPE_3 || font.target_type == PS_TYPE_42_3_HYBRID) { ttfont_add_glyph_dependencies(&font, glyph_ids); } } /* end of insert_ttfont() */
// Returns: // OK - if new record retrieved // ERROR - if there was an interface error // ERROR_ABORT - if there is no new record (WH1080 generates new records at // best once a minute) static int readStationData (WVIEWD_WORK *work) { WH1080_IF_DATA* ifWorkData = (WH1080_IF_DATA*)work->stationData; int currentPosition, readPosition, index, retVal; if ((*(work->medium.usbhidInit))(&work->medium) != OK) { return ERROR; } // Read the WH1080 fixed block: retVal = readFixedBlock(work, &wh1080Work.controlBlock[0]); if (retVal == ERROR_ABORT) { // Try again later (bad magic number): (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } else if (retVal == ERROR) { // USB interface error: (*(work->medium.usbhidExit))(&work->medium); return ERROR; } // Get the current record position; the WH1080 reports the record it is // building, thus if it changes we need the prior just finished record: currentPosition = (int)getUSHORT(&wh1080Work.controlBlock[WH1080_CURRENT_POS]); // Make sure the index is aligned on 16-byte boundary: if ((currentPosition % 16) != 0) { // bogus, try again later: (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Is this the first time? if (wh1080Work.lastRecord == -1) { // Yes. wh1080Work.lastRecord = currentPosition; (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Is there a new record? if (currentPosition == wh1080Work.lastRecord) { // No, wait till it is finished. (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Read last record that is now complete: if (readBlock(work, wh1080Work.lastRecord, &wh1080Work.recordBlock[0]) == ERROR) { radMsgLog (PRI_HIGH, "WH1080: read data block at index %d failed!", wh1080Work.lastRecord); (*(work->medium.usbhidExit))(&work->medium); return ERROR; } (*(work->medium.usbhidExit))(&work->medium); readPosition = wh1080Work.lastRecord; wh1080Work.lastRecord = currentPosition; //radMsgLogData(wh1080Work.recordBlock, 32); // Is the record valid? Check for unpopulated record or no sensor data // received status bit: if ((wh1080Work.recordBlock[WH1080_STATUS] & 0x40) != 0) { // No! radMsgLog (PRI_HIGH, "WH1080: data block at index %d has bad status, ignoring the record", readPosition); return ERROR_ABORT; } // Parse the data received: for (index = 0; index < WH1080_NUM_SENSORS; index ++) { if (decodeSensor(&wh1080Work.recordBlock[decodeVals[index].pos], decodeVals[index].ws_type, decodeVals[index].scale, decodeVals[index].var) != OK) { // Bad sensor data, abort this cycle: radMsgLog (PRI_HIGH, "WH1080: data block at index %d has bad sensor value, ignoring the record", readPosition); return ERROR_ABORT; } } // Convert to Imperial units: wh1080Work.sensorData.intemp = wvutilsConvertCToF(wh1080Work.sensorData.intemp); wh1080Work.sensorData.outtemp = wvutilsConvertCToF(wh1080Work.sensorData.outtemp); wh1080Work.sensorData.pressure = wvutilsConvertHPAToINHG(wh1080Work.sensorData.pressure); wh1080Work.sensorData.windAvgSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windAvgSpeed); wh1080Work.sensorData.windGustSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windGustSpeed); wh1080Work.sensorData.rain = wvutilsConvertMMToIN(wh1080Work.sensorData.rain); return OK; }
static int decodeSensor(char* raw, enum ws_types ws_type, float scale, float* var) { float fresult; uint16_t usTemp; switch (ws_type) { case ub: if ((unsigned char)raw[0] == 0xFF) { // Deal with humidity < 10% problem by hard-coding to 9: fresult = 9; } else { fresult = (unsigned char)raw[0] * scale; } break; case us: usTemp = getUSHORT(raw); if (usTemp == 0xFFFF) { return ERROR; } fresult = usTemp * scale; break; case ss: if (((unsigned char)raw[0] == 0xFF) && ((unsigned char)raw[1] == 0xFF)) { return ERROR; } fresult = getSHORT(raw) * scale; break; case pb: fresult = (unsigned char)raw[0]; break; case wa: // wind average - 12 bits split across a byte and a nibble if (((unsigned char)raw[0] == 0xFF) && (((unsigned char)raw[2] & 0x0F) == 0x0F)) { return ERROR; } fresult = (unsigned char)raw[0] + (((unsigned char)raw[2] & 0x0F) * 256); fresult = fresult * scale; break; case wg: // wind gust - 12 bits split across a byte and a nibble if (((unsigned char)raw[0] == 0xFF) && (((unsigned char)raw[1] & 0xF0) == 0xF0)) { return ERROR; } fresult = (unsigned char)raw[0] + (((unsigned char)raw[1] & 0xF0) * 16); fresult = fresult * scale; break; case wd: if (((unsigned char)raw[0] & 0x80) == 0x80) { return ERROR; } fresult = (unsigned char)raw[0] * scale; fresult *= 22.5; break; default: fresult = ARCHIVE_VALUE_NULL; break; } *var = fresult; return OK; }
// Returns: // OK - if new record retrieved // ERROR - if there was an interface error // ERROR_ABORT - if there is no new record (WH1080 generates new records at // best once a minute) static int readStationData (WVIEWD_WORK *work) { WH1080_IF_DATA* ifWorkData = (WH1080_IF_DATA*)work->stationData; int currentPosition, index; if ((*(work->medium.usbhidInit))(&work->medium) != OK) { return ERROR; } // Read the WH1080 fixed block: if (readFixedBlock(work, &wh1080Work.controlBlock[0]) == ERROR) { (*(work->medium.usbhidExit))(&work->medium); return ERROR; } // Get the current record position; the WH1080 reports the record it is // building, thus if it changes we need the prior just finished record: currentPosition = (int)getUSHORT(&wh1080Work.controlBlock[WH1080_CURRENT_POS]); currentPosition -= WH1080_BUFFER_RECORD; if (currentPosition < WH1080_BUFFER_START) { // wrap back around to the end of the memory block: currentPosition = WH1080_BUFFER_END; } // Is there a new record? if (currentPosition == wh1080Work.lastRecord) { // No! (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Read current and next record on first read on even position if (readBlock(work, currentPosition, &wh1080Work.recordBlock[0]) == ERROR) { radMsgLog (PRI_HIGH, "WH1080: read data block at index %d failed!", currentPosition); (*(work->medium.usbhidExit))(&work->medium); return ERROR; } (*(work->medium.usbhidExit))(&work->medium); wh1080Work.lastRecord = currentPosition; //radMsgLogData(wh1080Work.recordBlock, 32); // Is the record valid? Check for unpopulated record or no sensor data // received status bit: if (((wh1080Work.recordBlock[0] != 1)) || ((wh1080Work.recordBlock[WH1080_STATUS] & 0x40) != 0)) { // No! return ERROR_ABORT; } // Parse the data received: for (index = 0; index < WH1080_NUM_SENSORS; index ++) { if (decodeSensor(&wh1080Work.recordBlock[decodeVals[index].pos], decodeVals[index].ws_type, decodeVals[index].scale, decodeVals[index].var) != OK) { // Bad sensor data, abort this cycle: return ERROR_ABORT; } } // Convert to Imperial units: wh1080Work.sensorData.intemp = wvutilsConvertCToF(wh1080Work.sensorData.intemp); wh1080Work.sensorData.outtemp = wvutilsConvertCToF(wh1080Work.sensorData.outtemp); wh1080Work.sensorData.pressure = wvutilsConvertHPAToINHG(wh1080Work.sensorData.pressure); wh1080Work.sensorData.windAvgSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windAvgSpeed); wh1080Work.sensorData.windGustSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windGustSpeed); wh1080Work.sensorData.rain = wvutilsConvertMMToIN(wh1080Work.sensorData.rain); return OK; }
static int decodeSensor(char* raw, enum ws_types ws_type, float scale, float* var) { float fresult; unsigned short usTemp; switch (ws_type) { case ub: if ((unsigned char)raw[0] == 0xFF) { return ERROR; } fresult = (unsigned char)raw[0] * scale; break; case us: usTemp = getUSHORT(raw); if (usTemp == 0xFFFF) { return ERROR; } fresult = usTemp * scale; break; case ss: if (((unsigned char)raw[0] == 0xFF) && ((unsigned char)raw[1] == 0xFF)) { return ERROR; } fresult = getSHORT(raw) * scale; break; case pb: fresult = (unsigned char)raw[0]; break; case wa: // wind average - 12 bits split across a byte and a nibble if (((unsigned char)raw[0] == 0xFF) && (((unsigned char)raw[2] & 0x0F) == 0x0F)) { return ERROR; } fresult = (unsigned char)raw[0] + (((unsigned char)raw[2] & 0x0F) * 256); fresult = fresult * scale; break; case wg: // wind gust - 12 bits split across a byte and a nibble if (((unsigned char)raw[0] == 0xFF) && (((unsigned char)raw[1] & 0xF0) == 0xF0)) { return ERROR; } fresult = (unsigned char)raw[0] + (((unsigned char)raw[1] & 0xF0) * 16); fresult = fresult * scale; break; case wd: if (((unsigned char)raw[0] & 0x80) == 0x80) { return ERROR; } fresult = (unsigned char)raw[0] * scale; fresult *= 22.5; break; default: fresult = -10000; break; } *var = fresult; return OK; }