Refactor comms: save 130+ bytes RAM (#906)

* Remove serialCRC - only used within parseSerial()
Also hoist the CRC read into a function.

* Minimize global variable visibility

* Encapsulate write of multi-byte primitives

* Factor out sendBufferAndCrc()

* Push safety test into TS_CommandButtonsHandler()

* Extract writePage()

* Simpler parsing

* Remove some functions from public interface

* Store constant arrays in progmem

* Centralize high speed logger start/stop code

* Factor out loadO2Calibration()

* Factor out temperature calibration table update functions

* Remove dead code

* Fix sendToothLog()

* Fix sendCompositeLog()

* Replace tooth log send booleans with an enum
Saves a byte

* Remove sendBufferAndCrcProgMem()
Use serialPayload to send

* Whitespace clean up

* Optimize comms.cpp for size

* Replace global unsigned long with bool
Saves 2 bytes

* Replace 2 global bools with an enum
Saves a byte, reads better.

* Remove global FastCRC instance

* Make sendSerialReturnCode blocking.
It was using non-blocking functions but was never
re-entered.
Rename to make blocking & non-blocking calls
more obvious.

* Use one uint16_t to track RX/TX byte count

* Simplify new comms log tx API

* Extract loadPageToBuffer function

* All endianess changes use the same code

* Doxygen comments and code organization

* Remove serialWriteUpdateCrc() & updateTmpCalibration()

* Combine SerialStatus & logSendStatus enums.
Makes sense since we can only be doing one thing at a time.

* Remove global inProgressCompositeTime
Only used when sending composite log

* Replace 3 global bools with expanded SerialStatus enum

* Remove unused global tsCanId

* Limit scope of some comms globals.

* Remove isMap global - replace witth function

* Reduce the serial API to only 2 calls
transmit & receive

* Tidy up #define visibility

* Fix Black* build errors

* Workaround Teensy code race condition
availableForWrite() is not reliable.

* Prevent race condition
Was pematurely setting the serialStatusFlag to
SERIAL_INACTIVE before final CRC ws read from
serial.

* Use post write buffer availability checks
Remove buffer size check prior to writing.

* Write multi-byte values as single bytes.
(attempt to fix Teensy 3.5 issue)

* Only use Serial.available() as a boolean test
(Teensy fix)

* writeNonBlocking checks Serial.write() return value

* Non-blocking CRC write
In sendBufferAndCrcNonBlocking().

* Fix compile warning

* Set serial status flag prior to transmitting!

* Reliable blocking byte writes.

* Fix timeout code: not firing under some conditions

* MISRA fixes
This commit is contained in:
tx_haggis 2023-02-20 19:55:54 -06:00 committed by GitHub
parent 0e19fc86bc
commit f95b4978cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 948 additions and 878 deletions

120
Doxyfile
View File

@ -1,4 +1,4 @@
# Doxyfile 1.9.3
# Doxyfile 1.9.4
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -12,6 +12,15 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#
# Note:
#
# Use doxygen to compare the used configuration file with the template
# configuration file:
# doxygen -x [configFile]
# Use doxygen to compare the used configuration file with the template
# configuration file without replacing the environment variables:
# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
@ -60,16 +69,28 @@ PROJECT_LOGO = reference/speeduino_logo.png
OUTPUT_DIRECTORY = reference/doxygen
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# sub-directories (in 2 levels) under the output directory of each output format
# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
# Controls the number of sub-directories that will be created when
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
# level increment doubles the number of directories, resulting in 4096
# directories at level 8 which is the default and also the maximum value. The
# sub-directories are organized in 2 levels, the first level always has a fixed
# numer of 16 directories.
# Minimum value: 0, maximum value: 8, default value: 8.
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
CREATE_SUBDIRS_LEVEL = 8
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@ -81,14 +102,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@ -389,7 +410,7 @@ IDL_PROPERTY_SUPPORT = YES
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
DISTRIBUTE_GROUP_DOC = YES
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
@ -452,7 +473,7 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
@ -577,7 +598,7 @@ INTERNAL_DOCS = NO
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# are not case sensitive the option should be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
@ -851,10 +872,21 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
# In the $text part of the WARN_FORMAT command it is possible that a reference
# to a more specific place is given. To make it easier to jump to this place
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
# Example:
# WARN_LINE_FORMAT = "'vi $file +$line'"
# See also: WARN_FORMAT
# The default value is: at line $line of file $file.
WARN_LINE_FORMAT = "at line $line of file $file"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr). In case the file specified cannot be opened for writing the
@ -874,7 +906,8 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = speeduino/ contributing.md
INPUT = speeduino/ \
contributing.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -1166,6 +1199,46 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
# tag is set to YES then doxygen will add the directory of each input to the
# include path.
# The default value is: YES.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@ -2164,6 +2237,10 @@ DOCBOOK_OUTPUT = docbook
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
@ -2238,7 +2315,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
# preprocessor.
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@ -2259,7 +2337,8 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED =
PREDEFINED = __attribute__((x))= \
PROGMEM
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@ -2411,7 +2490,8 @@ CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
# groups, showing the direct groups dependencies.
# groups, showing the direct groups dependencies. See also the chapter Grouping
# in the manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.

View File

@ -71,4 +71,4 @@
#define TS_CMD_VSS_RATIO6 39174
/* the maximum id number is 65,535 */
void TS_CommandButtonsHandler(uint16_t buttonCommand);
bool TS_CommandButtonsHandler(uint16_t buttonCommand);

View File

@ -15,13 +15,24 @@
#include "acc_mc33810.h"
#endif
static bool commandRequiresStoppedEngine(uint16_t buttonCommand)
{
return ((buttonCommand >= TS_CMD_INJ1_ON) && (buttonCommand <= TS_CMD_IGN8_50PC))
|| ((buttonCommand == TS_CMD_TEST_ENBL) || (buttonCommand == TS_CMD_TEST_DSBL));
}
/**
* @brief
*
* @param buttonCommand The command number of the button that was clicked. See TS_CommendButtonHandler.h for a list of button IDs
*/
void TS_CommandButtonsHandler(uint16_t buttonCommand)
bool TS_CommandButtonsHandler(uint16_t buttonCommand)
{
if (commandRequiresStoppedEngine(buttonCommand) && currentStatus.RPM != 0)
{
return false;
}
switch (buttonCommand)
{
case TS_CMD_TEST_DSBL: // cmd is stop
@ -363,6 +374,9 @@ void TS_CommandButtonsHandler(uint16_t buttonCommand)
#endif
default:
return false;
break;
}
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -10,78 +10,14 @@
#ifndef NEW_COMMS_H
#define NEW_COMMS_H
//Hardcoded TunerStudio addresses/commands for various SD/RTC commands
#define SD_READWRITE_PAGE 0x11
#define SD_READFILE_PAGE 0x14
#define SD_RTC_PAGE 0x07
/**
* @brief The serial receive pump. Should be called whenever the serial port
* has data available to read.
*/
void serialReceive(void);
#define SD_READ_STAT_ARG1 0x0000
#define SD_READ_STAT_ARG2 0x0010
#define SD_READ_DIR_ARG1 0x0000
#define SD_READ_DIR_ARG2 0x0202
#define SD_READ_SEC_ARG1 0x0002
#define SD_READ_SEC_ARG2 0x0004
#define SD_READ_STRM_ARG1 0x0004
#define SD_READ_STRM_ARG2 0x0001
#define SD_READ_COMP_ARG1 0x0000 //Not used for anything
#define SD_READ_COMP_ARG2 0x0800
#define SD_RTC_READ_ARG1 0x024D
#define SD_RTC_READ_ARG2 0x0008
#define SD_WRITE_DO_ARG1 0x0000
#define SD_WRITE_DO_ARG2 0x0001
#define SD_WRITE_DIR_ARG1 0x0001
#define SD_WRITE_DIR_ARG2 0x0002
#define SD_WRITE_SEC_ARG1 0x0003
#define SD_WRITE_SEC_ARG2 0x0204
#define SD_WRITE_COMP_ARG1 0x0005
#define SD_WRITE_COMP_ARG2 0x0008
#define SD_ERASEFILE_ARG1 0x0006
#define SD_ERASEFILE_ARG2 0x0006
#define SD_SPD_TEST_ARG1 0x0007
#define SD_SPD_TEST_ARG2 0x0004
#define SD_RTC_WRITE_ARG1 0x027E
#define SD_RTC_WRITE_ARG2 0x0009
#define SERIAL_CRC_LENGTH 4
#define SERIAL_LEN_SIZE 2
#define SERIAL_OVERHEAD_SIZE (SERIAL_LEN_SIZE + SERIAL_CRC_LENGTH) //The overhead for each serial command is 6 bytes. 2 bytes for the length and 4 bytes for the CRC
#define SERIAL_TIMEOUT 3000 //ms
#ifdef RTC_ENABLED
#define SD_FILE_TRANSMIT_BUFFER_SIZE (2048 + 3)
extern uint16_t SDcurrentDirChunk;
extern uint32_t SDreadStartSector;
extern uint32_t SDreadNumSectors; //Number of sectors to read
extern uint32_t SDreadCompletedSectors; //Number of sectors that have been read
#endif
//Serial return codes
#define SERIAL_RC_OK 0x00
#define SERIAL_RC_REALTIME 0x01
#define SERIAL_RC_PAGE 0x02
#define SERIAL_RC_BURN_OK 0x04
#define SERIAL_RC_TIMEOUT 0x80 //Timeout error
#define SERIAL_RC_CRC_ERR 0x82
#define SERIAL_RC_UKWN_ERR 0x83 //Unknown command
#define SERIAL_RC_RANGE_ERR 0x84 //Incorrect range. TS will not retry command
#define SERIAL_RC_BUSY_ERR 0x85 //TS will wait and retry
extern bool serialWriteInProgress;
extern bool serialReceivePending; /**< Whether or not a serial request has only been partially received. This occurs when a the length has been received in the serial buffer, but not all of the payload or CRC has yet been received. */
void parseSerial(void);//This is the heart of the Command Line Interpreter. All that needed to be done was to make it human readable.
void processSerialCommand(void);
void sendSerialReturnCode(byte returnCode);
void sendSerialPayload(void* payload, uint16_t payloadLength);
void generateLiveValues(uint16_t offset, uint16_t packetLength);
void flushRXbuffer(void);
void sendToothLog(uint8_t startOffset);
void sendCompositeLog(uint8_t startOffset);
void continueSerialTransmission(void);
/** @brief The serial transmit pump. Should be called when ::serialStatusFlag indicates a transmit
* operation is in progress */
void serialTransmit(void);
#endif // COMMS_H

View File

@ -23,23 +23,22 @@ A full copy of the license may be found in the projects root directory
#include "rtc_common.h"
#endif
byte currentPage = 1;//Not the same as the speeduino config page numbers
bool isMap = true; /**< Whether or not the currentPage contains only a 3D map that would require translation */
unsigned long requestCount = 0; /**< The number of times the A command has been issued. This is used to track whether a reset has recently been performed on the controller */
byte currentCommand; /**< The serial command that is currently being processed. This is only useful when cmdPending=True */
bool cmdPending = false; /**< Whether or not a serial request has only been partially received. This occurs when a command character has been received in the serial buffer, but not all of its arguments have yet been received. If true, the active command will be stored in the currentCommand variable */
bool chunkPending = false; /**< Whether or not the current chunk write is complete or not */
uint16_t chunkComplete = 0; /**< The number of bytes in a chunk write that have been written so far */
uint16_t chunkSize = 0; /**< The complete size of the requested chunk write */
int valueOffset; /**< The memory offset within a given page for a value to be read from or written to. Note that we cannot use 'offset' as a variable name, it is a reserved word for several teensy libraries */
byte tsCanId = 0; // current tscanid requested
byte inProgressOffset;
static byte currentPage = 1;//Not the same as the speeduino config page numbers
bool firstCommsRequest = true; /**< The number of times the A command has been issued. This is used to track whether a reset has recently been performed on the controller */
static byte currentCommand; /**< The serial command that is currently being processed. This is only useful when cmdPending=True */
static bool chunkPending = false; /**< Whether or not the current chunk write is complete or not */
static uint16_t chunkComplete = 0; /**< The number of bytes in a chunk write that have been written so far */
static uint16_t chunkSize = 0; /**< The complete size of the requested chunk write */
static int valueOffset; /**< The memory offset within a given page for a value to be read from or written to. Note that we cannot use 'offset' as a variable name, it is a reserved word for several teensy libraries */
byte logItemsTransmitted;
byte inProgressLength;
uint32_t inProgressCompositeTime;
bool serialInProgress = false;
bool toothLogSendInProgress = false;
bool compositeLogSendInProgress = false;
bool legacySerial = false;
SerialStatus serialStatusFlag;
static bool isMap(void) {
// Detecting if the current page is a table/map
return (currentPage == veMapPage) || (currentPage == ignMapPage) || (currentPage == afrMapPage) || (currentPage == fuelMap2Page) || (currentPage == ignMap2Page);
}
/** Processes the incoming data on the serial buffer based on the command sent.
Can be either data for a new command or a continuation of data for command that is already in progress:
@ -50,20 +49,19 @@ Commands are single byte (letter symbol) commands.
*/
void legacySerialCommand(void)
{
if ( (cmdPending == false) && (legacySerial == false) ) { currentCommand = Serial.read(); }
if ( serialStatusFlag == SERIAL_INACTIVE ) { currentCommand = Serial.read(); }
switch (currentCommand)
{
case 'a':
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (Serial.available() >= 2)
{
Serial.read(); //Ignore the first value, it's always 0
Serial.read(); //Ignore the second value, it's always 6
sendValuesLegacy();
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -71,19 +69,20 @@ void legacySerialCommand(void)
sendValues(0, LOG_ENTRY_SIZE, 0x31, 0); //send values to serial0
break;
case 'B': // Burn current values to eeprom
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
writeAllConfig();
serialStatusFlag = SERIAL_INACTIVE;
break;
case 'b': // New EEPROM burn command to only burn a single page at a time
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (Serial.available() >= 2)
{
Serial.read(); //Ignore the first table value, it's always 0
writeConfig(Serial.read());
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -97,7 +96,7 @@ void legacySerialCommand(void)
break;
case 'd': // Send a CRC32 hash of a given page
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (Serial.available() >= 2)
{
@ -110,37 +109,18 @@ void legacySerialCommand(void)
Serial.write( ((CRC32_val >> 8) & 255) );
Serial.write( (CRC32_val & 255) );
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
case 'E': // receive command button commands
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if(Serial.available() >= 2)
{
byte cmdGroup = Serial.read();
byte cmdValue = Serial.read();
uint16_t cmdCombined = word(cmdGroup, cmdValue);
if ( ((cmdCombined >= TS_CMD_INJ1_ON) && (cmdCombined <= TS_CMD_IGN8_50PC)) || (cmdCombined == TS_CMD_TEST_ENBL) || (cmdCombined == TS_CMD_TEST_DSBL) )
{
//Hardware test buttons
if (currentStatus.RPM == 0) { TS_CommandButtonsHandler(cmdCombined); }
cmdPending = false;
}
else if( (cmdCombined >= TS_CMD_VSS_60KMH) && (cmdCombined <= TS_CMD_VSS_RATIO6) )
{
//VSS Calibration commands
TS_CommandButtonsHandler(cmdCombined);
cmdPending = false;
}
else if( (cmdCombined >= TS_CMD_STM32_REBOOT) && (cmdCombined <= TS_CMD_STM32_BOOTLOADER) )
{
//STM32 DFU mode button
TS_CommandButtonsHandler(cmdCombined);
cmdPending = false;
}
byte cmdGroup = (byte)Serial.read();
(void)TS_CommandButtonsHandler(word(cmdGroup, Serial.read()));
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -160,7 +140,7 @@ void legacySerialCommand(void)
{
Serial.write(EEPROMReadRaw(x));
}
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
break;
case 'g': // Receive a dump of raw EEPROM values from the user
@ -182,62 +162,26 @@ void legacySerialCommand(void)
EEPROMWriteRaw(x, Serial.read());
}
}
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
break;
}
case 'H': //Start the tooth logger
currentStatus.toothLogEnabled = true;
currentStatus.compositeLogEnabled = false; //Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
startToothLogger();
Serial.write(1); //TS needs an acknowledgement that this was received. I don't know if this is the correct response, but it seems to work
break;
case 'h': //Stop the tooth logger
currentStatus.toothLogEnabled = false;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
stopToothLogger();
break;
case 'J': //Start the composite logger
currentStatus.compositeLogEnabled = true;
currentStatus.toothLogEnabled = false; //Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
startCompositeLogger();
Serial.write(1); //TS needs an acknowledgement that this was received. I don't know if this is the correct response, but it seems to work
break;
case 'j': //Stop the composite logger
currentStatus.compositeLogEnabled = false;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
stopCompositeLogger();
break;
case 'L': // List the contents of current page in human readable form
@ -259,7 +203,7 @@ void legacySerialCommand(void)
case 'P': // set the current page
//This is a legacy function and is no longer used by TunerStudio. It is maintained for compatibility with other systems
//A 2nd byte of data is required after the 'P' specifying the new page number.
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (Serial.available() > 0)
{
@ -277,11 +221,7 @@ void legacySerialCommand(void)
{
currentPage -= 55;
}
// Detecting if the current page is a table/map
if ( (currentPage == veMapPage) || (currentPage == ignMapPage) || (currentPage == afrMapPage) || (currentPage == fuelMap2Page) || (currentPage == ignMap2Page) ) { isMap = true; }
else { isMap = false; }
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -289,7 +229,7 @@ void legacySerialCommand(void)
* New method for sending page values
*/
case 'p':
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
//6 bytes required:
//2 - Page identifier
@ -315,7 +255,7 @@ void legacySerialCommand(void)
Serial.write( getPageValue(tempPage, valueOffset + i) );
}
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -325,11 +265,11 @@ void legacySerialCommand(void)
break;
case 'r': //New format for the optimised OutputChannels
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
byte cmd;
if (Serial.available() >= 6)
{
tsCanId = Serial.read(); //Read the $tsCanId
Serial.read(); //Read the $tsCanId
cmd = Serial.read(); // read the command
uint16_t offset, length;
@ -339,6 +279,7 @@ void legacySerialCommand(void)
tmp = Serial.read();
length = word(Serial.read(), tmp);
serialStatusFlag = SERIAL_INACTIVE;
if(cmd == 0x30) //Send output channels command 0x30 is 48dec
{
@ -348,7 +289,6 @@ void legacySerialCommand(void)
{
//No other r/ commands are supported in legacy mode
}
cmdPending = false;
}
break;
@ -363,7 +303,7 @@ void legacySerialCommand(void)
//2 - Page identifier
//2 - offset
//2 - Length
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if(Serial.available() >= 6)
{
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
@ -375,12 +315,8 @@ void legacySerialCommand(void)
if(currentStatus.toothLogEnabled == true) { sendToothLog_legacy(0); } //Sends tooth log values as ints
else if (currentStatus.compositeLogEnabled == true) { sendCompositeLog_legacy(0); }
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
case 't': // receive new Calibration info. Command structure: "t", <tble_idx> <data array>.
@ -400,7 +336,7 @@ void legacySerialCommand(void)
if (resetControl != RESET_CONTROL_DISABLED)
{
#ifndef SMALL_FLASH_MODE
if (!cmdPending) { Serial.println(F("Comms halted. Next byte will reset the Arduino.")); }
if (serialStatusFlag == SERIAL_INACTIVE) { Serial.println(F("Comms halted. Next byte will reset the Arduino.")); }
#endif
while (Serial.available() == 0) { }
@ -409,7 +345,7 @@ void legacySerialCommand(void)
else
{
#ifndef SMALL_FLASH_MODE
if (!cmdPending) { Serial.println(F("Reset control is currently disabled.")); }
if (serialStatusFlag == SERIAL_INACTIVE) { Serial.println(F("Reset control is currently disabled.")); }
#endif
}
break;
@ -419,9 +355,9 @@ void legacySerialCommand(void)
break;
case 'W': // receive new VE obr constant at 'W'+<offset>+<newbyte>
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (isMap)
if (isMap())
{
if(Serial.available() >= 3) // 1 additional byte is required on the MAP pages which are larger than 255 bytes
{
@ -430,7 +366,7 @@ void legacySerialCommand(void)
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
setPageValue(currentPage, valueOffset, Serial.read());
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
}
else
@ -439,14 +375,14 @@ void legacySerialCommand(void)
{
valueOffset = Serial.read();
setPageValue(currentPage, valueOffset, Serial.read());
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
}
break;
case 'M':
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if(chunkPending == false)
{
@ -483,7 +419,7 @@ void legacySerialCommand(void)
setPageValue(currentPage, (valueOffset + chunkComplete), Serial.read());
chunkComplete++;
}
if(chunkComplete >= chunkSize) { cmdPending = false; chunkPending = false; }
if(chunkComplete >= chunkSize) { serialStatusFlag = SERIAL_INACTIVE; chunkPending = false; }
}
break;
@ -544,11 +480,11 @@ void legacySerialCommand(void)
break;
case '`': //Custom 16u2 firmware is making its presence known
cmdPending = true;
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if (Serial.available() >= 1) {
configPage4.bootloaderCaps = Serial.read();
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
break;
@ -589,7 +525,7 @@ void legacySerialCommand(void)
default:
Serial.println(F("Err: Unknown cmd"));
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
break;
}
}
@ -603,9 +539,10 @@ void legacySerialCommand(void)
* E.g. tuning sw command 'A' (Send all values) will send data from field number 0, LOG_ENTRY_SIZE fields.
* @return the current values of a fixed group of variables
*/
//void sendValues(int packetlength, byte portNum)
void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
{
serialStatusFlag = SERIAL_TRANSMIT_INPROGRESS_LEGACY;
if (portNum == 3)
{
//CAN serial
@ -622,8 +559,11 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
}
else
{
if(requestCount == 0) { currentStatus.secl = 0; }
requestCount++;
if(firstCommsRequest)
{
firstCommsRequest = false;
currentStatus.secl = 0;
}
}
currentStatus.spark ^= (-currentStatus.hasSync ^ currentStatus.spark) & (1U << BIT_SPARK_SYNC); //Set the sync bit of the Spark variable to match the hasSync variable
@ -639,17 +579,15 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
if(Serial.availableForWrite() < 1)
{
//tx buffer is full. Store the current state so it can be resumed later
inProgressOffset = offset + x + 1;
logItemsTransmitted = offset + x + 1;
inProgressLength = packetLength - x - 1;
serialInProgress = true;
return;
}
}
serialInProgress = false;
serialStatusFlag = SERIAL_INACTIVE;
// Reset any flags that are being used to trigger page refreshes
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_VSS_REFRESH);
}
void sendValuesLegacy(void)
@ -1155,33 +1093,21 @@ void receiveCalibration(byte tableID)
* if useChar is true, the values are sent as chars to be printed out by a terminal emulator
* if useChar is false, the values are sent as a 2 byte integer which is readable by TunerStudios tooth logger
*/
void sendToothLog_legacy(byte startOffset)
void sendToothLog_legacy(byte startOffset) /* Blocking */
{
//We need TOOTH_LOG_SIZE number of records to send to TunerStudio. If there aren't that many in the buffer then we just return and wait for the next call
if (BIT_CHECK(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY)) //Sanity check. Flagging system means this should always be true
{
serialStatusFlag = SERIAL_TRANSMIT_TOOTH_INPROGRESS_LEGACY;
for (int x = startOffset; x < TOOTH_LOG_SIZE; x++)
{
//Check whether the tx buffer still has space
/*
if(Serial.availableForWrite() < 4)
{
//tx buffer is full. Store the current state so it can be resumed later
inProgressOffset = x;
toothLogSendInProgress = true;
return;
}
*/
Serial.write(toothHistory[x] >> 24);
Serial.write(toothHistory[x] >> 16);
Serial.write(toothHistory[x] >> 8);
Serial.write(toothHistory[x]);
}
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
cmdPending = false;
toothLogSendInProgress = false;
serialStatusFlag = SERIAL_INACTIVE;
toothHistoryIndex = 0;
}
else
@ -1191,27 +1117,27 @@ void sendToothLog_legacy(byte startOffset)
{
Serial.write(static_cast<byte>(0x00)); //GCC9 fix
}
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
}
void sendCompositeLog_legacy(byte startOffset)
void sendCompositeLog_legacy(byte startOffset) /* Non-blocking */
{
if (BIT_CHECK(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY)) //Sanity check. Flagging system means this should always be true
{
if(startOffset == 0) { inProgressCompositeTime = 0; }
serialStatusFlag = SERIAL_TRANSMIT_COMPOSITE_INPROGRESS_LEGACY;
for (int x = startOffset; x < TOOTH_LOG_SIZE; x++)
{
//Check whether the tx buffer still has space
if(Serial.availableForWrite() < 4)
{
//tx buffer is full. Store the current state so it can be resumed later
inProgressOffset = x;
compositeLogSendInProgress = true;
logItemsTransmitted = x;
return;
}
inProgressCompositeTime = toothHistory[x]; //This combined runtime (in us) that the log was going for by this record)
uint32_t inProgressCompositeTime = toothHistory[x]; //This combined runtime (in us) that the log was going for by this record)
Serial.write(inProgressCompositeTime >> 24);
Serial.write(inProgressCompositeTime >> 16);
@ -1222,9 +1148,7 @@ void sendCompositeLog_legacy(byte startOffset)
}
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
cmdPending = false;
compositeLogSendInProgress = false;
inProgressCompositeTime = 0;
serialStatusFlag = SERIAL_INACTIVE;
}
else
{
@ -1233,11 +1157,11 @@ void sendCompositeLog_legacy(byte startOffset)
{
Serial.write(static_cast<byte>(0x00)); //GCC9 fix
}
cmdPending = false;
serialStatusFlag = SERIAL_INACTIVE;
}
}
void testComm()
void testComm(void)
{
Serial.write(1);
return;

View File

@ -10,24 +10,67 @@
#ifndef COMMS_H
#define COMMS_H
/** \enum SerialStatus
* @brief The current state of serial communication
* */
enum SerialStatus {
/** No serial comms is in progress */
SERIAL_INACTIVE,
/** A partial write is in progress. */
SERIAL_TRANSMIT_INPROGRESS,
/** A partial write is in progress (legacy send). */
SERIAL_TRANSMIT_INPROGRESS_LEGACY,
/** We are part way through transmitting the tooth log */
SERIAL_TRANSMIT_TOOTH_INPROGRESS,
/** We are part way through transmitting the tooth log (legacy send) */
SERIAL_TRANSMIT_TOOTH_INPROGRESS_LEGACY,
/** We are part way through transmitting the composite log */
SERIAL_TRANSMIT_COMPOSITE_INPROGRESS,
/** We are part way through transmitting the composite log (legacy send) */
SERIAL_TRANSMIT_COMPOSITE_INPROGRESS_LEGACY,
/** Whether or not a serial request has only been partially received.
* This occurs when a the length has been received in the serial buffer,
* but not all of the payload or CRC has yet been received.
*
* Expectation is that ::serialReceive is called until the status reverts
* to SERIAL_INACTIVE
*/
SERIAL_RECEIVE_INPROGRESS,
/** We are part way through processing a legacy serial commang: call ::serialReceive */
SERIAL_COMMAND_INPROGRESS_LEGACY,
};
/** @brief Current status of serial comms. */
extern SerialStatus serialStatusFlag;
extern byte currentPage;//Not the same as the speeduino config page numbers
extern bool isMap; /**< Whether or not the currentPage contains only a 3D map that would require translation */
extern unsigned long requestCount; /**< The number of times the A command has been issued. This is used to track whether a reset has recently been performed on the controller */
extern byte currentCommand; /**< The serial command that is currently being processed. This is only useful when cmdPending=True */
extern bool cmdPending; /**< Whether or not a serial request has only been partially received. This occurs when a command character has been received in the serial buffer, but not all of its arguments have yet been received. If true, the active command will be stored in the currentCommand variable */
extern bool chunkPending; /**< Whether or not the current chunk write is complete or not */
extern uint16_t chunkComplete; /**< The number of bytes in a chunk write that have been written so far */
extern uint16_t chunkSize; /**< The complete size of the requested chunk write */
extern int valueOffset; /**< THe memory offset within a given page for a value to be read from or written to. Note that we cannot use 'offset' as a variable name, it is a reserved word for several teensy libraries */
extern byte tsCanId; // current tscanid requested
extern byte inProgressOffset;
/**
* @brief Is a serial write in progress?
*
* Expectation is that ::serialTransmit is called until this
* returns false
*/
inline bool serialTransmitInProgress(void) {
return serialStatusFlag==SERIAL_TRANSMIT_INPROGRESS
|| serialStatusFlag==SERIAL_TRANSMIT_INPROGRESS_LEGACY
|| serialStatusFlag==SERIAL_TRANSMIT_TOOTH_INPROGRESS
|| serialStatusFlag==SERIAL_TRANSMIT_TOOTH_INPROGRESS_LEGACY
|| serialStatusFlag==SERIAL_TRANSMIT_COMPOSITE_INPROGRESS
|| serialStatusFlag==SERIAL_TRANSMIT_COMPOSITE_INPROGRESS_LEGACY;
}
/**
* @brief Is a non-blocking serial receive operation in progress?
*
* Expectation is the ::serialReceive is called until this
* returns false.
*/
inline bool serialRecieveInProgress(void) {
return serialStatusFlag==SERIAL_RECEIVE_INPROGRESS
|| serialStatusFlag==SERIAL_COMMAND_INPROGRESS_LEGACY;
}
extern bool firstCommsRequest; /**< The number of times the A command has been issued. This is used to track whether a reset has recently been performed on the controller */
extern byte logItemsTransmitted;
extern byte inProgressLength;
extern bool legacySerial;
extern uint32_t inProgressCompositeTime;
extern bool serialInProgress;
extern bool toothLogSendInProgress;
extern bool compositeLogSendInProgress;
void legacySerialCommand(void);//This is the heart of the Command Line Interpreter. All that needed to be done was to make it human readable.
void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum);

35
speeduino/comms_sd.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
//Hardcoded TunerStudio addresses/commands for various SD/RTC commands
#define SD_READWRITE_PAGE 0x11
#define SD_READFILE_PAGE 0x14
#define SD_RTC_PAGE 0x07
#define SD_READ_STAT_ARG1 0x0000
#define SD_READ_STAT_ARG2 0x0010
#define SD_READ_DIR_ARG1 0x0000
#define SD_READ_DIR_ARG2 0x0202
#define SD_READ_SEC_ARG1 0x0002
#define SD_READ_SEC_ARG2 0x0004
#define SD_READ_STRM_ARG1 0x0004
#define SD_READ_STRM_ARG2 0x0001
#define SD_READ_COMP_ARG1 0x0000 //Not used for anything
#define SD_READ_COMP_ARG2 0x0800
#define SD_RTC_READ_ARG1 0x024D
#define SD_RTC_READ_ARG2 0x0008
#define SD_WRITE_DO_ARG1 0x0000
#define SD_WRITE_DO_ARG2 0x0001
#define SD_WRITE_DIR_ARG1 0x0001
#define SD_WRITE_DIR_ARG2 0x0002
#define SD_WRITE_SEC_ARG1 0x0003
#define SD_WRITE_SEC_ARG2 0x0204
#define SD_WRITE_COMP_ARG1 0x0005
#define SD_WRITE_COMP_ARG2 0x0008
#define SD_ERASEFILE_ARG1 0x0006
#define SD_ERASEFILE_ARG2 0x0006
#define SD_SPD_TEST_ARG1 0x0007
#define SD_SPD_TEST_ARG2 0x0004
#define SD_RTC_WRITE_ARG1 0x027E
#define SD_RTC_WRITE_ARG2 0x0009

View File

@ -248,9 +248,9 @@
#define TOOTH_LOG_SIZE 1
#endif
#define O2_CALIBRATION_PAGE 2
#define IAT_CALIBRATION_PAGE 1
#define CLT_CALIBRATION_PAGE 0
#define O2_CALIBRATION_PAGE 2U
#define IAT_CALIBRATION_PAGE 1U
#define CLT_CALIBRATION_PAGE 0U
#define COMPOSITE_LOG_PRI 0
#define COMPOSITE_LOG_SEC 1
@ -450,7 +450,6 @@ This is so we can use an unsigned byte (0-255) to represent temperature ranges f
extern const char TSfirmwareVersion[] PROGMEM;
extern const byte data_structure_version; //This identifies the data structure when reading / writing. Now in use: CURRENT_DATA_VERSION (migration on-the fly) ?
extern FastCRC32 CRC32; //Generic CRC32 instance for general use in pages etc. Note that the serial comms has its own CRC32 instance
extern struct table3d16RpmLoad fuelTable; //16x16 fuel map
extern struct table3d16RpmLoad fuelTable2; //16x16 fuel map

View File

@ -6,7 +6,6 @@
const char TSfirmwareVersion[] PROGMEM = "Speeduino";
const byte data_structure_version = 2; //This identifies the data structure when reading / writing. (outdated ?)
FastCRC32 CRC32;
struct table3d16RpmLoad fuelTable; ///< 16x16 fuel map
struct table3d16RpmLoad fuelTable2; ///< 16x16 fuel map

View File

@ -28,6 +28,12 @@ int16_t getReadableLogEntry(uint16_t logIndex);
#endif
bool is2ByteEntry(uint8_t key);
void startToothLogger(void);
void stopToothLogger(void);
void startCompositeLogger(void);
void stopCompositeLogger(void);
// This array indicates which index values from the log are 2 byte values
// This array MUST remain in ascending order
// !!!! WARNING: If any value above 255 is required in this array, changes MUST be made to is2ByteEntry() function !!!!

View File

@ -360,4 +360,58 @@ bool is2ByteEntry(uint8_t key)
}
return isFound;
}
}
void startToothLogger(void)
{
currentStatus.toothLogEnabled = true;
currentStatus.compositeLogEnabled = false; //Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
}
void stopToothLogger(void)
{
currentStatus.toothLogEnabled = false;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
}
void startCompositeLogger(void)
{
currentStatus.compositeLogEnabled = true;
currentStatus.toothLogEnabled = false; //Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
}
void stopCompositeLogger(void)
{
currentStatus.compositeLogEnabled = false;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
}

View File

@ -3,32 +3,32 @@
#include "pages.h"
#include "table3d_axis_io.h"
typedef uint32_t (FastCRC32::*pCrcCalc)(const uint8_t *, const uint16_t, bool);
using pCrcCalc = uint32_t (FastCRC32::*)(const uint8_t *, const uint16_t, bool);
static inline uint32_t compute_raw_crc(const page_iterator_t &entity, pCrcCalc calcFunc)
static inline uint32_t compute_raw_crc(const page_iterator_t &entity, pCrcCalc calcFunc, FastCRC32 &crcCalc)
{
return (CRC32.*calcFunc)((uint8_t*)entity.pData, entity.size, false);
return (crcCalc.*calcFunc)((uint8_t*)entity.pData, entity.size, false);
}
static inline uint32_t compute_row_crc(const table_row_iterator &row, pCrcCalc calcFunc)
static inline uint32_t compute_row_crc(const table_row_iterator &row, pCrcCalc calcFunc, FastCRC32 &crcCalc)
{
return (CRC32.*calcFunc)(&*row, row.size(), false);
return (crcCalc.*calcFunc)(&*row, row.size(), false);
}
static inline uint32_t compute_tablevalues_crc(table_value_iterator it, pCrcCalc calcFunc)
static inline uint32_t compute_tablevalues_crc(table_value_iterator it, pCrcCalc calcFunc, FastCRC32 &crcCalc)
{
uint32_t crc = compute_row_crc(*it, calcFunc);
uint32_t crc = compute_row_crc(*it, calcFunc, crcCalc);
++it;
while (!it.at_end())
{
crc = compute_row_crc(*it, &FastCRC32::crc32_upd);
crc = compute_row_crc(*it, &FastCRC32::crc32_upd, crcCalc);
++it;
}
return crc;
}
static inline uint32_t compute_tableaxis_crc(table_axis_iterator it, uint32_t crc)
static inline uint32_t compute_tableaxis_crc(table_axis_iterator it, uint32_t crc, FastCRC32 &crcCalc)
{
const int16_byte *pConverter = table3d_axis_io::get_converter(it.get_domain());
@ -39,41 +39,43 @@ static inline uint32_t compute_tableaxis_crc(table_axis_iterator it, uint32_t cr
*pValue++ = pConverter->to_byte(*it);
++it;
}
return pValue-values==0 ? crc : CRC32.crc32_upd(values, pValue-values, false);
return pValue-values==0 ? crc : crcCalc.crc32_upd(values, pValue-values, false);
}
static inline uint32_t compute_table_crc(page_iterator_t &entity, pCrcCalc calcFunc)
static inline uint32_t compute_table_crc(const page_iterator_t &entity, pCrcCalc calcFunc, FastCRC32 &crcCalc)
{
return compute_tableaxis_crc(y_begin(entity),
compute_tableaxis_crc(x_begin(entity),
compute_tablevalues_crc(rows_begin(entity), calcFunc)));
compute_tablevalues_crc(rows_begin(entity), calcFunc, crcCalc),
crcCalc),
crcCalc);
}
static inline uint32_t pad_crc(uint16_t padding, uint32_t crc)
static inline uint32_t pad_crc(uint16_t padding, uint32_t crc, FastCRC32 &crcCalc)
{
const uint8_t raw_value = 0u;
while (padding>0)
{
crc = CRC32.crc32_upd(&raw_value, 1, false);
crc = crcCalc.crc32_upd(&raw_value, 1, false);
--padding;
}
return crc;
}
static inline uint32_t compute_crc(page_iterator_t &entity, pCrcCalc calcFunc)
static inline uint32_t compute_crc(const page_iterator_t &entity, pCrcCalc calcFunc, FastCRC32 &crcCalc)
{
switch (entity.type)
{
case Raw:
return compute_raw_crc(entity, calcFunc);
return compute_raw_crc(entity, calcFunc, crcCalc);
break;
case Table:
return compute_table_crc(entity, calcFunc);
return compute_table_crc(entity, calcFunc, crcCalc);
break;
case NoEntity:
return pad_crc(entity.size, 0U);
return pad_crc(entity.size, 0U, crcCalc);
break;
default:
@ -84,15 +86,16 @@ static inline uint32_t compute_crc(page_iterator_t &entity, pCrcCalc calcFunc)
uint32_t calculatePageCRC32(byte pageNum)
{
FastCRC32 crcCalc;
page_iterator_t entity = page_begin(pageNum);
// Initial CRC calc
uint32_t crc = compute_crc(entity, &FastCRC32::crc32);
uint32_t crc = compute_crc(entity, &FastCRC32::crc32, crcCalc);
entity = advance(entity);
while (entity.type!=End)
{
crc = compute_crc(entity, &FastCRC32::crc32_upd /* Note that we are *updating* */);
crc = compute_crc(entity, &FastCRC32::crc32_upd /* Note that we are *updating* */, crcCalc);
entity = advance(entity);
}
return ~pad_crc(getPageSize(pageNum) - entity.size, crc);
return ~pad_crc(getPageSize(pageNum) - entity.size, crc, crcCalc);
}

View File

@ -121,36 +121,15 @@ void loop(void)
//SERIAL Comms
//Initially check that the last serial send values request is not still outstanding
if (serialInProgress == true)
{
if(Serial.availableForWrite() > 16) { sendValues(inProgressOffset, inProgressLength, 0x30, 0); }
}
//Perform the same check for the tooth and composite logs
if( toothLogSendInProgress == true)
if (serialTransmitInProgress())
{
if(Serial.availableForWrite() > 16)
{
if(legacySerial == true) { sendToothLog_legacy(inProgressOffset); }
else { sendToothLog(inProgressOffset); }
}
}
if( compositeLogSendInProgress == true)
{
if(Serial.availableForWrite() > 16) { sendCompositeLog(inProgressOffset); }
}
if(serialWriteInProgress == true)
{
if(Serial.availableForWrite() > 16) { continueSerialTransmission(); }
serialTransmit();
}
//Check for any new requests from serial.
//if ( (Serial.available()) > 0) { command(); }
if ( (Serial.available()) > 0) { parseSerial(); }
else if(cmdPending == true)
//Check for any new or in-progress requests from serial.
if (Serial.available()>0 || serialRecieveInProgress())
{
//This is a special case just for the tooth and composite loggers
if (currentCommand == 'T') { legacySerialCommand(); }
serialReceive();
}
//Check for any CAN comms requiring action
@ -301,8 +280,6 @@ void loop(void)
// Air conditioning control
airConControl();
//if( (isEepromWritePending() == true) && (serialReceivePending == false) && (micros() > deferEEPROMWritesUntil)) { writeAllConfig(); } //Used for slower EEPROM writes (Currently this runs in the 30Hz block)
currentStatus.vss = getSpeed();
currentStatus.gear = getGear();
@ -334,7 +311,7 @@ void loop(void)
#endif
//Check for any outstanding EEPROM writes.
if( (isEepromWritePending() == true) && (serialReceivePending == false) && (micros() > deferEEPROMWritesUntil)) { writeAllConfig(); }
if( (isEepromWritePending() == true) && (serialStatusFlag == SERIAL_INACTIVE) && (micros() > deferEEPROMWritesUntil)) { writeAllConfig(); }
}
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ))
{