///////////////////////////////////////////////////////////////////////////////////////////////////////// // $PCPROBE, FW,f // Firmware version. f = 0xNNMM, where NN is the major version number and MM the minor number. ///////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDevCProbe::ParseFW( tnmeastring& wiss, NMEA_INFO *pINFO ) { unsigned int Version = HexStrToInt(wiss.GetNextString()); LockDeviceData(); _stprintf(m_szVersion, TEXT("%u.%.02u"), ((Version&0xFF00) >> 8), (Version&0x00FF)); UnlockDeviceData(); return TRUE; }
BOOL CDevCProbe::ParseNMEA( DeviceDescriptor_t *d, TCHAR *String, NMEA_INFO *pINFO ) { tnmeastring wiss(String); TCHAR* strToken = wiss.GetNextString(); if(_tcscmp(strToken,TEXT("$PCPROBE"))==0) { strToken = wiss.GetNextString(); // this sentence must handled first, also we can't detect end of Compass Calibration. if (_tcscmp(strToken,TEXT("COMPASSCALIBRATION"))==0) { // $PCPROBE,COMPASSCALIBRATION // The calibration of the accelerometers and of the magnetometers is being performed // no other thread modify m_bCompassCal Flag : no lock needed for read in this thread if(!m_bCompassCalOn){ LockDeviceData(); m_bCompassCalOn=TRUE; UnlockDeviceData(); } return TRUE; } // if we receive sentence other than compass calibration -> compass calibration is finish. // no other thread modify m_bCompassCal Flag : no lock needed for read in this thread if(m_bCompassCalOn) { LockDeviceData(); m_bCompassCalOn=FALSE; UnlockDeviceData(); } if (_tcscmp(strToken,TEXT("T"))==0) { BOOL bOk = ParseData(wiss, pINFO); if(!pINFO->BaroAltitudeAvailable) { SetBaroOn(d); } return bOk; } if (_tcscmp(strToken,TEXT("GYROCALIBRATION"))==0) { LockDeviceData(); m_bCompassCalOn=FALSE; UnlockDeviceData(); return ParseGyro(wiss, pINFO); } if (_tcscmp(strToken,TEXT("FW"))==0) { LockDeviceData(); m_bCompassCalOn=FALSE; UnlockDeviceData(); return ParseFW(wiss, pINFO); } if(_tcscmp(strToken,TEXT("NAME"))==0) { LockDeviceData(); m_bCompassCalOn=FALSE; UnlockDeviceData(); return ParseName(wiss, pINFO); } } return FALSE; }
void CDevCProbe::Update() { TCHAR Temp[50] = {0}; LockFlightData(); NMEA_INFO _INFO = GPS_INFO; UnlockFlightData(); LockDeviceData(); _stprintf(Temp, TEXT("C-Probe - Version: %s"), m_szVersion); UnlockDeviceData(); m_wf->SetCaption(Temp); WndProperty* wp; wp = (WndProperty*)m_wf->FindByName(TEXT("prpPitch")); if(wp){ _stprintf(Temp, TEXT("%.2f%s"), _INFO.Pitch, gettext(_T("_@M2179_"))); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpHeading")); if(wp){ _stprintf(Temp, TEXT("%.2f%s"), _INFO.MagneticHeading, gettext(_T("_@M2179_"))); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpRoll")); if(wp){ _stprintf(Temp, TEXT("%.2f%s"), _INFO.Roll, gettext(_T("_@M2179_"))); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpGx")); if(wp){ _stprintf(Temp, TEXT("%.2f"), _INFO.AccelX); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpGy")); if(wp){ _stprintf(Temp, TEXT("%.2f"), _INFO.AccelY); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpGz")); if(wp){ _stprintf(Temp, TEXT("%.2f"), _INFO.AccelZ); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpTemp")); if(wp){ _stprintf(Temp, TEXT("%.2f %sC"), _INFO.OutsideAirTemperature, gettext(_T("_@M2179_"))); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpRh")); if(wp){ _stprintf(Temp, TEXT("%.2f %%"), _INFO.RelativeHumidity); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpDeltaPress")); if(wp){ LockDeviceData(); _stprintf(Temp, TEXT("%.2f Pa"), m_delta_press); UnlockDeviceData(); wp->SetText(Temp); } wp = (WndProperty*)m_wf->FindByName(TEXT("prpAbsPress")); if(wp){ LockDeviceData(); _stprintf(Temp, TEXT("%.2f hPa"), m_abs_press); UnlockDeviceData(); wp->SetText(Temp); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////// // $PCPROBE,T,Q0,Q1,Q2,Q3,ax,ay,az,temp,rh,batt,delta_press,abs_press,C, // - "T" after "$PCPROBE" indicates that the string contains data. Data are represented as signed, // 16-bit hexadecimal integers. The only exception is abs_press which is in signed 24-bits hex // format. // - Q0, Q1, Q2, Q3: 3D orientation of the C-Probe in quaternion format. Heading, pitch, and roll can // be calculated as follows: // q0 = Q0 * 0.001; // q1 = Q1 * 0.001; // q2 = Q2 * 0.001; // q3 = Q3 * 0.001; // sin_pitch = -2 * (q0 * q2 - q3 * q1); // if sin_pitch > 1 or sin_pitch < -1, discard the data // pitch = asin(sin_pitch); // heading = M_PI + atan2(2*(q1 * q2 + q3 * q0), q3 * q3 - q0 * q0 - q1 * q1 + q2 * q2); // roll = atan2( 2 * (q0 * q1 + q3 * q2), q3 * q3 + q0 * q0 - q1 * q1 - q2 * q2); // - ax, ay, az: x, y, z components of the acceleration in units of 0.001 g. // - temp: temperature in units of 0.1°C. // - rh: relative humidity in units of 0.1%. // - batt: battery level from 0 to 100%. // - delta_press: differential pressure (dynamic - static) in units of 0.1 Pa. // - abs_press: absolute pressure in units of 1/400 Pa // - C: is transmitted only if the C-Probe is being charged. In this case, heat produced by the charging // process is likely to affect the readings of the temperature and humidity sensors. //////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDevCProbe::ParseData( tnmeastring& wiss, NMEA_INFO *pINFO ) { double q0 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q1 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q2 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q3 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double sin_pitch = -2 * (q0 * q2 - q3 * q1); // if sin_pitch > 1 or sin_pitch < -1, discard the data if(sin_pitch < 1.0 && sin_pitch > -1.0){ pINFO->MagneticHeadingAvailable=TRUE; pINFO->MagneticHeading = (PI + atan2(2*(q1 * q2 + q3 * q0), q3 * q3 - q0 * q0 - q1 * q1 + q2 * q2))*RAD_TO_DEG; pINFO->GyroscopeAvailable=TRUE; pINFO->Pitch = asin(sin_pitch)*RAD_TO_DEG; pINFO->Roll = atan2( 2 * (q0 * q1 + q3 * q2), q3 * q3 + q0 * q0 - q1 * q1 - q2 * q2)*RAD_TO_DEG; }else{ pINFO->MagneticHeadingAvailable=FALSE; pINFO->GyroscopeAvailable=FALSE; } pINFO->AccelerationAvailable=TRUE; pINFO->AccelX = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->AccelY = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->AccelZ = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->TemperatureAvailable=TRUE; pINFO->OutsideAirTemperature = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.1; pINFO->HumidityAvailable=TRUE; pINFO->RelativeHumidity = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.1; pINFO->ExtBatt1_Voltage = int16toDouble(HexStrToInt(wiss.GetNextString()))+1000; double delta_press = int16toDouble(HexStrToInt(wiss.GetNextString())) * 1.0/10.0 ; double abs_press = int24toDouble(HexStrToInt(wiss.GetNextString())) * (1.0/4.0); LockDeviceData(); m_delta_press = delta_press; m_abs_press = abs_press; UnlockDeviceData(); // the highest sea level air pressure ever recorded was 1084 mb (32.01 in.) // at Siberia associated with an extremely cold air mass. if(abs_press > 0.0 && abs_press < 115000.0) { UpdateBaroSource(pINFO, BARO__CPROBE, NULL, StaticPressureToAltitude(abs_press)); } else { if(pINFO->BaroAltitudeAvailable) { abs_press = QNHAltitudeToStaticPressure(pINFO->BaroAltitude); } else { abs_press = QNHAltitudeToStaticPressure(pINFO->Altitude); } } if(delta_press>0.0){ pINFO->AirspeedAvailable = TRUE; pINFO->IndicatedAirspeed = sqrt(2 * delta_press / 1.225); pINFO->TrueAirspeed = TrueAirSpeed(delta_press, pINFO->RelativeHumidity, pINFO->OutsideAirTemperature, abs_press>0.0?abs_press:101325.0); } if(*(wiss.GetNextString()) == L'C'){ pINFO->ExtBatt1_Voltage *= -1; } TriggerVarioUpdate(); return TRUE; }
//////////////////////////////////////////////////////////////////////////////////////////////////////// // $PCPROBE,T,Q0,Q1,Q2,Q3,ax,ay,az,temp,rh,batt,delta_press,abs_press,C, // - "T" after "$PCPROBE" indicates that the string contains data. Data are represented as signed, // 16-bit hexadecimal integers. The only exception is abs_press which is in signed 24-bits hex // format. // - Q0, Q1, Q2, Q3: 3D orientation of the C-Probe in quaternion format. Heading, pitch, and roll can // be calculated as follows: // q0 = Q0 * 0.001; // q1 = Q1 * 0.001; // q2 = Q2 * 0.001; // q3 = Q3 * 0.001; // sin_pitch = -2 * (q0 * q2 - q3 * q1); // if sin_pitch > 1 or sin_pitch < -1, discard the data // pitch = asin(sin_pitch); // heading = M_PI + atan2(2*(q1 * q2 + q3 * q0), q3 * q3 - q0 * q0 - q1 * q1 + q2 * q2); // roll = atan2( 2 * (q0 * q1 + q3 * q2), q3 * q3 + q0 * q0 - q1 * q1 - q2 * q2); // - ax, ay, az: x, y, z components of the acceleration in units of 0.001 g. // - temp: temperature in units of 0.1°C. // - rh: relative humidity in units of 0.1%. // - batt: battery level from 0 to 100%. // - delta_press: differential pressure (dynamic - static) in units of 0.1 Pa. // - abs_press: absolute pressure in units of 1/400 Pa // - C: is transmitted only if the C-Probe is being charged. In this case, heat produced by the charging // process is likely to affect the readings of the temperature and humidity sensors. //////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDevCProbe::ParseData( wnmeastring& wiss, NMEA_INFO *pINFO ) { double q0 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q1 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q2 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double q3 = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; double sin_pitch = -2 * (q0 * q2 - q3 * q1); // if sin_pitch > 1 or sin_pitch < -1, discard the data if(sin_pitch < 1.0 && sin_pitch > -1.0){ pINFO->MagneticCompassAvailable=TRUE; pINFO->Heading = (PI + atan2(2*(q1 * q2 + q3 * q0), q3 * q3 - q0 * q0 - q1 * q1 + q2 * q2))*RAD_TO_DEG; pINFO->GyroscopeAvailable=TRUE; pINFO->Pitch = asin(sin_pitch)*RAD_TO_DEG; pINFO->Roll = atan2( 2 * (q0 * q1 + q3 * q2), q3 * q3 + q0 * q0 - q1 * q1 - q2 * q2)*RAD_TO_DEG; }else{ pINFO->MagneticCompassAvailable=FALSE; pINFO->GyroscopeAvailable=FALSE; } pINFO->AccelerationAvailable=TRUE; pINFO->AccelX = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->AccelY = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->AccelZ = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.001; pINFO->Gload = sqrt(pow(pINFO->AccelX,2.0)+pow(pINFO->AccelY,2.0)+pow(pINFO->AccelZ,2.0)); pINFO->TemperatureAvailable=TRUE; pINFO->OutsideAirTemperature = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.1; pINFO->HumidityAvailable=TRUE; pINFO->RelativeHumidity = int16toDouble(HexStrToInt(wiss.GetNextString())) * 0.1; pINFO->ExtBatt1_Voltage = int16toDouble(HexStrToInt(wiss.GetNextString()))+1000; double delta_press = int16toDouble(HexStrToInt(wiss.GetNextString())) / 10.0 ; double abs_press = int24toDouble(HexStrToInt(wiss.GetNextString())) / 400.0; if(abs_press > 0.0) { UpdateBaroSource(pINFO, BARO__CPROBE, NULL, StaticPressureToAltitude(abs_press*100)); } else { if(pINFO->BaroAltitudeAvailable) { abs_press = QNHAltitudeToStaticPressure(pINFO->BaroAltitude); } else { abs_press = QNHAltitudeToStaticPressure(pINFO->Altitude); } } if(delta_press>=0){ pINFO->AirspeedAvailable = TRUE; pINFO->IndicatedAirspeed = sqrt(2*delta_press); pINFO->TrueAirspeed = TrueAirSpeed(delta_press, pINFO->RelativeHumidity, pINFO->OutsideAirTemperature, abs_press>0.0?abs_press*100:101325.0); } if(*(wiss.GetNextString()) == L'C'){ pINFO->ExtBatt1_Voltage *= -1; } LockDeviceData(); m_delta_press = delta_press; m_abs_press = abs_press; UnlockDeviceData(); TriggerVarioUpdate(); return TRUE; }