FreeEMS  0.2.0-SNAPSHOT-285-g028e24c
Macros | Functions
main.c File Reference

The main function! More...

#include "inc/main.h"
Include dependency graph for main.c:

Go to the source code of this file.

Macros

#define NUMBER_OF_OUTPUT_PINS   6

Functions

int main ()
 The main function!

Detailed Description

The main function!

The function main is traditionally an applications starting point. For us it has two jobs. The first is to call init() which initialises everything before any normal code runs. After that main() is simply an infinite loop from which low priority non-realtime code runs. The most important units of code that runs under the main loop umbrella are the injection, ignition and scheduling calculations.

Definition in file main.c.

Macro Definition Documentation

#define NUMBER_OF_OUTPUT_PINS   6

Referenced by main().

Function Documentation

int main ( )

The main function!

The centre of the application is here. From here all non-ISR code is called directly or indirectly. The two coarse blocks are init and the main loop. Init is called first to set everything up and then the main loop is entered where the flow of control continues until the device is switched off or reset (excluding asynchronous ISR code). Currently the main loop only runs the fuel, ignition and scheduling calculation code, and the communications code and only when actually required. The intention is to maintain a very low latency for calculations such that the behaviour of the device more closely reflects the attached engines rapidly changing requirements. When accessory code is added a new scheduling algorithm will be required to keep the latency low without starving any particular blocks of CPU time.

Todo:
TODO maybe move this to paged flash ?
Todo:
TODO Add verification reporting code here that disables the timer interrupts such that no events ever get scheduled, and then sits looping sending error packets out about what is wrong. set a whole bunch of flags and check them here sending a packet for each with a unique errorID for each and thus a unique easy to understand message for each on the PC side. BEFORE the priming code such that no fuel gets injected. Will need to modularise the comms stuff to process packets based on calls from this section too, avoid excess duplication if possible.

Store PTIT for now, later make address of byte configurable TODO

Todo:

Definition at line 57 of file main.c.

References ADCBuffers, ADCBuffers0, ADCBuffers1, ADCBuffersRecord, adjustPWM(), asyncDatalogBasic, asyncDatalogBlockBytes, asyncDatalogBlockLongs, asyncDatalogBlockWords, asyncDatalogOff, asyncDatalogPosition, asyncDatalogScratchPad, asyncDatalogStreamByte, asyncDatalogStreamLong, asyncDatalogStreamWord, asyncDatalogStructs, ATOMIC_END, ATOMIC_START, CALC_FUEL_IGN, calculateFuelAndIgnition(), Counter::calculationsPerformed, CoreVar::CHT, CLEAR_CALC_FUEL_IGN, CLEAR_FORCE_READING, COM_SET_SCI0_INTERFACE_ID, coreStatusA, CoreVars, Counters, decodePacketAndRespond(), DerivedVars, edgeTimeStamp, EVENT_ARRIVAL_TIMEOUT, finaliseAndSend(), fixedConfigs1, FORCE_READING, generateCoreVars(), generateDerivedVars(), HEADER_HAS_LENGTH, DerivedVar::IDT, init(), lastCalcCount, lookupTwoDTableUS(), MAX_NUMBER_OF_OUTPUT_EVENTS, NUMBER_OF_OUTPUT_PINS, schedulingSetting::numberOfConfiguredOutputEvents, outputEventDelayFinalPeriod, schedulingSetting::outputEventPinNumbers, outputEventPulseWidthsMath, performSimpleGPIO(), populateBasicDatalog(), PTIT, resetToNonRunningState(), responseBasicDatalog, responseByteLADatalog, RX_CLEAR_READY_TO_PROCESS, RX_READY_TO_PROCESS, RXStateFlags, safeAdd(), sampleEachADC(), scheduleOutputs(), schedulePortTPin(), schedulingSetting::schedulingConfigurationBits, fixedConfig1::schedulingSettings, SHORTHALF, sleepMicro(), TCNT, TFLGOF, ticksPerDegree, ticksPerDegree0, ticksPerDegree1, ticksPerDegreeRecord, Counter::timeoutADCreadings, timerExtensionClock, LongTime::timeShorts, timeStamp, TRUE, TXBufferCurrentPositionCAN0, TXBufferCurrentPositionHandler, TXBufferCurrentPositionSCI0, and TXBufferInUseFlags.

{ /// @todo TODO maybe move this to paged flash ?
// Set everything up.
init();
/// @todo TODO Add verification reporting code here that disables the timer interrupts such that no events ever get scheduled, and then sits looping sending error packets out about what is wrong. set a whole bunch of flags and check them here sending a packet for each with a unique errorID for each and thus a unique easy to understand message for each on the PC side. BEFORE the priming code such that no fuel gets injected. Will need to modularise the comms stuff to process packets based on calls from this section too, avoid excess duplication if possible.
// TODO move this to a function so that it can be called on a hot restart post being asleep.
#define NUMBER_OF_OUTPUT_PINS 6
unsigned char outputEvent;
unsigned char activeFuelChannels[NUMBER_OF_OUTPUT_PINS] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
for(outputEvent = 0;outputEvent < fixedConfigs1.schedulingSettings.numberOfConfiguredOutputEvents;outputEvent++){
if(fixedConfigs1.schedulingSettings.schedulingConfigurationBits[outputEvent] == 1 && fixedConfigs1.schedulingSettings.outputEventPinNumbers[outputEvent] < NUMBER_OF_OUTPUT_PINS) { // todo remove second condition?
activeFuelChannels[fixedConfigs1.schedulingSettings.outputEventPinNumbers[outputEvent]] = outputEvent;
}
}
sampleEachADC(ADCBuffers); // Read sensors
generateCoreVars(); // Calculate BRV
generateDerivedVars(); // Calculate IDT
unsigned short primingPulseWidth = lookupTwoDTableUS((twoDTableUS*)&TablesA.SmallTablesA.primingVolumeTable, CoreVars->CHT);
primingPulseWidth = safeAdd(primingPulseWidth, DerivedVars->IDT);
unsigned short edgeTimeStamp = TCNT;
// call sched output with args
/* Install the low word */
timeStamp.timeShorts[1] = edgeTimeStamp;
/* Find out what our timer value means and put it in the high word */
if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
timeStamp.timeShorts[0] = timerExtensionClock + 1;
}else{
}
unsigned char outputPin;
for(outputPin = 0; outputPin< NUMBER_OF_OUTPUT_PINS; outputPin++){
if(activeFuelChannels[outputPin] < MAX_NUMBER_OF_OUTPUT_EVENTS){
outputEventPulseWidthsMath[activeFuelChannels[outputPin]] = primingPulseWidth;
outputEventDelayFinalPeriod[activeFuelChannels[outputPin]] = SHORTHALF;
schedulePortTPin(activeFuelChannels[outputPin], timeStamp);
}
}
// Run forever repeating.
while(TRUE){
//unsigned short start = realTimeClockMillis;
/* If ADCs require forced sampling, sample now */
ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
/* Atomic block to ensure a full set of readings are taken together */
/* Check to ensure that a reading wasn't take before we entered a non interruptable state */
if(coreStatusA & FORCE_READING){ // do we still need to do this TODO ?
sampleEachADC(ADCBuffersRecord); // TODO still need to do a pair of loops and clock these two functions for performance.
//sampleLoopADC(&ADCBuffers);
/* Set flag to say calc required */
/* Clear force reading flag */
}
ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
}
/* If required, do main fuel and ignition calcs first */
ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
/* Atomic block to ensure that we don't clear the flag for the next data set when things are tight */
/* Switch input bank so that we have a stable set of the latest data */
ticksPerDegree = &ticksPerDegree0; // TODO temp, remove, maybe
ticksPerDegreeRecord = &ticksPerDegree1; // TODO temp, remove, maybe
}else{
ticksPerDegree = &ticksPerDegree1; // TODO temp, remove, maybe
ticksPerDegreeRecord = &ticksPerDegree0; // TODO temp, remove, maybe
}
/* Clear the calc required flag */
ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
// TODO DEBUG/TUNING MACRO HERE!
/* Keep track of how many calcs we are managing per second... */
/* Generate the core variables from sensor input and recorded tooth timings */
// TODO DEBUG/TUNING MACRO HERE!
/* Generate the derived variables from the core variables based on settings */
// TODO DEBUG/TUNING MACRO HERE!
/* Perform the calculations TODO possibly move this to the software interrupt if it makes sense to do so */
// TODO DEBUG/TUNING MACRO HERE!
/* Calculate the scheduling based on configuration and previously calculated variables */
// TODO DEBUG/TUNING MACRO HERE!
}else{
/* In the event that no calcs are required, sleep a little before returning to retry. */
sleepMicro(3000); // TODO tune this, and then replace it completely. not doing this will cause the ISR lockouts to run for too high a proportion of the time
/* Using 0.8 ticks as micros so it will run for a little longer than the math did */
}
/* If the flag for com packet processing is set and the TX buffer is available process the data! */
/* Clear the flag */
/* Handle the incoming packet */
}else{// if(lastCalcCount != Counters.calculationsPerformed){ // substitute true for full speed continuous stream test...
/* send asynchronous data log if required */
switch (TablesB.SmallTablesB.loggingSettings.datalogStreamType) {
{
break;
}
{
/* Flag that we are transmitting! */
// SCI0 only for now...
// headers including length... *length = configuredBasicDatalogLength;
TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
/* Initialised here such that override is possible */
TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer;
TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer;
/* Set the flags : firmware, no ack, no addrs, has length */
/* Set the payload ID */
/* Set the length */
unsigned short* localLength = (unsigned short*)TXBufferCurrentPositionHandler;
/* populate data log */
*localLength = populateBasicDatalog();
break;
}
{
break;
}
{
break;
}
{
break;
}
{
break;
}
{
break;
}
{
break;
}
{
/* Flag that we are transmitting! */
// SCI0 only for now...
// headers including length... *length = configuredBasicDatalogLength;
TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
/* Initialised here such that override is possible */
TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer;
TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer;
/* Set the flags all zeros */
/* Set the payload ID */
/** Store PTIT for now, later make address of byte configurable TODO @todo */
*((unsigned char*)TXBufferCurrentPositionHandler) = PTIT;
break;
}
{
break;
}
{
break;
}
}
// mechanism to ensure we only send something if the data has been updated
}
}
// PWM experimentation
}
}

Here is the call graph for this function: