2016-09-26 09:44:21 -07:00
/*
Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright ( C ) Josh Stewart
A full copy of the license may be found in the projects root directory
can_comms was originally contributed by Darren Siepka
*/
/*
can_command is called when a command is received over serial3 from the Can interface
It parses the command and calls the relevant function
sendcancommand is called when a comman d is to be sent via serial3 to the Can interface
*/
2016-09-30 08:57:57 -07:00
void canCommand ( )
2016-09-26 09:44:21 -07:00
{
2017-05-31 01:57:36 -07:00
currentcanCommand = CANSerial . read ( ) ;
2017-05-10 16:08:24 -07:00
switch ( currentcanCommand )
2016-09-26 09:44:21 -07:00
{
2016-09-29 04:40:16 -07:00
case ' A ' : // sends the bytes of realtime values
2017-10-31 20:55:47 -07:00
sendcanValues ( 0 , CAN_PACKET_SIZE , 0x30 , 1 ) ; //send values to serial3
2016-09-29 04:40:16 -07:00
break ;
2016-09-26 09:44:21 -07:00
case ' G ' : // this is the reply command sent by the Can interface
2017-06-19 18:29:55 -07:00
byte destcaninchannel ;
2017-11-01 13:17:47 -07:00
if ( CANSerial . available ( ) > = 9 )
2017-06-19 18:29:55 -07:00
{
2017-11-01 13:17:47 -07:00
cancmdfail = CANSerial . read ( ) ; //0 == fail, 1 == good.
destcaninchannel = CANSerial . read ( ) ; // the input channel that requested the data value
2017-04-08 16:48:39 -07:00
if ( cancmdfail ! = 0 )
2017-07-02 05:54:41 -07:00
{ // read all 8 bytes of data.
2017-06-19 18:29:55 -07:00
for ( byte Gx = 0 ; Gx < 8 ; Gx + + ) // first two are the can address the data is from. next two are the can address the data is for.then next 1 or two bytes of data
{
Gdata [ Gx ] = CANSerial . read ( ) ;
}
2018-01-23 17:05:50 -08:00
Glow = Gdata [ ( configPage9 . caninput_source_start_byte [ destcaninchannel ] & 7 ) ] ;
if ( ( BIT_CHECK ( configPage9 . caninput_source_num_bytes , destcaninchannel ) ) ) //if true then num bytes is 2
2017-06-19 18:29:55 -07:00
{
2018-01-23 17:05:50 -08:00
if ( ( configPage9 . caninput_source_start_byte [ destcaninchannel ] & 7 ) < 8 ) //you cant have a 2 byte value starting at byte 7(8 on the list)
2017-06-19 18:29:55 -07:00
{
2018-01-23 17:05:50 -08:00
Ghigh = Gdata [ ( ( configPage9 . caninput_source_start_byte [ destcaninchannel ] & 7 ) + 1 ) ] ;
2017-06-19 18:29:55 -07:00
}
2017-07-02 05:54:41 -07:00
else { Ghigh = 0 ; }
2017-06-19 18:29:55 -07:00
}
2017-04-08 16:48:39 -07:00
else
2017-06-19 18:29:55 -07:00
{
Ghigh = 0 ;
}
2017-07-02 05:54:41 -07:00
currentStatus . canin [ destcaninchannel ] = ( Ghigh < < 8 ) | Glow ;
2017-01-10 23:30:46 -08:00
}
2017-05-31 01:57:36 -07:00
else { } //continue as command request failed and/or data/device was not available
2017-06-19 18:29:55 -07:00
}
2016-09-29 04:40:16 -07:00
break ;
2016-09-26 09:44:21 -07:00
2016-09-29 04:40:16 -07:00
case ' L ' :
uint8_t Llength ;
2017-05-31 01:57:36 -07:00
while ( CANSerial . available ( ) = = 0 ) { }
canlisten = CANSerial . read ( ) ;
2016-09-26 09:44:21 -07:00
if ( canlisten = = 0 )
{
//command request failed and/or data/device was not available
break ;
}
2017-05-31 01:57:36 -07:00
while ( CANSerial . available ( ) = = 0 ) { }
Llength = CANSerial . read ( ) ; // next the number of bytes expected value
2016-09-26 09:44:21 -07:00
for ( uint8_t Lcount = 0 ; Lcount < Llength ; Lcount + + )
2017-05-31 01:57:36 -07:00
{
while ( CANSerial . available ( ) = = 0 ) { }
// receive all x bytes into "Lbuffer"
Lbuffer [ Lcount ] = CANSerial . read ( ) ;
}
break ;
2017-05-08 15:15:03 -07:00
case ' r ' : //New format for the optimised OutputChannels
2017-07-02 05:54:41 -07:00
byte Cmd ;
2017-05-31 01:57:36 -07:00
if ( CANSerial . available ( ) > = 6 )
2017-05-08 15:15:03 -07:00
{
2017-05-31 01:57:36 -07:00
CANSerial . read ( ) ; //Read the $tsCanId
2017-06-12 18:58:00 -07:00
Cmd = CANSerial . read ( ) ;
2017-05-31 01:57:36 -07:00
uint16_t offset , length ;
2017-07-02 05:54:41 -07:00
if ( ( Cmd = = 0x30 ) | | ( ( Cmd > = 0x40 ) & & ( Cmd < 0x50 ) ) ) //Send output channels command 0x30 is 48dec, 0x40(64dec)-0x4F(79dec) are external can request
2017-05-31 01:57:36 -07:00
{
byte tmp ;
tmp = CANSerial . read ( ) ;
offset = word ( CANSerial . read ( ) , tmp ) ;
tmp = CANSerial . read ( ) ;
length = word ( CANSerial . read ( ) , tmp ) ;
2017-10-25 17:43:33 -07:00
sendcanValues ( offset , length , Cmd , 1 ) ;
2017-06-19 18:29:55 -07:00
//Serial.print(Cmd);
2017-05-31 01:57:36 -07:00
}
else
{
//No other r/ commands should be called
}
2017-05-08 15:15:03 -07:00
}
break ;
2017-05-31 01:57:36 -07:00
2016-09-26 09:44:21 -07:00
case ' S ' : // send code version
2017-10-04 00:02:12 -07:00
for ( unsigned int revn = 0 ; revn < sizeof ( TSfirmwareVersion ) - 1 ; revn + + )
{
CANSerial . write ( TSfirmwareVersion [ revn ] ) ;
}
2016-09-29 04:40:16 -07:00
//Serial3.print("speeduino 201609-dev");
break ;
2016-09-26 09:44:21 -07:00
case ' Q ' : // send code version
2017-05-31 01:57:36 -07:00
for ( unsigned int revn = 0 ; revn < sizeof ( TSfirmwareVersion ) - 1 ; revn + + )
{
CANSerial . write ( TSfirmwareVersion [ revn ] ) ;
2016-09-29 04:40:16 -07:00
}
//Serial3.print("speeduino 201609-dev");
break ;
2016-09-26 09:44:21 -07:00
2017-05-10 16:08:24 -07:00
case ' Z ' : //dev use
break ;
2017-05-31 01:57:36 -07:00
2016-09-26 09:44:21 -07:00
default :
2016-09-29 04:40:16 -07:00
break ;
2016-09-26 09:44:21 -07:00
}
}
2017-10-25 17:43:33 -07:00
void sendcanValues ( uint16_t offset , uint16_t packetLength , byte cmd , byte portType )
{
2017-10-31 20:55:47 -07:00
byte fullStatus [ CAN_PACKET_SIZE ] ;
2017-10-25 17:43:33 -07:00
//CAN serial
# if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)|| defined(CORE_STM32) || defined (CORE_TEENSY) //ATmega2561 does not have Serial3
if ( offset = = 0 )
{
CANSerial . write ( " A " ) ; //confirm cmd type
}
else
{
CANSerial . write ( " r " ) ; //confirm cmd type
CANSerial . write ( cmd ) ;
}
# endif
currentStatus . spark ^ = ( - currentStatus . hasSync ^ currentStatus . spark ) & ( 1 < < BIT_SPARK_SYNC ) ; //Set the sync bit of the Spark variable to match the hasSync variable
fullStatus [ 0 ] = currentStatus . secl ; //secl is simply a counter that increments each second. Used to track unexpected resets (Which will reset this count to 0)
fullStatus [ 1 ] = currentStatus . status1 ; //status1 Bitfield
fullStatus [ 2 ] = currentStatus . engine ; //Engine Status Bitfield
fullStatus [ 3 ] = ( byte ) ( divu100 ( currentStatus . dwell ) ) ; //Dwell in ms * 10
fullStatus [ 4 ] = lowByte ( currentStatus . MAP ) ; //2 bytes for MAP
fullStatus [ 5 ] = highByte ( currentStatus . MAP ) ;
fullStatus [ 6 ] = ( byte ) ( currentStatus . IAT + CALIBRATION_TEMPERATURE_OFFSET ) ; //mat
fullStatus [ 7 ] = ( byte ) ( currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ; //Coolant ADC
fullStatus [ 8 ] = currentStatus . batCorrection ; //Battery voltage correction (%)
fullStatus [ 9 ] = currentStatus . battery10 ; //battery voltage
fullStatus [ 10 ] = currentStatus . O2 ; //O2
fullStatus [ 11 ] = currentStatus . egoCorrection ; //Exhaust gas correction (%)
fullStatus [ 12 ] = currentStatus . iatCorrection ; //Air temperature Correction (%)
fullStatus [ 13 ] = currentStatus . wueCorrection ; //Warmup enrichment (%)
fullStatus [ 14 ] = lowByte ( currentStatus . RPM ) ; //rpm HB
fullStatus [ 15 ] = highByte ( currentStatus . RPM ) ; //rpm LB
fullStatus [ 16 ] = currentStatus . TAEamount ; //acceleration enrichment (%)
fullStatus [ 17 ] = currentStatus . corrections ; //Total GammaE (%)
fullStatus [ 18 ] = currentStatus . VE ; //Current VE 1 (%)
fullStatus [ 19 ] = currentStatus . afrTarget ;
fullStatus [ 20 ] = lowByte ( currentStatus . PW1 ) ; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
fullStatus [ 21 ] = highByte ( currentStatus . PW1 ) ; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
fullStatus [ 22 ] = currentStatus . tpsDOT ; //TPS DOT
fullStatus [ 23 ] = currentStatus . advance ;
fullStatus [ 24 ] = currentStatus . TPS ; // TPS (0% to 100%)
//Need to split the int loopsPerSecond value into 2 bytes
fullStatus [ 25 ] = lowByte ( currentStatus . loopsPerSecond ) ;
fullStatus [ 26 ] = highByte ( currentStatus . loopsPerSecond ) ;
//The following can be used to show the amount of free memory
currentStatus . freeRAM = freeRam ( ) ;
fullStatus [ 27 ] = lowByte ( currentStatus . freeRAM ) ; //(byte)((currentStatus.loopsPerSecond >> 8) & 0xFF);
fullStatus [ 28 ] = highByte ( currentStatus . freeRAM ) ;
fullStatus [ 29 ] = ( byte ) ( currentStatus . boostTarget > > 1 ) ; //Divide boost target by 2 to fit in a byte
fullStatus [ 30 ] = ( byte ) ( currentStatus . boostDuty / 100 ) ;
fullStatus [ 31 ] = currentStatus . spark ; //Spark related bitfield
//rpmDOT must be sent as a signed integer
fullStatus [ 32 ] = lowByte ( currentStatus . rpmDOT ) ;
fullStatus [ 33 ] = highByte ( currentStatus . rpmDOT ) ;
fullStatus [ 34 ] = currentStatus . ethanolPct ; //Flex sensor value (or 0 if not used)
fullStatus [ 35 ] = currentStatus . flexCorrection ; //Flex fuel correction (% above or below 100)
fullStatus [ 36 ] = currentStatus . flexIgnCorrection ; //Ignition correction (Increased degrees of advance) for flex fuel
fullStatus [ 37 ] = currentStatus . idleLoad ;
fullStatus [ 38 ] = currentStatus . testOutputs ;
fullStatus [ 39 ] = currentStatus . O2_2 ; //O2
fullStatus [ 40 ] = currentStatus . baro ; //Barometer value
fullStatus [ 41 ] = lowByte ( currentStatus . canin [ 0 ] ) ;
fullStatus [ 42 ] = highByte ( currentStatus . canin [ 0 ] ) ;
fullStatus [ 43 ] = lowByte ( currentStatus . canin [ 1 ] ) ;
fullStatus [ 44 ] = highByte ( currentStatus . canin [ 1 ] ) ;
fullStatus [ 45 ] = lowByte ( currentStatus . canin [ 2 ] ) ;
fullStatus [ 46 ] = highByte ( currentStatus . canin [ 2 ] ) ;
fullStatus [ 47 ] = lowByte ( currentStatus . canin [ 3 ] ) ;
fullStatus [ 48 ] = highByte ( currentStatus . canin [ 3 ] ) ;
fullStatus [ 49 ] = lowByte ( currentStatus . canin [ 4 ] ) ;
fullStatus [ 50 ] = highByte ( currentStatus . canin [ 4 ] ) ;
fullStatus [ 51 ] = lowByte ( currentStatus . canin [ 5 ] ) ;
fullStatus [ 52 ] = highByte ( currentStatus . canin [ 5 ] ) ;
fullStatus [ 53 ] = lowByte ( currentStatus . canin [ 6 ] ) ;
fullStatus [ 54 ] = highByte ( currentStatus . canin [ 6 ] ) ;
fullStatus [ 55 ] = lowByte ( currentStatus . canin [ 7 ] ) ;
fullStatus [ 56 ] = highByte ( currentStatus . canin [ 7 ] ) ;
fullStatus [ 57 ] = lowByte ( currentStatus . canin [ 8 ] ) ;
fullStatus [ 58 ] = highByte ( currentStatus . canin [ 8 ] ) ;
fullStatus [ 59 ] = lowByte ( currentStatus . canin [ 9 ] ) ;
fullStatus [ 60 ] = highByte ( currentStatus . canin [ 9 ] ) ;
fullStatus [ 61 ] = lowByte ( currentStatus . canin [ 10 ] ) ;
fullStatus [ 62 ] = highByte ( currentStatus . canin [ 10 ] ) ;
fullStatus [ 63 ] = lowByte ( currentStatus . canin [ 11 ] ) ;
fullStatus [ 64 ] = highByte ( currentStatus . canin [ 11 ] ) ;
fullStatus [ 65 ] = lowByte ( currentStatus . canin [ 12 ] ) ;
fullStatus [ 66 ] = highByte ( currentStatus . canin [ 12 ] ) ;
fullStatus [ 67 ] = lowByte ( currentStatus . canin [ 13 ] ) ;
fullStatus [ 68 ] = highByte ( currentStatus . canin [ 13 ] ) ;
fullStatus [ 69 ] = lowByte ( currentStatus . canin [ 14 ] ) ;
fullStatus [ 70 ] = highByte ( currentStatus . canin [ 14 ] ) ;
fullStatus [ 71 ] = lowByte ( currentStatus . canin [ 15 ] ) ;
fullStatus [ 72 ] = highByte ( currentStatus . canin [ 15 ] ) ;
fullStatus [ 73 ] = currentStatus . tpsADC ;
fullStatus [ 74 ] = getNextError ( ) ;
for ( byte x = 0 ; x < packetLength ; x + + )
{
if ( portType = = 1 ) { CANSerial . write ( fullStatus [ offset + x ] ) ; }
else if ( portType = = 2 )
{
//sendto canbus transmit routine
}
}
}
2016-09-26 09:44:21 -07:00
2017-05-08 15:15:03 -07:00
// this routine sends a request(either "0" for a "G" , "1" for a "L" , "2" for a "R" to the Can interface or "3" sends the request via the actual local canbus
2017-11-01 13:17:47 -07:00
void sendCancommand ( uint8_t cmdtype , uint16_t canaddress , uint8_t candata1 , uint8_t candata2 , uint16_t sourcecanAddress )
2016-09-26 09:44:21 -07:00
{
switch ( cmdtype )
{
case 0 :
2017-05-31 01:57:36 -07:00
CANSerial . print ( " G " ) ;
CANSerial . write ( canaddress ) ; //tscanid of speeduino device
CANSerial . write ( candata1 ) ; // table id
CANSerial . write ( candata2 ) ; //table memory offset
break ;
2017-05-10 16:08:24 -07:00
2017-05-31 01:57:36 -07:00
case 1 : //send request to listen for a can message
CANSerial . print ( " L " ) ;
CANSerial . write ( canaddress ) ; //11 bit canaddress of device to listen for
break ;
2017-04-08 16:48:39 -07:00
2017-06-19 18:29:55 -07:00
case 2 : // requests via serial3
CANSerial . print ( " R " ) ; //send "R" to request data from the parmagroup can address whos value is sent next
CANSerial . write ( candata1 ) ; //the currentStatus.current_caninchannel
2017-11-01 13:17:47 -07:00
CANSerial . write ( lowByte ( sourcecanAddress ) ) ; //send lsb first
CANSerial . write ( highByte ( sourcecanAddress ) ) ;
2017-05-31 01:57:36 -07:00
break ;
2017-05-08 15:15:03 -07:00
case 3 :
//send to truecan send routine
2017-06-19 18:29:55 -07:00
//canaddress == speeduino canid, candata1 == canin channel dest, paramgroup == can address to request from
2017-05-31 01:57:36 -07:00
break ;
2017-05-10 16:08:24 -07:00
2017-05-31 01:57:36 -07:00
default :
break ;
2017-02-07 20:40:44 -08:00
}
2016-09-26 09:44:21 -07:00
}