Update a batch of files copyright year ranges and make the script more useable.
[freeems-vanilla.git] / src / decoders / BenchTest.c
blobf4c8a387ac67ec3e86dcad160f336041ef0875db
1 /* FreeEMS - the open source engine management system
3 * Copyright 2011-2012 Fred Cooke
5 * This file is part of the FreeEMS project.
7 * FreeEMS software is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * FreeEMS software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
20 * We ask that if you make any changes to this file you email them upstream to
21 * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
23 * Thank you for choosing FreeEMS to run your engine!
27 /** @file
29 * @ingroup enginePositionRPMDecoders
31 * To facilitate testing of output circuits and physical hardware such as
32 * injectors and coils on the bench or in the car.
34 * This "decoder" is intended to generate an output pattern that allows various
35 * testing to occur without any external stimulus. This is useful for scheduler
36 * testing, injector testing, output hardware testing, coil testing, etc. This
37 * will be the only decoder that will be usable with just a cpu and comms interface.
39 * @todo TODO setup the timer registers as required.
43 #define DECODER_IMPLEMENTATION_C
44 #define DECODER_MAX_CODE_TIME 66 // TODO measure reality
45 #define NUMBER_OF_REAL_EVENTS 1 // no events really...
46 #define NUMBER_OF_VIRTUAL_EVENTS 1 // no events really...
49 #include "../inc/freeEMS.h"
50 #include "../inc/interrupts.h"
51 #include "../inc/decoderInterface.h"
52 #include "inc/BenchTest.h"
55 // Setup the timer interrupts as internal timers only triggered by a serial call that returns if this isn't the decoder.
56 void decoderInitPreliminary(){
57 // Configure 0 and 1 as outputs, but decouple them from the interrupts
58 TIOS = 0xFF; // All outputs
60 // Disable capture when in IC mode.
61 TCTL4 = 0x00; // TODO Unrequired, remove.
63 // Leave configured to not toggle the pin at all (0,0)
64 // Std behaviour, no change required
66 // Disable interrupts, to be enabled by a serial trigger
67 TIE = 0x00;
71 void perDecoderReset(){} // Nothing special to reset for this code
74 const unsigned short eventAngles[] = {0}; // no events really...
75 const unsigned char eventValidForCrankSync[] = {0}; // no events really...
78 /* Fire from serial, then repeat X revolutions or seconds or whatever and trigger Z outputs of various types etc
80 * Possible modes of repetition:
81 * - Iterations
82 * - Revolutions
83 * - Time units
85 void PrimaryRPMISR(){
86 TFLG = 0x01;
87 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS, BIT0, PORTB);
89 unsigned short edgeTimeStamp = TC0;
91 /* Reset the clock for reading timeout */
92 Clocks.timeoutADCreadingClock = 0;
94 // call sched output with args
95 LongTime timeStamp;
96 /* Install the low word */
97 timeStamp.timeShorts[1] = edgeTimeStamp;
98 /* Find out what our timer value means and put it in the high word */
99 if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
100 timeStamp.timeShorts[0] = timerExtensionClock + 1;
101 }else{
102 timeStamp.timeShorts[0] = timerExtensionClock;
105 unsigned char shouldFire = 1;
106 // unsigned long localPeriod = 0; // mutlifire or busy wait, if doing this, check last period for some min, and if too small, shrink second to last and increase last
107 // unsigned short localPeriod = 0; // normal mode
108 if(testMode == TEST_MODE_ITERATIONS){
109 KeyUserDebugs.currentEvent++;
110 if(KeyUserDebugs.currentEvent == testEventsPerCycle){
111 KeyUserDebugs.currentEvent = 0;
112 testNumberOfCycles--;
113 if(testNumberOfCycles == 0){
114 // Disable the interrupt again, to be enabled by a serial trigger
115 TIE &= NBIT0;
116 coreStatusA &= CLEAR_BENCH_TEST_ON;
117 return;
121 // TODO make this more sophisticated
122 TC0 += testTicksPerEvent;
123 }else if(testMode == TEST_MODE_DODGY_MISSING_TOOTH){
124 KeyUserDebugs.currentEvent++;
125 if(KeyUserDebugs.currentEvent == testEventsPerCycle){
126 KeyUserDebugs.currentEvent = 0;
127 testNumberOfCycles--;
128 if(testNumberOfCycles == 0){
129 // Disable the interrupt again, to be enabled by a serial trigger
130 TIE &= NBIT0;
131 coreStatusA &= CLEAR_BENCH_TEST_ON;
132 return;
136 // Grab updated time period
137 testTicksPerEvent = CoreVars->RPM;
139 // Output the sync pulse only once per "engine cycle"
140 if(KeyUserDebugs.currentEvent == 0){
141 // Schedule the cam pulse
142 outputEventDelayFinalPeriod[1] = 3*(testTicksPerEvent/4);
143 outputEventPulseWidthsMath[1] = testTicksPerEvent;
144 outputEventInputEventNumbers[1] = KeyUserDebugs.currentEvent;
145 }else{
146 outputEventInputEventNumbers[1] = 0xFF;
149 // Generate crank strength signal
150 unsigned char fakeCurrentEvent = 0;
151 if(KeyUserDebugs.currentEvent >= (testEventsPerCycle/2)){
152 fakeCurrentEvent = KeyUserDebugs.currentEvent - (testEventsPerCycle/2);
153 }else{
154 fakeCurrentEvent = KeyUserDebugs.currentEvent;
157 // Schedule the main teeth, or not
158 if(fakeCurrentEvent < testNumberOfMissing){
159 outputEventInputEventNumbers[0] = 0xFF;
160 }else{
161 outputEventDelayFinalPeriod[0] = decoderMaxCodeTime;
162 outputEventInputEventNumbers[0] = KeyUserDebugs.currentEvent;
164 unsigned short singleWidth = testTicksPerEvent/2;
165 // See if this is the last one before the gap
166 if((KeyUserDebugs.currentEvent == ((testEventsPerCycle / 2) - 1)) || (KeyUserDebugs.currentEvent == (testEventsPerCycle - 1))){
167 // Migrate this to a safeMultiply() inline function
168 unsigned long wideWideWidth = (unsigned long)singleWidth * (testNumberOfMissing + 1);
169 if(wideWideWidth < SHORTMAX){
170 outputEventPulseWidthsMath[0] = (unsigned short)wideWideWidth;
171 }else{
172 outputEventPulseWidthsMath[0] = SHORTMAX;
174 }else{
175 outputEventPulseWidthsMath[0] = singleWidth;
179 TC0 += testTicksPerEvent;
180 }else if(testMode == TEST_MODE_REVOLUTIONS){
181 // sub modes of different patterns, use scheduler for this by setting the ADC array up and probing/triggering/touching/poking/starting/
182 // switch statement for selecting different const arrays of angles, use busy wait, or multiple interrupt to do larger gaps for lower rpms/coarse events
183 // perhaps accept the pattern in the input packet and busy wait on some "run completed" flag before returning and freeing the buffer.
184 // TEMP de-configure timers and leave shouldFire zeroed.
185 TIE &= NBIT0;
186 }else if(testMode == TEST_MODE_TIME_UNITS_SECONDS){
187 // reset all timer modes for first time around, then check for timer >= requested value, check appropriate units of time, obviously...
188 // TEMP de-configure timers and leave shouldFire zeroed.
189 TIE &= NBIT0;
190 }else if(testMode == TEST_MODE_TIME_UNITS_MINUTES){
191 // ditto
192 // TEMP de-configure timers and leave shouldFire zeroed.
193 TIE &= NBIT0;
194 }else if(testMode == TEST_MODE_TIME_UNITS_HOURS){
195 // ditto again
196 // TEMP de-configure timers and leave shouldFire zeroed.
197 TIE &= NBIT0;
198 }else{
199 // de-configure timers and leave shouldFire zeroed.
200 TIE &= NBIT0;
203 if(shouldFire){
204 // configuration for multiple periods setup here?
206 // fire outputs here
207 unsigned char channel;
208 for(channel = 0;channel < 6;channel++){
209 if(KeyUserDebugs.currentEvent == outputEventInputEventNumbers[channel]){
210 schedulePortTPin(channel, timeStamp);
214 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS, NBIT0, PORTB);
218 #include "inc/defaultSecondaryRPMISR.c"