Receive signed value over CAN

Discuss issues and ideas you have to configuring displays with PowerVision
Josh.b@ST
Posts: 18
Joined: Tue Dec 06, 2011 10:00 am

Receive signed value over CAN

Post by Josh.b@ST » Wed Aug 27, 2014 8:11 am

After reading through various posts and trying different methods, i still cannot get my PV450 to receive a signed value correctly over CAN. I am trying to receive a 32 bit signed integer in the following format:
CAN ID: 0x193
Byte 0 = 0C
Byte 1 = FE
Byte 2 = FF
Byte 3 = FF
The variable has a resolution of 0.01 and works in the range of -40.00 to +150.00. With the CAN data set to the values above, i am expecting a value of -5.

Here is my code so far:

Code: Select all

void $e_Convert_Signed$ () 
{
	double NewVariable = 0;
	double SignedVariable = 0;

	smRead(VariableIDs.Limit_TMinusCoolant_Alarm, NewVariable); //read variable received from CAN
	SignedVariable = utos(NewVariable); //call function to convert to signed format
	smWrite(VariableIDs.Scaled_Coolant_Alarm, (SignedVariable / 100)); //scale to show in format xx.xx
}

double utos( double x ) //convert unsigned to signed
{
   uint u;
   int s;   

   u = x;
   s = u & 0xFFFF;
   x = s;   

   return x;
}
Has anybody else found a solution that has worked for them? Any ideas, support or advice would be greatly appreciated.

Many thanks in advance.
stalley
Enovation Controls Development
Enovation Controls Development
Posts: 618
Joined: Tue Mar 18, 2014 12:57 pm

Re: Receive signed value over CAN

Post by stalley » Wed Aug 27, 2014 11:30 am

Hi Josh.b,

Have you tried using 0xFFFFFFFF in the utos() function in place of the 0xFFFF?
Sara Talley
Software Engineer
Enovation Controls
Josh.b@ST
Posts: 18
Joined: Tue Dec 06, 2011 10:00 am

Re: Receive signed value over CAN

Post by Josh.b@ST » Thu Aug 28, 2014 3:59 am

Thank you for your response Sara, however when it is set to the value you mention it still does not work. All of my positive values are displayed correctly but as soon as the value goes negative, the variable seems to be set to the maximum value for the displayed numeric field (1500.00).
Please see below for how i have the numeric field set up to display my value.
PVCS.JPG
Numeric field set up
PVCS.JPG (13.83 KiB) Viewed 169 times
Many thanks.
stalley wrote:Hi Josh.b,

Have you tried using 0xFFFFFFFF in the utos() function in place of the 0xFFFF?
ksaenz
Enovation Controls Development
Enovation Controls Development
Posts: 263
Joined: Thu Aug 19, 2010 7:53 am

Re: Receive signed value over CAN

Post by ksaenz » Thu Aug 28, 2014 8:45 am

Hi Josh,

I suspected that the int32 was just too big for the double so I broke it in two parts and that seems to work.
FFCAN.png
FFCAN.png (25.8 KiB) Viewed 165 times
script.png
script.png (27.31 KiB) Viewed 165 times
remote diagnostics.png
remote diagnostics.png (2.42 KiB) Viewed 165 times

Code: Select all

int utos( uint u ) //convert unsigned to signed
{
   int s;
   
   s = u & 0xFFFFFFFF;

   return s;
}

//---------------------------------------------------------------------------------------------
// Murphy Scripting
// - Leave EventName as $e_Convert_Signed$ for main script method
//---------------------------------------------------------------------------------------------
void $e_Convert_Signed$ () 
{
   uint lsb = 0;
   uint msb = 0;
   uint UnsignedVariable = 0;
   double SignedVariable = 0;

   smRead( VariableIDs.lsb, lsb ); //read variable received from CAN
   smRead( VariableIDs.msb, msb );
   UnsignedVariable = ( msb << 16 ) + lsb;
   SignedVariable = utos( UnsignedVariable ); //call function to convert to signed format
   smWrite( VariableIDs.SignedVariable, ( SignedVariable / 100 ) ); //scale to show in format xx.xx

}
Regards,
ksaenz
Josh.b@ST
Posts: 18
Joined: Tue Dec 06, 2011 10:00 am

Re: Receive signed value over CAN

Post by Josh.b@ST » Thu Aug 28, 2014 10:05 am

I have also found another workaround which has worked.

Code: Select all

void $e_Convert_Signed$ () 
{
	//This will be used to convert received CAN values to signed values
	//PV450 cannot receive signed values
	double Coolant_Alarm_Temp = 0;
	double Coolant_Alarm = 0;
	smRead(VariableIDs.Limit_TMinusCoolant_Alarm, Coolant_Alarm_Temp);
	if (Coolant_Alarm_Temp > 2147483647)
	{
		Coolant_Alarm = ((((4294967295 - Coolant_Alarm_Temp) + 1) * -1) / 100);
	}
	else
	{
		Coolant_Alarm = (Coolant_Alarm_Temp / 100);
	}
	smWrite(VariableIDs.Scaled_Coolant_Alarm, Coolant_Alarm);
}
It basically checks to see if the received value is greater than the maximum value of a 32 bit signed value (this means it is signed), we then use the maximum size of a 32 bit unsigned value and take away our received value from it, we add one to use it in the correct number base, multiply by -1 to invert the value and then divide by 100 to put it into the format i require for display purposes (xx.xx).
Hopefully this post with the various solutions will help someone else as well as myself. I will also try splitting up the received value into 2 variables as previously suggested.
Thanks for everyone's help.