/*
This software is subject to the license described in the License.txt file 
included with this software distribution. You may not use this file except in compliance 
with this license.

Copyright (c) Dynastream Innovations Inc. 2012
All rights reserved.
*/



#include "StdAfx.h"
#include "WeightScaleSensor.h"
#include "antmessage.h"


/**************************************************************************
 * WeightScaleSensor::ANT_eventNotification
 * 
 * Process ANT channel event
 *
 * ucEventCode_: code of ANT channel event
 * pucEventBuffer_: pointer to buffer containing data received from ANT,
 *		or a pointer to the transmit buffer in the case of an EVENT_TX
 * 
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::ANT_eventNotification(UCHAR ucEventCode_, UCHAR* pucEventBuffer_)
{
	switch(ucEventCode_)
	{
		case EVENT_TX:
			HandleTransmit((UCHAR*) pucEventBuffer_);
			break;
		case EVENT_RX_BROADCAST:
			HandleReceive((UCHAR*) pucEventBuffer_);
			break;	
		case MESG_OPEN_CHANNEL_ID:
			AllowChangesProfile(FALSE);
			break;
		case MESG_CLOSE_CHANNEL_ID:
			AllowChangesProfile(TRUE);
			break;
		default:
			break;
	}
}


/**************************************************************************
 * WeightScaleSensor::InitializeSim
 * 
 * Initializes simulator variables
 * 
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::InitializeSim()
{
	// Initialization of ANT+ simulation variables
	wsPages->usBodyWeight100 = WeightScale::WEIGHT_COMPUTING;
	wsPages->usHydrationP100 = (USHORT) (this->numericUpDown_Hydration->Value * 100);	// Hydration in 0.01%
	wsPages->usBodyFatP100 = (USHORT) (this->numericUpDown_BodyFat->Value * 100);	// Body fat in 0.01%
	wsPages->usActiveMetRate4 = (USHORT) (this->numericUpDown_ActiveMetRate->Value * 4);	// Active metabolic rate (1/4 kcal)
	wsPages->usBasalMetRate4= (USHORT) (this->numericUpDown_BasalMetRate->Value * 4); // Basal metabolic rate (1/4 kcal)
   wsPages->usMuscleMass100 = (USHORT) (this->numericUpDown_MuscleMass->Value * 100);  // Muscle mass (1/100 kg)
   wsPages->ucBoneMass10 = (UCHAR) (this->numericUpDown_BoneMass->Value * 10);   // Bone mass (1/10 kg)


	// Common Pages (Read from UI values)
	commonPages->usMfgID = System::Convert::ToUInt16(this->textboxMfgID->Text);
	commonPages->usModelNum = System::Convert::ToUInt16(this->textboxModelNum->Text);
	commonPages->ucHwVersion= System::Convert::ToByte(this->textboxHwVer->Text);
	commonPages->ucSwVersion = System::Convert::ToByte(this->textboxSwVer->Text);
	commonPages->ulSerialNum = System::Convert::ToUInt32(this->textboxSerialNum->Text);

	// Preset User Profiles
	uprofUndef = gcnew WeightScaleUserProfile();
	uprofU1 = gcnew WeightScaleUserProfile((USHORT) 1, WeightScaleUserProfile::GENDER_MALE, (UCHAR) 47, (UCHAR) 170, WeightScaleUserProfile::ACTIVITY_LOW, WeightScaleUserProfile::PRIORITY_WATCH, WeightScaleUserProfile::NOT_ATHLETE);
	uprofU2 = gcnew WeightScaleUserProfile((USHORT) 5, WeightScaleUserProfile::GENDER_FEMALE, (UCHAR) 25, (UCHAR) 162, WeightScaleUserProfile::ACTIVITY_HIGH, WeightScaleUserProfile::PRIORITY_WATCH, WeightScaleUserProfile::IS_ATHLETE);
	uprofU3 = gcnew WeightScaleUserProfile((USHORT) 12, WeightScaleUserProfile::GENDER_MALE, (UCHAR) 8, (UCHAR) 117, WeightScaleUserProfile::ACTIVITY_CHILD, WeightScaleUserProfile::PRIORITY_WATCH, WeightScaleUserProfile::NOT_ATHLETE);
	
	// Status
	bTxAdvanced = FALSE;
	bTxUserProfile = FALSE;
	bTxPage2 = TRUE;
	bTxPage3 = TRUE;
   bTxPage4 = TRUE;
}


/**************************************************************************
 * WeightScaleSensor::HandleTransmit
 * 
 * Encode data into Tx Buffer
 * pucTxBuffer_: pointer to the Tx buffer
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::HandleTransmit(UCHAR* pucTxBuffer_)
{
	static UCHAR ucMsgCount = 0;
	UCHAR ucPageNum = WeightScale::PAGE_BODY_WEIGHT;

	if(bTxAdvanced && wsPages->usBodyWeight100 < WeightScale::WEIGHT_COMPUTING)	// Make sure profile has been enabled, and body weight is calculated
	{
		if(ucMsgCount % 4 == 1 && bTxAdvanced && bTxPage2)		// Interleaving advanced data pages
			ucPageNum = WeightScale::PAGE_BODY_COMPOSITION;
		if(ucMsgCount % 4 == 2 && bTxAdvanced && bTxPage3)
			ucPageNum = WeightScale::PAGE_METABOLIC_INFO;
      if(ucMsgCount % 4 == 3 && bTxAdvanced && bTxPage4)
         ucPageNum = WeightScale::PAGE_BODY_MASS;
	}
	if(ucMsgCount == (WeightScale::INTERVAL_COMMON-1))		// Interleaving common pages
		ucPageNum = CommonData::PAGE80;
	if(++ucMsgCount >= (WeightScale::INTERVAL_COMMON*2))
	{
		ucPageNum = CommonData::PAGE81;
		ucMsgCount = 0;
	}

	if(bTxUserProfile)			
	{
		ucPageNum = WeightScale::PAGE_USER_PROFILE;		// Transmit user profile 
		bTxUserProfile = FALSE;							// Only once
	}

	switch(ucPageNum)
	{
		case WeightScale::PAGE_BODY_WEIGHT:
		case WeightScale::PAGE_BODY_COMPOSITION:
		case WeightScale::PAGE_METABOLIC_INFO:
      case WeightScale::PAGE_BODY_MASS:
		case WeightScale::PAGE_USER_PROFILE:			// Intentional fall thru
			try
			{
				wsPages->Encode(ucPageNum, pucTxBuffer_);	// Encode weight scale pages
			}
			catch(WeightScale::Error^ errorWeightScale)
			{
			}
			break;		
		case CommonData::PAGE80:
		case CommonData::PAGE81:						// Intentional fall thru
			try
			{
				commonPages->Encode(ucPageNum, pucTxBuffer_);	// Encode common pages
			}
			catch(CommonData::Error^ errorCommon)
			{
			}
			break;
		default:
			break;
	}

	UpdateDisplay();
}


/**************************************************************************
 * WeightScaleSensor::HandleReceive
 * 
 * Decode incoming transmissions
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::HandleReceive(UCHAR* pucRxBuffer_)
{
	UCHAR ucPageNum = pucRxBuffer_[0];

	if(ucPageNum == WeightScale::PAGE_USER_PROFILE)	// Only decode user profile
	{
		try
			{
				wsPages->Decode(pucRxBuffer_);
			}
			catch(WeightScale::Error^ errorWeightScale)
			{
			}

		UpdateDisplayCapabilities();
		ProcessReceivedProfile();		// Process incoming profile
	}
}


/**************************************************************************
 * WeightScaleSensor::ProcessReceivedProfile
 * 
 * Process incoming profile (device specific decision tree)
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::ProcessReceivedProfile()
{

	this->labelStatusProfileRx->Text = L"User Profile Received";

	// Process capabilities
	wsPages->capabScale->bDisplayExchange = wsPages->capabDisplay->bDisplayExchange; // Update display exchange support field as received from display

	// Does display support profile exchange?
	if(wsPages->capabDisplay->bDisplayExchange)
	{
		// Is user profile ID received from display valid?
		if(wsPages->uprofDisplay->usID != WeightScaleUserProfile::PROFILE_UNDEF)
		{
			// User profile ID match?
			// This implementation only looks for a match in the active profile of the scale
			// It could also be possible to look for a match in all profiles stored on the scale
			if(wsPages->uprofActive->usID == wsPages->uprofDisplay->usID)
			{
				this->labelStatusProfileMatch->Text = L"User Profile Match";		// Profile ID match
				// Check for changes to user profile for this ID
				if(!(WeightScaleUserProfile::isEqual(wsPages->uprofActive, wsPages->uprofDisplay)))
					this->labelStatusProfileUpdate->Text = L"User Profile Updated";	// Changes detected, profile will be updated
			}
			else
			{
				this->labelStatusProfileNew->Text = L"New User Profile";		// New user profile
			}
			// Apply user profile to calculations
			WeightScaleUserProfile::copyProfile(wsPages->uprofDisplay, wsPages->uprofActive);
			UpdateDisplayActiveProfile();
			wsPages->capabScale->bScaleSet = TRUE;
			bTxAdvanced = TRUE;			// Enable advanced calculations
		}
		else
		{
			// No valid user profile in display
			// Is user profile set on scale?
			// In this implementation, the scale only looks for a valid active user profile
			if(wsPages->uprofActive->usID != WeightScaleUserProfile::PROFILE_UNDEF)
			{
				// Transmit User Profile
				bTxUserProfile = TRUE;
				this->labelStatusProfileSent->Text = L"Sent User Profile";
				// Apply profile to calculations
				bTxAdvanced = TRUE;
			}
		}
	}
}


/**************************************************************************
 * WeightScaleSensor::UpdateDisplay
 * 
 * Updates display of current transmission
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::UpdateDisplay()
{
	// Update display
	if(wsPages->usBodyWeight100 == WeightScale::WEIGHT_COMPUTING)
		this->labelWeight->Text = "Comp";
	else if (wsPages->usBodyWeight100 == WeightScale::WEIGHT_INVALID)
		this->labelWeight->Text = "Invalid";
	else
		this->labelWeight->Text = System::Convert::ToString((double) wsPages->usBodyWeight100 / 100);	// Weight (kg)

	this->labelProfileActive->Text = Convert::ToString(wsPages->uprofActive->usID);		// Active profile


	if(bTxPage2 && bTxAdvanced && wsPages->usBodyWeight100 < WeightScale::WEIGHT_COMPUTING)
	{
		if(wsPages->usHydrationP100 == WeightScale::WEIGHT_COMPUTING)
			this->label_Hydration->Text = "Comp";
		else if (wsPages->usHydrationP100 == WeightScale::WEIGHT_INVALID)
			this->label_Hydration->Text = "Invalid";
		else
			this->label_Hydration->Text = System::Convert::ToString((double) wsPages->usHydrationP100 / 100);	// Hydration (%)

		if(wsPages->usBodyFatP100 == WeightScale::WEIGHT_COMPUTING)
			this->label_BodyFat->Text = "Comp";
		else if (wsPages->usBodyFatP100 == WeightScale::WEIGHT_INVALID)
			this->label_BodyFat->Text = "Invalid";
		else
			this->label_BodyFat->Text = System::Convert::ToString((double) wsPages->usBodyFatP100 / 100);	// Body Fat (%)
	}
	else
	{
		this->label_Hydration->Text = "---";
		this->label_BodyFat->Text = "---";
	}


	if(bTxPage3 && bTxAdvanced && wsPages->usBodyWeight100 < WeightScale::WEIGHT_COMPUTING)
	{
		if(wsPages->usActiveMetRate4 == WeightScale::WEIGHT_COMPUTING)
			this->label_ActiveMetRate->Text = "Comp";
		else if (wsPages->usActiveMetRate4 == WeightScale::WEIGHT_INVALID)
			this->label_ActiveMetRate->Text = "Invalid";
		else
			this->label_ActiveMetRate->Text = System::Convert::ToString((double) wsPages->usActiveMetRate4 / 4);	// Active Metabolic Rate (kcal)

		if(wsPages->usBasalMetRate4 == WeightScale::WEIGHT_COMPUTING)
			this->label_BasalMetRate->Text = "Comp";
		else if (wsPages->usBasalMetRate4 == WeightScale::WEIGHT_INVALID)
			this->label_BasalMetRate->Text = "Invalid";
		else
			this->label_BasalMetRate->Text = System::Convert::ToString((double) wsPages->usBasalMetRate4 / 4);	// Basal Metabolic Rate (kcal)
	}
	else
	{
		this->label_ActiveMetRate->Text = "---";
		this->label_BasalMetRate->Text = "---";
	}


}


/**************************************************************************
 * WeightScaleSensor::UpdateDisplayActiveProfile
 * 
 * Updates display of current active user profile
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::UpdateDisplayActiveProfile()
{
	// Updates field on active profile tab
	this->labelProfileActive->Text = System::Convert::ToString(wsPages->uprofActive->usID);		// Active profile ID
	this->labelProfileActive2->Text = System::Convert::ToString(wsPages->uprofActive->usID);
	if(wsPages->uprofActive->ucGender == WeightScaleUserProfile::GENDER_FEMALE)				// Gender
		this->labelGenderActive->Text = L"Female";
	if(wsPages->uprofActive->ucGender == WeightScaleUserProfile::GENDER_MALE)
		this->labelGenderActive->Text = L"Male";
	this->labelAgeActive->Text = System::Convert::ToString(wsPages->uprofActive->ucAge);	// Age
	this->labelHeightActive->Text = System::Convert::ToString(wsPages->uprofActive->ucHeight);	// Height
	this->labelDescriptionActive->Text = System::Convert::ToString(wsPages->uprofActive->ucDescription);	// Description
	if (wsPages->uprofActive->bAthlete == TRUE)	 // Athlete bit
		this->labelLifestyle->Text = "Athlete";
	else
		this->labelLifestyle->Text = "Standard";

	// Update fields on custom tab
	this->numericUpDownActivityLevel->Value = wsPages->uprofActive->ucDescription;	// Description
	this->numericUpDownAge->Value = wsPages->uprofActive->ucAge;					// Age
	this->numericUpDownHeight->Value = wsPages->uprofActive->ucHeight;				// Height
	if (wsPages->uprofActive->ucGender == WeightScaleUserProfile::GENDER_MALE)		// Gender
		this->radioButtonMale->Checked = TRUE;
	else
		this->radioButtonFemale->Checked = TRUE;
	if (wsPages->uprofActive->usID <= WeightScaleUserProfile::PROFILE_SCALE_MAX)	// ID
		this->numericUpDownProfile->Value = wsPages->uprofActive->usID;
	else
		this->numericUpDownProfile->Value = 0;

	if(wsPages->uprofActive->bAthlete == TRUE)  // Athlete bit
		this->radioButtonLifetimeActivityTrue->Checked = TRUE;
	else
		this->radioButtonLifetimeActivityFalse->Checked = TRUE;
}


/**************************************************************************
 * WeightScaleSensor::UpdateDisplayCapabilities
 * 
 * Updates display of capabilities (received from display)
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::UpdateDisplayCapabilities()
{
	// Show capabilities of display
	if(wsPages->capabDisplay->bScaleSet)
		this->labelProfileSetScale->Text = L"Yes";
	else
		this->labelProfileSetScale->Text = L"No";

	if(wsPages->capabDisplay->bScaleExchange)
		this->labelExchangeScale->Text = L"Yes";
	else
		this->labelExchangeScale->Text = L"No";

	if(wsPages->capabDisplay->bAntfs)
		this->labelAntfsRx->Text = L"Yes";
	else
		this->labelAntfsRx->Text = L"No";	

	if(wsPages->capabDisplay->bDisplayExchange)
		this->labelExchangeDisplay->Text = L"Yes";
	else
		this->labelExchangeDisplay->Text = L"No";
}



/**************************************************************************
 * WeightScaleSensor::SelectPresetProfile
 * 
 * Selects between preset user profiles
 * Application specific
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::SelectPresetProfile()
{
	if(this->radioButtonUser1->Checked)			// Select among predefined profiles
		WeightScaleUserProfile::copyProfile(uprofU1, wsPages->uprofScale);
	if(this->radioButtonUser2->Checked)
		WeightScaleUserProfile::copyProfile(uprofU2, wsPages->uprofScale);
	if(this->radioButtonUser3->Checked)
		WeightScaleUserProfile::copyProfile(uprofU3, wsPages->uprofScale);
	if(this->radioButtonGuest->Checked)
	{
		// Enable Custom Profile
		this->numericUpDownProfile->Enabled = TRUE;
		this->numericUpDownAge->Enabled = TRUE;
		this->numericUpDownHeight->Enabled = TRUE;
		this->radioButtonFemale->Enabled = TRUE;
		this->radioButtonMale->Enabled = TRUE;
		this->numericUpDownActivityLevel->Enabled = TRUE;
		this->groupBoxLifetimeActivity->Enabled = TRUE;
		SelectCustomProfile();
	}
	else
	{
		// Disble Custom Profile
		this->numericUpDownProfile->Enabled = FALSE;
		this->numericUpDownAge->Enabled = FALSE;
		this->numericUpDownHeight->Enabled = FALSE;
		this->radioButtonFemale->Enabled = FALSE;
		this->radioButtonMale->Enabled = FALSE;
		this->numericUpDownActivityLevel->Enabled = FALSE;
		this->groupBoxLifetimeActivity->Enabled = FALSE;
	}

	// If there is no active profile, or current active profile was set on a scale, set scale profile as active
	if((wsPages->uprofActive->usID == WeightScaleUserProfile::PROFILE_UNDEF) || (wsPages->uprofActive->usID <= WeightScaleUserProfile::PROFILE_SCALE_MAX))
	{
		WeightScaleUserProfile::copyProfile(wsPages->uprofScale, wsPages->uprofActive);
		UpdateDisplayActiveProfile();
	}
}

/**************************************************************************
 * WeightScaleSensor::SelectCustomProfile
 * 
 * Updates custom profile set on scale
 * Application specific
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::SelectCustomProfile()
{
	if(wsPages->capabScale->bScaleSet && this->radioButtonGuest->Checked)	// User profile selected through interface and custom profile enabled
	{
		// Read user profile from GUI
		wsPages->uprofScale->usID = (USHORT) (this->numericUpDownProfile->Value);	// ID
		wsPages->uprofScale->ucAge = (UCHAR) (this->numericUpDownAge->Value);		// Age
		wsPages->uprofScale->ucHeight = (UCHAR) (this->numericUpDownHeight->Value);	// Height
		wsPages->uprofScale->ucDescription = (UCHAR) (this->numericUpDownActivityLevel->Value);	// Activity Level
		if(this->radioButtonFemale->Checked)
			wsPages->uprofScale->ucGender = WeightScaleUserProfile::GENDER_FEMALE;	// Gender
		else if(this->radioButtonMale->Checked)
			wsPages->uprofScale->ucGender = WeightScaleUserProfile::GENDER_MALE;
		else
			wsPages->uprofScale->ucGender = WeightScaleUserProfile::GENDER_UNDEF;
		if (this->radioButtonLifetimeActivityTrue->Checked == TRUE)
			wsPages->uprofScale->bAthlete = TRUE;									// Lifetime activity
		else
			wsPages->uprofScale->bAthlete = FALSE;

	}

	// Set scale profile as active
	// - if there is no active profile
	// - if updating current active profile (ID match)
	// - if current active profile was set on a scale
	if((wsPages->uprofActive->usID == WeightScaleUserProfile::PROFILE_UNDEF) || (wsPages->uprofActive->usID == wsPages->uprofScale->usID) || (wsPages->uprofActive->usID <= WeightScaleUserProfile::PROFILE_SCALE_MAX))
	{
		WeightScaleUserProfile::copyProfile(wsPages->uprofScale, wsPages->uprofActive);
		UpdateDisplayActiveProfile();
	}
}


/**************************************************************************
 * WeightScaleSensor::checkBoxProfileSet_CheckedChanged
 * 
 * Selects user profile through the interface of the weight scale
 *
 * returns: N/A
 *
 **************************************************************************/
System::Void WeightScaleSensor::checkBoxProfileSet_CheckedChanged(System::Object^  sender, System::EventArgs^  e)
{
	if(this->checkBoxProfileSet->Checked == TRUE)	// Profile set
	{
		this->groupBox2->Enabled = TRUE;
		SelectPresetProfile();						// Use profile selected
		// The selected profile is only applied if there is no active profile
		wsPages->capabScale->bScaleSet = TRUE;		// Set capabilities		
	}
	else
	{
		this->groupBox2->Enabled = FALSE;			// Profile not set
		WeightScaleUserProfile::copyProfile(uprofUndef, wsPages->uprofScale);	// Invalid profile
		// Set the profile as active if current profile was set on the scale
		if(wsPages->uprofActive->usID <= WeightScaleUserProfile::PROFILE_SCALE_MAX)
		{
			WeightScaleUserProfile::copyProfile(wsPages->uprofScale, wsPages->uprofActive);
			UpdateDisplayActiveProfile();
		}
		wsPages->capabScale->bScaleSet = FALSE;		// Set capabilities
		// This only affects the profile selected at the scale, it will not delete the current active profile
	}
}


/**************************************************************************
 * WeightScaleSensor::checkBoxExchange_CheckedChanged
 * 
 * Enable/disable profile exchange
 *
 * returns: N/A
 *
 **************************************************************************/
System::Void WeightScaleSensor::checkBoxExchange_CheckedChanged(System::Object^  sender, System::EventArgs^  e) 
{
	if(this->checkBoxExchange->Checked)
		wsPages->capabScale->bScaleExchange = TRUE;
	else
		wsPages->capabScale->bScaleExchange = FALSE;
		 
}

/**************************************************************************
 * WeightScaleSensor::checkBoxAntfs_CheckedChanged
 * 
 * Enable/disable use of ANT-FS (future functionality)
 * ANT-FS usage on weight scale is not yet defined on the device profile
 *
 * returns: N/A
 *
 **************************************************************************/
System::Void WeightScaleSensor::checkBoxAntfs_CheckedChanged(System::Object^  sender, System::EventArgs^  e) 
{
	if(this->checkBoxAntfs->Checked)
		wsPages->capabScale->bAntfs = TRUE;
	else
		wsPages->capabScale->bAntfs = FALSE;
		 
}

/**************************************************************************
 * WeightScaleSensor::SelectWeightStatus
 * 
 * Sets weight as valid, invalid or computing
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::SelectWeightStatus()
{
	if (this->radioButtonWeightValid->Checked)	// Valid weight
	{
		this->numericUpDownWeight->Enabled = TRUE;
		wsPages->usBodyWeight100 = (USHORT) (this->numericUpDownWeight->Value * 100);
	}
	else
	{
		this->numericUpDownWeight->Enabled = FALSE;
		this->label_Hydration->Text = "---";
		this->label_BodyFat->Text = "---";
		this->label_ActiveMetRate->Text = "---";
		this->label_BasalMetRate->Text = "---";
		if (this->radioButtonWieghtComputing->Checked == TRUE)
		{
			wsPages->usBodyWeight100 = WeightScale::WEIGHT_COMPUTING;
		}
		if (this->radioButtonWeightError->Checked == TRUE)
		{
			wsPages->usBodyWeight100 = WeightScale::WEIGHT_INVALID;
		}
	}
}


/**************************************************************************
 * WeightScaleSensor::SelectPages
 * 
 * Selects advanced pages to transmit
 *
 * returns: N/A
 *
 **************************************************************************/
void WeightScaleSensor::SelectPages()
{
	bTxPage2 = (BOOL) (this->checkBox_TxPage2->Checked);
	bTxPage3 = (BOOL) (this->checkBox_TxPage3->Checked);
   bTxPage4 = (BOOL) (this->checkBox_TxPage4->Checked);
}

/**************************************************************************
 * WeightScaleSensor::buttonUpdateGlobal_Click
 * 
 * Updates and validates global data
 *
 * returns: N/A
 *
 **************************************************************************/
System::Void WeightScaleSensor::buttonUpdateGlobal_Click(System::Object^  sender, System::EventArgs^  e)
{
	this->labelError->Visible = false;
	try
	{
		commonPages->usMfgID = System::Convert::ToUInt16(this->textboxMfgID->Text);
		commonPages->usModelNum = System::Convert::ToUInt16(this->textboxModelNum->Text);
		commonPages->ucHwVersion = System::Convert::ToByte(this->textboxHwVer->Text);
		commonPages->ucSwVersion = System::Convert::ToByte(this->textboxSwVer->Text);
		if(!this->checkBox_InvalidSerial->Checked)
			commonPages->ulSerialNum = System::Convert::ToUInt32(this->textboxSerialNum->Text);
		else
			commonPages->ulSerialNum = 0xFFFFFFFF;
	}
	catch(...)
	{
		this->labelError->Visible = true;
		this->labelError->Text = L"Invalid input";
	}
		 
}

/**************************************************************************
 * WeightScaleSensor::buttonReset_Click
 * 
 * Resets session, without changing user profiles
 *
 * returns: N/A
 *
 **************************************************************************/
System::Void WeightScaleSensor::buttonReset_Click(System::Object^  sender, System::EventArgs^  e)
{
	// Reset session
	bTxAdvanced = FALSE;
	bTxUserProfile = FALSE;
	// Set weight to calculating
	radioButtonWieghtComputing->Checked = TRUE;
	// Clear status
	this->labelStatusProfileMatch->Text= "---";
	this->labelStatusProfileNew->Text = "---";
	this->labelStatusProfileRx->Text = "---";
	this->labelStatusProfileSent->Text = "---";
	this->labelStatusProfileUpdate->Text = "---";

}

/**************************************************************************
 * WeightScaleSensor::AllowChangesProfile
 * 
 * Enables/disables changes to user profile
 *
 * returns: N/A
 *
 **************************************************************************/

void WeightScaleSensor::AllowChangesProfile(BOOL bNoSession_)
{
	if(bNoSession_)
	{
		this->checkBoxProfileSet->Enabled = true;
		this->radioButtonUser1->Enabled = true;
		this->radioButtonUser2->Enabled = true;
		this->radioButtonGuest->Enabled = true;
		this->radioButtonGuest->Enabled = true;
		if(this->radioButtonGuest->Checked)	// Enable custom profiles
		{
			this->numericUpDownProfile->Enabled = true;
			this->numericUpDownAge->Enabled = true;
			this->numericUpDownHeight->Enabled = true;
			this->radioButtonFemale->Enabled = true;
			this->radioButtonMale->Enabled = true;
			this->numericUpDownActivityLevel->Enabled = true;
			this->groupBoxLifetimeActivity->Enabled = true;
		}
	}
	else
	{
		this->checkBoxProfileSet->Enabled = false;
		this->radioButtonUser1->Enabled = false;
		this->radioButtonUser2->Enabled = false;
		this->radioButtonGuest->Enabled = false;
		this->radioButtonGuest->Enabled = false;
		this->numericUpDownProfile->Enabled = false;
		this->numericUpDownAge->Enabled = false;
		this->numericUpDownHeight->Enabled = false;
		this->radioButtonFemale->Enabled = false;
		this->radioButtonMale->Enabled = false;
		this->numericUpDownActivityLevel->Enabled = false;
		this->groupBoxLifetimeActivity->Enabled = false;
	}
}



/**************************************************************************
 * Functions to update input from numeric boxes:
 * Weight, Hydration, Body Fat, Active Metabolic Rate, Basal Metabolic Rate
 * Validation of input is done by the control
 *
 **************************************************************************/
System::Void WeightScaleSensor::numericUpDownWeight_ValueChanged(System::Object^  sender, System::EventArgs^  e) 
{
	wsPages->usBodyWeight100 = (USHORT) (this->numericUpDownWeight->Value * 100);  // Weight in 1/100 kg
}

System::Void WeightScaleSensor::numericUpDown_Hydration_ValueChanged(System::Object^  sender, System::EventArgs^  e) 
{
	wsPages->usHydrationP100 = (USHORT) (this->numericUpDown_Hydration->Value * 100);	// Hydration in 0.01%
}

System::Void WeightScaleSensor::numericUpDown_BodyFat_ValueChanged(System::Object^  sender, System::EventArgs^  e) 
{
	wsPages->usBodyFatP100 = (USHORT) (this->numericUpDown_BodyFat->Value * 100);	// Body fat in 0.01%
}

System::Void WeightScaleSensor::numericUpDown_ActiveMetRate_ValueChanged(System::Object^  sender, System::EventArgs^  e) 
{
	wsPages->usActiveMetRate4 = (USHORT) (this->numericUpDown_ActiveMetRate->Value * 4);	// Active metabolic rate (1/4 kcal)
}

System::Void WeightScaleSensor::numericUpDown_BasalMetRate_ValueChanged(System::Object^  sender, System::EventArgs^  e) 
{
	wsPages->usBasalMetRate4 = (USHORT) (this->numericUpDown_BasalMetRate->Value * 4); // Basal metabolic rate (1/4 kcal)
}

System::Void WeightScaleSensor::numericUpDown_MuscleMass_ValueChanged(System::Object^  sender, System::EventArgs^  e)
{
   wsPages->usMuscleMass100 = (USHORT) (this->numericUpDown_MuscleMass->Value * 100);  // Muscle mass (1/100 kg)
}

System::Void WeightScaleSensor::numericUpDown_BoneMass_ValueChanged(System::Object^  sender, System::EventArgs^  e)
{
   wsPages->ucBoneMass10 = (UCHAR) (this->numericUpDown_BoneMass->Value * 10);   // Bone mass (1/10 kg)
}

System::Void WeightScaleSensor::checkBox_InvalidSerial_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
{
	if(this->checkBox_InvalidSerial->Checked)
		this->textboxSerialNum->Enabled = false;
	else
		this->textboxSerialNum->Enabled = true;
}