Initial work on new serial comms protocols (Working, but slow)

This commit is contained in:
Josh Stewart 2017-09-19 14:10:07 +10:00
parent 7ca7650a31
commit 6763ff15b4
4 changed files with 248 additions and 19 deletions

View File

@ -11,7 +11,7 @@
versionInfo = "S" ; Put this in the title bar.
[TunerStudio]
iniSpecVersion = 3.24
iniSpecVersion = 3.46
;-------------------------------------------------------------------------------
@ -98,23 +98,35 @@
endianness = little
nPages = 11
burnCommand = "B"
pageSize = 288, 64, 288, 64, 288, 64, 64, 160, 192, 128, 192
; pageIdentifier = "\$tsCanId\x01", "\$tsCanId\x02", "\$tsCanId\x03", "\$tsCanId\x04", "\$tsCanId\x05", "\$tsCanId\x06", "\$tsCanId\x07", "\$tsCanId\x08", "\$tsCanId\x09", "\$tsCanId\x0A"
pageActivationDelay = 10
pageActivate = "P\001", "P\002", "P\003", "P\004", "P\005", "P\006", "P\007", "P\010", "P\011", "P\012", "P\013"
pageReadCommand = "V", "V", "V", "V", "V", "V", "V", "V", "V", "V", "V"
pageValueWrite = "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v"
; pageChunkWrite = "" ; No chunk write yet
;pageSize = 288, 64, 288, 64, 288, 64, 64, 160, 192, 128, 192
;burnCommand = "B"
;pageActivate = "P\001", "P\002", "P\003", "P\004", "P\005", "P\006", "P\007", "P\010", "P\011", "P\012", "P\013"
;pageReadCommand = "V", "V", "V", "V", "V", "V", "V", "V", "V", "V", "V"
;pageValueWrite = "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v"
;pageChunkWrite = "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v"
;pageChunkWrite = "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v"
; New commands
pageSize = 288, 128, 288, 128, 288, 128, 128, 160, 192, 128, 192
pageIdentifier = "\$tsCanId\x01", "\$tsCanId\x02", "\$tsCanId\x03", "\$tsCanId\x04", "\$tsCanId\x05", "\$tsCanId\x06", "\$tsCanId\x07", "\$tsCanId\x08", "\$tsCanId\x09", "\$tsCanId\x0A", "\$tsCanId\x0B"
burnCommand = "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i"
pageReadCommand = "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v"
pageValueWrite = "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
;pageChunkWrite = "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
;pageChunkWrite = "w%2i%2o%2c%v", "", "w%2i%2o%2c%v", "", "w%2i%2o%2c%v", "", "", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
blockingFactor = 2048
tableBlockingFactor = 2048
delayAfterPortOpen=1000
;validateArrayBounds = true
blockReadTimeout = 2000
;tsWriteBlocks = off
;tsWriteBlocks = on
;writeBlocks = off
interWriteDelay = 5
interWriteDelay = 1
pageActivationDelay = 10
;New for TS 3.0.08ish upwards, define lists of standard I/O options

View File

@ -20,6 +20,9 @@ bool isMap = true;
unsigned long requestCount = 0; //The number of times the A command has been issued
byte currentCommand;
bool cmdPending = false;
bool chunkPending = false;
uint16_t chunkComplete = 0;
uint16_t chunkSize = 0;
byte cmdGroup = 0;
byte cmdValue = 0;
int cmdCombined = 0; //the cmdgroup as high byte and cmdvalue as low byte

View File

@ -15,7 +15,7 @@ A detailed description of each call can be found at: http://www.msextra.com/doc/
void command()
{
if (!cmdPending) { currentCommand = Serial.read(); }
if (cmdPending == false) { currentCommand = Serial.read(); }
switch (currentCommand)
{
@ -26,7 +26,18 @@ void command()
case 'B': // Burn current values to eeprom
writeConfig();
writeAllConfig();
break;
case 'b': // New EEPROM burn command to only burn a single page at a time
cmdPending = true;
if (Serial.available() >= 2)
{
Serial.read(); //Ignore the first table value, it's always 0
writeConfig(Serial.read());
cmdPending = false;
}
break;
case 'C': // test communications. This is used by Tunerstudio to see whether there is an ECU on a given serial port
@ -82,7 +93,7 @@ void command()
case 'Q': // send code version
Serial.print("speeduino 201709-dev");
break;
break;
case 'V': // send VE table and constants in binary
sendPage(false);
@ -117,6 +128,76 @@ void command()
break;
/*
* New method for sending page values
*/
case 'p':
cmdPending = true;
//6 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length
if(Serial.available() >= 6)
{
byte offset1, offset2, length1, length2;
int length;
byte tempPage;
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
tempPage = Serial.read();
//currentPage = 1;
offset1 = Serial.read();
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
length1 = Serial.read();
length2 = Serial.read();
length = word(length2, length1);
for(int x = 0; x < length; x++)
{
Serial.write( getPageValue(tempPage, valueOffset + x) );
}
cmdPending = false;
}
break;
case 'w':
cmdPending = true;
if(chunkPending == false)
{
//This means it's a new request
//7 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length (Should always be 1 until chunk write is setup)
//1 - New value
if(Serial.available() >= 7)
{
byte offset1, offset2, length1, length2;
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
currentPage = Serial.read();
//currentPage = 1;
offset1 = Serial.read();
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
length1 = Serial.read(); // Length to be written (Should always be 1)
length2 = Serial.read(); // Length to be written (Should always be 1)
chunkSize = word(length2, length1);
//chunkPending = true;
for(uint16_t x = 0; x < chunkSize; x++)
{
while(Serial.available() == 0) { }
receiveValue( (valueOffset + x), Serial.read());
}
cmdPending = false;
}
}
break;
case 't': // receive new Calibration info. Command structure: "t", <tble_idx> <data array>. This is an MS2/Extra command, NOT part of MS1 spec
byte tableID;
//byte canID;
@ -382,12 +463,16 @@ void receiveValue(int valueOffset, byte newValue)
//X Axis
fuelTable.axisX[(valueOffset - 256)] = ((int)(newValue) * TABLE_RPM_MULTIPLIER); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
}
else
else if(valueOffset < 288)
{
//Y Axis
int tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right
fuelTable.axisY[tempOffset] = (int)(newValue) * TABLE_LOAD_MULTIPLIER;
}
else
{
//This should never happen. It means there's an invalid offset value coming through
}
}
break;
@ -413,7 +498,7 @@ void receiveValue(int valueOffset, byte newValue)
//X Axis
ignitionTable.axisX[(valueOffset - 256)] = (int)(newValue) * TABLE_RPM_MULTIPLIER; //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
}
else
else if(valueOffset < 288)
{
//Y Axis
int tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
@ -544,6 +629,7 @@ void receiveValue(int valueOffset, byte newValue)
default:
break;
}
//if(Serial.available() > 16) { command(); }
}
/*
@ -980,6 +1066,130 @@ void sendPage(bool useChar)
} //sendComplete
}
byte getPageValue(byte page, uint16_t valueAddress)
{
void* pnt_configPage = &configPage1; //Default value is for safety only. Will be changed below if needed.
byte returnValue = 0;
switch (page)
{
case veMapPage:
if( valueAddress < 256) { returnValue = fuelTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(fuelTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(fuelTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case veSetPage:
pnt_configPage = &configPage1; //Create a pointer to Page 1 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case ignMapPage:
if( valueAddress < 256) { returnValue = ignitionTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(ignitionTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(ignitionTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case ignSetPage:
pnt_configPage = &configPage2; //Create a pointer to Page 2 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case afrMapPage:
if( valueAddress < 256) { returnValue = afrTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(afrTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(afrTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case afrSetPage:
pnt_configPage = &configPage3; //Create a pointer to Page 3 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case iacPage:
pnt_configPage = &configPage4; //Create a pointer to Page 4 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case boostvvtPage:
{
//Need to perform a translation of the values[MAP/TPS][RPM] into the MS expected format
if(valueAddress < 80)
{
//Boost table
if(valueAddress < 64) { returnValue = boostTable.values[7 - (valueAddress / 8)][valueAddress % 8]; }
else if(valueAddress < 72) { returnValue = byte(boostTable.axisX[(valueAddress - 64)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 80) { returnValue = byte(boostTable.axisY[7 - (valueAddress - 72)]); }
}
else
{
valueAddress -= 80;
//VVT table
if(valueAddress < 64) { returnValue = vvtTable.values[7 - (valueAddress / 8)][valueAddress % 8]; }
else if(valueAddress < 72) { returnValue = byte(vvtTable.axisX[(valueAddress - 64)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 80) { returnValue = byte(vvtTable.axisY[7 - (valueAddress - 72)]); }
}
}
break;
case seqFuelPage:
{
//Need to perform a translation of the values[MAP/TPS][RPM] into the TS expected format
if(valueAddress < 48)
{
//trim1 table
if(valueAddress < 36) { returnValue = trim1Table.values[5 - (valueAddress / 6)][valueAddress % 6]; }
else if(valueAddress < 42) { returnValue = byte(trim1Table.axisX[(valueAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 48) { returnValue = byte(trim1Table.axisY[5 - (valueAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 96)
{
valueAddress -= 48;
//trim2 table
if(valueAddress < 36) { returnValue = trim2Table.values[5 - (valueAddress / 6)][valueAddress % 6]; }
else if(valueAddress < 42) { returnValue = byte(trim2Table.axisX[(valueAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 48) { returnValue = byte(trim2Table.axisY[5 - (valueAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 144)
{
valueAddress -= 96;
//trim3 table
if(valueAddress < 36) { returnValue = trim3Table.values[5 - (valueAddress / 6)][valueAddress % 6]; }
else if(valueAddress < 42) { returnValue = byte(trim3Table.axisX[(valueAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 48) { returnValue = byte(trim3Table.axisY[5 - (valueAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 192)
{
valueAddress -= 144;
//trim4 table
if(valueAddress < 36) { returnValue = trim4Table.values[5 - (valueAddress / 6)][valueAddress % 6]; }
else if(valueAddress < 42) { returnValue = byte(trim4Table.axisX[(valueAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 48) { returnValue = byte(trim4Table.axisY[5 - (valueAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
}
break;
case canbusPage:
pnt_configPage = &configPage10; //Create a pointer to Page 10 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case warmupPage:
pnt_configPage = &configPage11; //Create a pointer to Page 11 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
default:
Serial.println(F("\nPage has not been implemented yet. Change to another page."));
//Just set default Values to avoid warnings
pnt_configPage = &configPage11;
break;
}
return returnValue;
}
/*
This function is used to store calibration data sent by Tuner Studio.
*/

View File

@ -130,6 +130,7 @@ bool initialisationComplete = false; //Tracks whether the setup() functino has r
void setup()
{
initialiseTimers();
digitalWrite(LED_BUILTIN, LOW);
//Setup the dummy fuel and ignition tables
//dummyFuelTable(&fuelTable);
@ -237,10 +238,8 @@ void setup()
//Set the tacho output default state
digitalWrite(pinTachOut, HIGH);
//Perform all initialisations
initialiseSchedulers();
initialiseTimers();
//initialiseDisplay();
initialiseIdle();
initialiseFan();
@ -300,6 +299,7 @@ void setup()
currentStatus.launchingHard = false;
currentStatus.crankRPM = ((unsigned int)configPage2.crankRPM * 100); //Crank RPM limit (Saves us calculating this over and over again. It's updated once per second in timers.ino)
triggerFilterTime = 0; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise. This is simply a default value, the actual values are set in the setup() functinos of each decoder
dwellLimit_uS = (1000 * configPage2.dwellLimit);
noInterrupts();
initialiseTriggers();
@ -648,11 +648,15 @@ void loop()
//Check for any requets from serial. Serial operations are checked under 2 scenarios:
// 1) Every 64 loops (64 Is more than fast enough for TunerStudio). This function is equivalent to ((loopCount % 64) == 1) but is considerably faster due to not using the mod or division operations
// 2) If the amount of data in the serial buffer is greater than a set threhold (See globals.h). This is to avoid serial buffer overflow when large amounts of data is being sent
if ( (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) || (Serial.available() > SERIAL_BUFFER_THRESHOLD) )
//if ( (BIT_CHECK(TIMER_mask, BIT_TIMER_15HZ)) || (Serial.available() > SERIAL_BUFFER_THRESHOLD) )
//if ( (timer15Hz == true) )
if ( ((mainLoopCount & 31) == 1) or (Serial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (Serial.available() > 0) { command(); }
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
//if serial3 interface is enabled then check for serial3 requests.
if (configPage10.enable_canbus == 1)