Add missing flaggables2 clearing block to counter clear call and reuse a local variable.
[freeems-vanilla.git] / src / main / commsCore.c
blob4f3e8a04a400319234f072a75cead823102cb73f
1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2013 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 communicationsFiles
31 * @brief Core communications functions.
33 * This file contains most of the core comms functionality. Currently that is
34 * only for UART serial style communication. It is already too big and needs
35 * to be split up somewhat. This will happen fairly soon during the serial
36 * refactoring and protocol fine tuning.
38 * @todo TODO function to setup a packet and send it fn(populateBodyFunctionPointer(), header, other, fields, here, and, use, or, not, within){}
39 * @todo TODO factor many things into functions and move the receive delegator to its own file
43 #define COMMSCORE_C
44 #include "inc/freeEMS.h"
45 #include "inc/flashWrite.h"
46 #include "inc/interrupts.h"
47 #include "inc/utils.h"
48 #include "inc/tableLookup.h"
49 #include "inc/locationIDs.h"
50 #include "inc/blockDetailsLookup.h"
51 #include "inc/decoderInterface.h"
52 #include "inc/commsCore.h"
53 #include "inc/init.h"
54 #include <string.h> /// @todo TODO this is pulling in the system string.h not the m68hc1x version, and functions other than memcpy do not work because they are not in crt1.o or other included-by-default libs
55 #include "decoders/inc/BenchTest.h"
58 /** @brief Populate a basic datalog packet
60 * Copies various chunks of data to the transmission buffer and truncates to
61 * the configured length. If changing this, update the maxBasicDatalogLength.
63 unsigned short populateBasicDatalog(){
64 /// @todo TODO setup proper sequence and clock with some sort of differential measurement log to log. insert in front of actual data because these are part of the log itself.
66 // Log scheduling data by default for the time being.
67 CoreVars->DTPS = Counters.normalSchedule;
68 CoreVars->DMAP = Counters.timerStretchedToSchedule;
69 // CoreVars->DRPM = ?; currently in use logging *ticksPerDegree 27 December 2012, see line ~123 of coreVarsGenerator.c
70 // CoreVars->DDRPM = ?;
72 KeyUserDebugs.zsp3 = Counters.pinScheduledToGoHigh;
73 KeyUserDebugs.zsp4 = Counters.pinScheduledAlready;
74 KeyUserDebugs.zsp5 = Counters.pinScheduledToSelfSchedule;
75 KeyUserDebugs.zsp6 = Counters.pinScheduledAgainToStayOn;
76 KeyUserDebugs.zsp7 = Counters.pinScheduledToToggleError;
77 KeyUserDebugs.zsp8 = Counters.pinScheduledToDoNothing;
78 KeyUserDebugs.zsp9 = Counters.pinScheduledFromCold;
79 // ? = Counters.pinScheduledWithTimerExtension;
81 KeyUserDebugs.coreStatusA = coreStatusA;
82 KeyUserDebugs.clockIn8thsOfAMilli = Clocks.realTimeClockMain;
83 KeyUserDebugs.clockInMilliSeconds = Clocks.realTimeClockMillis;
85 unsigned short confSize = 0;
86 unsigned char chunkLimit = TablesB.SmallTablesB.loggingSettings.firstChunk + TablesB.SmallTablesB.loggingSettings.numberOfChunks;
87 unsigned char chunks;
88 for(chunks=TablesB.SmallTablesB.loggingSettings.firstChunk;chunks<chunkLimit;chunks++){
89 unsigned short localSize = TablesB.SmallTablesB.loggingSettings.logChunks[chunks].size;
90 confSize += localSize;
91 if(confSize > 2048){
92 confSize -= localSize;
93 break;
95 memcpy(TXBufferCurrentPositionHandler, TablesB.SmallTablesB.loggingSettings.logChunks[chunks].address, localSize);
96 TXBufferCurrentPositionHandler += localSize;
98 // After copying data, otherwise tempClock is NEVER zero and reset detection does NOT work
99 KeyUserDebugs.tempClock++;
100 return confSize;
104 // All of these require some range checking, eg only some registers, and all RAM, not flash, not other regs
105 // TODO pointer for one byte
106 // TODO pointer for one short
107 // TODO function to log generic memory region by location and size ? requires length!
108 // Ranges are :
109 // RAM window
110 // bss/data region
111 // IO registers etc that can't be altered simply by reading from.
112 // NOT :
113 // flash makes no sense
114 // some regs are sensitive
115 // some RAM is unused
116 // serial buffers make no sense
117 // eeprom makes no sense
119 // 2k of regs max - user beware for now
120 // 12k of RAM max
122 //init :
123 //logaddr = fixed.addr
124 //loglen = fixed.len
126 //len = loglen OR 1 OR 2
128 //check :
129 //if((addr < 0x0800) && (length < (0x0800 - addr))){
130 // // reg space is OK
131 //}else if(((0x1000 < addr) && (addr < 0x4000)) && (length < (0x4000 - addr))){
132 // // RAM space is OK
133 //}else{
134 // // send an error instead
137 //run check at init and set time, not run time or just not check?? maybe its silly to check at all
139 // /* Just dump the ADC channels as fast as possible */
140 //void populateScopeLogADCAll(){
141 // sampleBlockADC(TXBufferCurrentPositionHandler);
142 // TXBufferCurrentPositionHandler += sizeof(ADCBuffer);
146 // what does this mean >> ??? TODO Look at the time stamps and where to write them, also whether to function call these simple blocks or write one function that handles all the logic.
149 /** @brief Finalise a packet and send it
151 * This functions job is to finalise the main loop part of the packet sending
152 * process. It configures the pos/neg ack header bit, adds the code if neg,
153 * runs a checksum over the packet data and tags it to the end before
154 * configuring the various ISRs that need to send the data out.
156 * @bug http://issues.freeems.org/view.php?id=81
157 * @todo TODO fix the double/none start byte bug and remove the hack!
159 void finaliseAndSend(unsigned short errorID){
161 if(errorID != 0){
162 *TXHeaderFlags |= HEADER_IS_NACK;
163 *((unsigned short*)TXBufferCurrentPositionHandler) = errorID;
164 TXBufferCurrentPositionHandler += 2;
167 /* Tag the checksum on the end */
168 *TXBufferCurrentPositionHandler = checksum((unsigned char*)&TXBuffer, ((unsigned short)TXBufferCurrentPositionHandler - (unsigned short)&TXBuffer));
170 /* Send it out on all the channels required. */
172 /* SCI0 - Main serial interface */
173 if(TXBufferInUseFlags & COM_SET_SCI0_INTERFACE_ID){
174 /* Initiate transmission */
175 SCI0DRL = START_BYTE;
177 /* Note : Order Is Important! */
178 /* TX empty flag is already set, so we must clear it by writing out before enabling the interrupt */
179 SCI0CR2 |= (SCICR2_TX_ENABLE | SCICR2_TX_ISR_ENABLE);
181 /* CAN0 - Main CAN interface */
182 if(TXBufferInUseFlags & COM_SET_CAN0_INTERFACE_ID){
183 // just clear up front for now
184 TXBufferInUseFlags &= COM_CLEAR_CAN0_INTERFACE_ID;
186 /* spare2 */
187 if(TXBufferInUseFlags & COM_SET_SPARE2_INTERFACE_ID){
188 // just clear up front for now
189 TXBufferInUseFlags &= COM_CLEAR_SPARE2_INTERFACE_ID;
191 /* spare3 */
192 if(TXBufferInUseFlags & COM_SET_SPARE3_INTERFACE_ID){
193 // just clear up front for now
194 TXBufferInUseFlags &= COM_CLEAR_SPARE3_INTERFACE_ID;
196 /* spare4 */
197 if(TXBufferInUseFlags & COM_SET_SPARE4_INTERFACE_ID){
198 // just clear up front for now
199 TXBufferInUseFlags &= COM_CLEAR_SPARE4_INTERFACE_ID;
201 /* spare5 */
202 if(TXBufferInUseFlags & COM_SET_SPARE5_INTERFACE_ID){
203 // just clear up front for now
204 TXBufferInUseFlags &= COM_CLEAR_SPARE5_INTERFACE_ID;
206 /* spare6 */
207 if(TXBufferInUseFlags & COM_SET_SPARE6_INTERFACE_ID){
208 // just clear up front for now
209 TXBufferInUseFlags &= COM_CLEAR_SPARE6_INTERFACE_ID;
211 /* spare7 */
212 if(TXBufferInUseFlags & COM_SET_SPARE7_INTERFACE_ID){
213 // just clear up front for now
214 TXBufferInUseFlags &= COM_CLEAR_SPARE7_INTERFACE_ID;
219 /** @brief Decode a packet and respond
221 * This is the core function that controls which functionality is run when a
222 * packet is received in full by the ISR code and control is passed back to the
223 * main loop code. The vast majority of communications action happens here.
225 void decodePacketAndRespond(){
226 /* Extract and build up the header fields */
227 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
229 /* Initialised here such that override is possible */
230 TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer;
231 TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer;
233 // How big was the packet that we got back
234 unsigned short RXPacketLengthReceived = (unsigned short)RXBufferCurrentPosition - (unsigned short)&RXBuffer;
236 /* Check that the packet is big enough for header,ID,checksum */
237 if(RXPacketLengthReceived < 4){
238 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
239 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_PACKETS_UNDER_LENGTH_OFFSET);
240 KeyUserDebugs.serialAndCommsCodeErrors++;
241 return;
244 /* Pull out the received checksum and calculate the real one, then check */
245 unsigned char RXReceivedChecksum = (unsigned char)*(RXBufferCurrentPosition - 1);
246 unsigned char RXCalculatedChecksum = checksum((unsigned char*)&RXBuffer, RXPacketLengthReceived - 1);
247 if(RXCalculatedChecksum != RXReceivedChecksum){
248 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
249 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_CHECKSUM_MISMATCHES_OFFSET);
250 KeyUserDebugs.serialAndCommsCodeErrors++;
251 return;
254 /* Start this off as full packet length and build down to the actual length */
255 RXCalculatedPayloadLength = RXPacketLengthReceived;
257 /* Grab the RX header flags out of the RX buffer */
258 RXBufferCurrentPosition = (unsigned char*)&RXBuffer;
259 RXHeaderFlags = *RXBufferCurrentPosition;
260 RXBufferCurrentPosition++;
261 RXCalculatedPayloadLength--;
263 /* Flag that we are transmitting! */
264 TXBufferInUseFlags |= COM_SET_SCI0_INTERFACE_ID;
265 // SCI0 only for now...
267 /* Load a blank header into the TX buffer ready for masking */
268 TXHeaderFlags = TXBufferCurrentPositionHandler;
269 *TXHeaderFlags = 0;
270 TXBufferCurrentPositionHandler++;
272 /* Grab the payload ID for processing and load the return ID */
273 RXHeaderPayloadID = *((unsigned short*)RXBufferCurrentPosition);
274 *((unsigned short*)TXBufferCurrentPositionHandler) = RXHeaderPayloadID + 1;
275 RXBufferCurrentPosition += 2;
276 TXBufferCurrentPositionHandler += 2;
277 RXCalculatedPayloadLength -= 2;
279 /* Check that the length is sufficient for the fields configured. Packets
280 * that are too long will be caught and rejected on an individual payload
281 * ID basis as the information required to handle that is not available at
282 * this point. Packets that are too short are rejected immediately!
284 if(((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 7))
285 || ((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXPacketLengthReceived < 6))
286 || ((RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 5))){
287 finaliseAndSend(packetTooShortForSpecifiedFields);
288 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
289 return;
292 /* Subtract checksum to get final length */
293 RXCalculatedPayloadLength--;
295 if(RXHeaderFlags & HEADER_HAS_SEQUENCE){
296 *TXBufferCurrentPositionHandler = *RXBufferCurrentPosition;
297 RXBufferCurrentPosition++;
298 TXBufferCurrentPositionHandler++;
299 RXCalculatedPayloadLength--;
300 *TXHeaderFlags |= HEADER_HAS_SEQUENCE;
303 if(RXHeaderFlags & HEADER_HAS_LENGTH){
304 RXHeaderPayloadLength = *((unsigned short*)RXBufferCurrentPosition);
305 RXBufferCurrentPosition += 2;
306 RXCalculatedPayloadLength -= 2;
307 /* Already subtracted one for checksum */
308 if(RXHeaderPayloadLength != RXCalculatedPayloadLength){
309 finaliseAndSend(payloadLengthHeaderMismatch);
310 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
311 return;
315 /* Calculate the position of the end of the stored packet for later use as a buffer */
316 void* leftOverBuffer = (void*)((unsigned short)&RXBuffer + RXPacketLengthReceived);
318 unsigned short errorID = 0;
319 /* This is where all the communication logic resides.
321 * Please Note: Length and its flag should be set by each return packet
322 * type handler if required or desired. If an ack has been requested,
323 * ensure the negative ack flag is set if the operation failed.
325 switch (RXHeaderPayloadID){
326 // FreeEMS Core Comms Interface cases
327 case requestInterfaceVersion:
329 if(RXCalculatedPayloadLength != 0){
330 errorID = payloadLengthTypeMismatch;
331 break;
334 /* This type must have a length field, set that up */
335 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(interfaceVersion);
336 *TXHeaderFlags |= HEADER_HAS_LENGTH;
337 TXBufferCurrentPositionHandler += 2;
338 /* Load the body into place */
339 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&interfaceVersion, sizeof(interfaceVersion));
340 TXBufferCurrentPositionHandler += sizeof(interfaceVersion);
341 break;
343 case requestFirmwareVersion:
345 if(RXCalculatedPayloadLength != 0){
346 errorID = payloadLengthTypeMismatch;
347 break;
349 /* This type must have a length field, set that up */
350 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(firmwareVersion);
351 *TXHeaderFlags |= HEADER_HAS_LENGTH;
352 TXBufferCurrentPositionHandler += 2;
353 /* Load the body into place */
354 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&firmwareVersion, sizeof(firmwareVersion));
355 TXBufferCurrentPositionHandler += sizeof(firmwareVersion);
356 break;
358 case requestMaxPacketSize:
360 if(RXCalculatedPayloadLength != 0){
361 errorID = payloadLengthTypeMismatch;
362 break;
364 /* Load the size into place */
365 *((unsigned short*)TXBufferCurrentPositionHandler) = RX_BUFFER_SIZE;
366 TXBufferCurrentPositionHandler += 2;
367 break;
369 case requestEchoPacketReturn:
371 /* This type must have a length field, set that up */
372 *((unsigned short*)TXBufferCurrentPositionHandler) = RXPacketLengthReceived;
373 *TXHeaderFlags |= HEADER_HAS_LENGTH;
374 TXBufferCurrentPositionHandler += 2;
375 /* Load the body into place */
376 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&RXBuffer, RXPacketLengthReceived);
377 /* Note, there is no overflow check here because the TX buffer is slightly */
378 /* bigger than the RX buffer and there is overflow checking for receives anyway. */
379 TXBufferCurrentPositionHandler += RXPacketLengthReceived;
380 break;
382 case requestSoftSystemReset:
384 if(RXCalculatedPayloadLength != 0){
385 errorID = payloadLengthTypeMismatch;
386 }else{ // Perform soft system reset
387 _start();
389 break;
391 case requestHardSystemReset:
393 if(RXCalculatedPayloadLength != 0){
394 errorID = payloadLengthTypeMismatch;
395 }else{
396 /* This is how the serial monitor does it. */
397 COPCTL = 0x01; /* Arm with shortest time */
398 ARMCOP = 0xFF; /* Write bad value, should cause immediate reset */
399 /* Using _start() only resets the app ignoring the monitor switch. It does not work */
400 /* properly because the location of _start is not the master reset vector location. */
402 break;
404 case requestReInitOfSystem:
406 if(RXCalculatedPayloadLength != 0){
407 errorID = payloadLengthTypeMismatch;
408 }else{
409 init();
411 break;
413 // FreeEMS Vanilla Firmware Specific cases
414 case clearCountersAndFlagsToZero:
416 if(RXCalculatedPayloadLength != 0){
417 errorID = payloadLengthTypeMismatch;
418 break;
421 unsigned short zeroCounter;
422 unsigned char* counterPointer;
424 counterPointer = (unsigned char*) &Counters;
425 for(zeroCounter = 0;zeroCounter < sizeof(Counter);zeroCounter++){
426 *counterPointer = 0;
427 counterPointer++;
430 KeyUserDebugs.flaggableFlags = 0;
431 counterPointer = (unsigned char*) &Flaggables;
432 for(zeroCounter = 0;zeroCounter < sizeof(Flaggable);zeroCounter++){
433 *counterPointer = 0;
434 counterPointer++;
437 KeyUserDebugs.flaggableFlags2 = 0;
438 counterPointer = (unsigned char*) &Flaggables2;
439 for(zeroCounter = 0;zeroCounter < sizeof(Flaggable2);zeroCounter++){
440 *counterPointer = 0;
441 counterPointer++;
443 break;
445 case requestDecoderName:
446 case requestFirmwareBuildDate:
447 case requestCompilerVersion:
448 case requestOperatingSystem:
450 if(RXCalculatedPayloadLength != 0){
451 errorID = payloadLengthTypeMismatch;
452 break;
455 unsigned char* stringToSend = 0;
456 switch (RXHeaderPayloadID) {
457 case requestDecoderName:
458 stringToSend = (unsigned char*)decoderName;
459 break;
460 case requestFirmwareBuildDate:
461 stringToSend = (unsigned char*)buildTimeAndDate;
462 break;
463 case requestCompilerVersion:
464 stringToSend = (unsigned char*)compilerVersion;
465 break;
466 case requestOperatingSystem:
467 stringToSend = (unsigned char*)operatingSystem;
468 break;
470 /* This type must have a length field, set that up and load the body into place at the same time */
471 *((unsigned short*)TXBufferCurrentPositionHandler) = stringCopy((TXBufferCurrentPositionHandler + 2), stringToSend);
472 *TXHeaderFlags |= HEADER_HAS_LENGTH;
473 // Update with length field and string length.
474 TXBufferCurrentPositionHandler += 2 + *((unsigned short*)TXBufferCurrentPositionHandler);
475 break;
477 case updateBlockInRAM:
479 // Subtract six to allow for the locationID, size, offset
480 if(RXCalculatedPayloadLength < 7){
481 errorID = payloadLengthTypeMismatch;
482 break;
485 // Extract the RAM location ID
486 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
487 RXBufferCurrentPosition += 2;
489 // Extract the offset to place the data at
490 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
491 RXBufferCurrentPosition += 2;
493 // Extract the size of the data to be stored
494 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
495 RXBufferCurrentPosition += 2;
497 // Look up the memory location details
498 blockDetails details;
499 lookupBlockDetails(locationID, &details);
501 // Don't let anyone write to running variables unless we are running BenchTest firmware!
502 if((details.flags & block_is_read_only) && compare((unsigned char*)&decoderName, (unsigned char*)BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME))){
503 errorID = attemptToWriteToReadOnlyBlock;
504 break;
507 // Subtract six to allow for the locationID, size, offset
508 if((RXCalculatedPayloadLength - 6) != size){
509 errorID = payloadNotEqualToSpecifiedValue;
510 break;
513 // If either of these is zero then this block is not in RAM!
514 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
515 errorID = invalidMemoryActionForID;
516 break;
519 // Check that size and offset describe a region that is not out of bounds
520 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
521 errorID = invalidSizeOffsetCombination;
522 break;
525 // Don't allow sub region manipulation where it does not make sense or is unsafe.
526 if((size != details.size) && !(details.flags & block_is_indexable)){
527 errorID = uncheckedTableManipulationNotAllowed;
528 break;
531 // Save page values for restore
532 unsigned char oldRamPage = RPAGE;
533 // Set the viewable RAM page
534 RPAGE = details.RAMPage;
536 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
538 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
539 void* bufferToCheck;
541 // For sub regions, construct an image for verification
542 if(size != details.size){
543 // Copy data from destination location to buffer
544 memcpy(leftOverBuffer, details.RAMAddress, details.size);
546 // Copy data from rx buffer to buffer over writing old data
547 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
549 bufferToCheck = leftOverBuffer;
550 }else{
551 bufferToCheck = RXBufferCurrentPosition;
554 // Verify all tables
555 if(details.flags & block_is_main_table){
556 errorID = validateMainTable((mainTable*)bufferToCheck);
557 }else if(details.flags & block_is_2dus_table){
558 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
559 }// TODO add other table types here
561 // If the validation failed, report it
562 if(errorID != 0){
563 RPAGE = oldRamPage; // Restore the original RAM page, even when getting an error condition.
564 break;
568 // Copy from the RX buffer to the block of RAM
569 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
571 // Check that the write was successful
572 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
574 // Restore the original RAM and flash pages
575 RPAGE = oldRamPage;
577 if(index != 0){
578 errorID = MEMORY_WRITE_ERROR;
580 break;
582 case updateBlockInFlash:
584 // Subtract six to allow for the locationID, size, offset
585 if(RXCalculatedPayloadLength < 7){
586 errorID = payloadLengthTypeMismatch;
587 break;
590 // Extract the RAM location ID
591 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
592 RXBufferCurrentPosition += 2;
594 // Extract the offset to place the data at
595 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
596 RXBufferCurrentPosition += 2;
598 // Extract the size of the data to be stored
599 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
600 RXBufferCurrentPosition += 2;
602 // Look up the memory location details
603 blockDetails details;
604 lookupBlockDetails(locationID, &details);
606 // Subtract six to allow for the locationID, size, offset
607 if((RXCalculatedPayloadLength - 6) != size){
608 errorID = payloadNotEqualToSpecifiedValue;
609 break;
612 // If either of these is zero then this block is not in flash!
613 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
614 errorID = invalidMemoryActionForID;
615 break;
618 // Check that size and offset describe a region that is not out of bounds
619 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
620 errorID = invalidSizeOffsetCombination;
621 break;
624 // Don't allow sub region manipulation where it does not make sense or is unsafe.
625 if((size != details.size) && !(details.flags & block_is_indexable)){
626 errorID = uncheckedTableManipulationNotAllowed;
627 break;
630 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
632 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
633 void* bufferToCheck;
635 // For sub regions, construct an image for verification
636 if(size != details.size){
637 /* Save page value for restore and set the visible page */
638 unsigned char oldFlashPage = PPAGE;
639 PPAGE = details.FlashPage;
641 // Copy data from destination location to buffer
642 memcpy(leftOverBuffer, details.FlashAddress, details.size);
644 /* Restore the original flash page */
645 PPAGE = oldFlashPage;
647 // Copy data from rx buffer to buffer over writing old data
648 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
650 bufferToCheck = leftOverBuffer;
651 }else{
652 bufferToCheck = RXBufferCurrentPosition;
655 // Verify all tables
656 if(details.flags & block_is_main_table){
657 errorID = validateMainTable((mainTable*)bufferToCheck);
658 }else if(details.flags & block_is_2dus_table){
659 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
660 }// TODO add other table types here
662 // If the validation failed, report it
663 if(errorID != 0){
664 break;
668 /* Copy the flash details and populate the RAM details with the buffer location */
669 blockDetails burnDetails;
670 burnDetails.FlashPage = details.FlashPage;
671 burnDetails.FlashAddress = details.FlashAddress + offset;
672 burnDetails.RAMPage = RPAGE;
673 burnDetails.RAMAddress = RXBufferCurrentPosition;
674 burnDetails.size = size;
676 /* Copy from the RX buffer to the block of flash */
677 errorID = writeBlock(&burnDetails, leftOverBuffer);
678 if(errorID != 0){
679 break;
682 /* If present in RAM, update that too */
683 if((details.RAMPage != 0) && (details.RAMAddress != 0)){
684 /* Save page values for restore */
685 unsigned char oldRamPage = RPAGE;
686 /* Set the viewable RAM page */
687 RPAGE = details.RAMPage;
689 /* Copy from the RX buffer to the block of RAM */
690 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
692 /* Check that the write was successful */
693 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
695 /* Restore the original RAM and flash pages */
696 RPAGE = oldRamPage;
698 if(index != 0){
699 errorID = MEMORY_WRITE_ERROR;
703 break;
705 case retrieveBlockFromRAM:
707 if(RXCalculatedPayloadLength != 6){
708 errorID = payloadLengthTypeMismatch;
709 break;
712 // Extract the RAM location ID
713 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
714 RXBufferCurrentPosition += 2;
716 // Extract the offset to place the data at
717 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
718 RXBufferCurrentPosition += 2;
720 // Extract the size of the data to be stored
721 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
722 RXBufferCurrentPosition += 2;
724 /* Look up the memory location details */
725 blockDetails details;
726 lookupBlockDetails(locationID, &details);
728 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
729 errorID = invalidMemoryActionForID;
730 break;
733 // Special behaviour for size of zero which returns the whole block
734 if((size == 0) && (offset == 0)){
735 size = details.size;
738 // Check that size and offset describe a region that is not out of bounds
739 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
740 errorID = invalidSizeOffsetCombination;
741 break;
744 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
745 if((size != details.size) && !(details.flags & block_is_indexable)){
746 errorID = doesNotMakeSenseToRetrievePartially;
747 break;
750 // This type must have a length field, set that up
751 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
752 *TXHeaderFlags |= HEADER_HAS_LENGTH;
753 TXBufferCurrentPositionHandler += 2;
755 /* Save page value for restore and set the visible page */
756 unsigned char oldRamPage = RPAGE;
757 RPAGE = details.RAMPage;
759 /* Copy the block of RAM to the TX buffer */
760 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.RAMAddress + offset), size);
761 TXBufferCurrentPositionHandler += size;
763 /* Restore the original RAM and flash pages */
764 RPAGE = oldRamPage;
766 break;
768 case retrieveBlockFromFlash:
770 if(RXCalculatedPayloadLength != 6){
771 errorID = payloadLengthTypeMismatch;
772 break;
775 // Extract the RAM location ID
776 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
777 RXBufferCurrentPosition += 2;
779 // Extract the offset to place the data at
780 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
781 RXBufferCurrentPosition += 2;
783 // Extract the size of the data to be stored
784 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
785 RXBufferCurrentPosition += 2;
787 /* Look up the memory location details */
788 blockDetails details;
789 lookupBlockDetails(locationID, &details);
791 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
792 errorID = invalidMemoryActionForID;
793 break;
796 // Special behaviour for size of zero which returns the whole block
797 if((size == 0) && (offset == 0)){
798 size = details.size;
801 // Check that size and offset describe a region that is not out of bounds
802 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
803 errorID = invalidSizeOffsetCombination;
804 break;
807 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
808 if((size != details.size) && !(details.flags & block_is_indexable)){
809 errorID = doesNotMakeSenseToRetrievePartially;
810 break;
813 // This type must have a length field, set that up
814 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
815 *TXHeaderFlags |= HEADER_HAS_LENGTH;
816 TXBufferCurrentPositionHandler += 2;
818 /* Save page value for restore and set the visible page */
819 unsigned char oldFlashPage = PPAGE;
820 PPAGE = details.FlashPage;
822 /* Copy the block of flash to the TX buffer */
823 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.FlashAddress + offset), size);
824 TXBufferCurrentPositionHandler += size;
826 /* Restore the original RAM and flash pages */
827 PPAGE = oldFlashPage;
829 break;
831 case burnBlockFromRamToFlash:
833 if(RXCalculatedPayloadLength != 6){
834 errorID = payloadLengthTypeMismatch;
835 break;
838 // Extract the RAM location ID
839 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
840 RXBufferCurrentPosition += 2;
842 // Extract the offset to place the data at
843 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
844 RXBufferCurrentPosition += 2;
846 // Extract the size of the data to be stored
847 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
848 RXBufferCurrentPosition += 2;
850 /* Look up the memory location details */
851 blockDetails details;
852 lookupBlockDetails(locationID, &details);
854 /* Check that all data we need is present */
855 if((details.RAMPage == 0) || (details.RAMAddress == 0) || (details.FlashPage == 0) || (details.FlashAddress == 0)){
856 errorID = invalidMemoryActionForID;
857 break;
860 // Special behaviour for size of zero which burns the whole block
861 if((size == 0) && (offset == 0)){
862 size = details.size;
865 // Check that size and offset describe a region that is not out of bounds
866 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
867 errorID = invalidSizeOffsetCombination;
868 break;
871 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
872 if((size != details.size) && !(details.flags & block_is_indexable)){
873 errorID = doesNotMakeSenseToRetrievePartially;
874 break;
878 // adjust details block to feed to represent the subsection of ram and flash that we want to burn down.
879 details.RAMAddress += offset;
880 details.FlashAddress += offset;
881 details.size = size;
883 /* Write the block down from RAM to Flash */
884 errorID = writeBlock(&details, leftOverBuffer);
885 break;
887 case requestDatalogPacket: // Set type through standard configuration methods
889 if(RXCalculatedPayloadLength != 0){
890 errorID = payloadLengthTypeMismatch;
891 break;
894 /* Set the length field up */
895 *TXHeaderFlags |= HEADER_HAS_LENGTH;
896 unsigned short* localLength = (unsigned short*)TXBufferCurrentPositionHandler;
897 TXBufferCurrentPositionHandler += 2;
899 /* Fill out the log and send */
900 *localLength = populateBasicDatalog();
901 break;
903 case setAsyncDatalogType:
905 if(RXCalculatedPayloadLength != 1){
906 errorID = payloadLengthTypeMismatch;
907 break;
910 unsigned char newDatalogType = *((unsigned char*)RXBufferCurrentPosition);
911 if(newDatalogType > asyncDatalogLastType){
912 errorID = noSuchAsyncDatalogType;
913 break;
916 TablesB.SmallTablesB.loggingSettings.datalogStreamType = newDatalogType;
917 break;
919 case retrieveArbitraryMemory:
921 if(RXCalculatedPayloadLength != 6){
922 errorID = payloadLengthTypeMismatch;
923 break;
926 unsigned short length = *((unsigned short*)RXBufferCurrentPosition);
927 RXBufferCurrentPosition += 2;
928 // Make sure the buffer can handle the block
929 if(length > TX_MAX_PAYLOAD_SIZE){
930 errorID = requestedLengthTooLarge;
931 break;
934 void* address = (void*) *((unsigned short*)RXBufferCurrentPosition);
935 RXBufferCurrentPosition += 2;
936 // Ensure we don't try to read past the end of the address space
937 if(((unsigned short)address) <= ((0xFFFF - length) + 1)){
938 // TODO Possibly check and limit ranges
939 errorID = requestedAddressDisallowed;
940 break;
943 unsigned char RAMPage = *((unsigned char*)RXBufferCurrentPosition);
944 RXBufferCurrentPosition++;
945 // Ensure RAM page is valid. Being too high is not possible.
946 if(RAMPage < RPAGE_MIN){
947 errorID = requestedRAMPageInvalid;
948 break;
951 unsigned char FlashPage = *((unsigned char*)RXBufferCurrentPosition);
952 RXBufferCurrentPosition++;
953 // Ensure Flash page is valid. Being too high is not possible.
954 if(FlashPage < PPAGE_MIN){
955 errorID = requestedFlashPageInvalid;
956 break;
959 /* This type must have a length field, set that up */
960 *((unsigned short*)TXBufferCurrentPositionHandler) = length + 6;
961 *TXHeaderFlags |= HEADER_HAS_LENGTH;
962 TXBufferCurrentPositionHandler += 2;
964 /* Put the request payload into the reply */
965 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short) address;
966 TXBufferCurrentPositionHandler += 2;
967 *((unsigned short*)TXBufferCurrentPositionHandler) = length;
968 TXBufferCurrentPositionHandler += 2;
969 *((unsigned char*)TXBufferCurrentPositionHandler) = RAMPage;
970 TXBufferCurrentPositionHandler++;
971 *((unsigned char*)TXBufferCurrentPositionHandler) = FlashPage;
972 TXBufferCurrentPositionHandler++;
974 /* Load the body into place */
975 memcpy((void*)TXBufferCurrentPositionHandler, address, length);
976 TXBufferCurrentPositionHandler += length;
978 break;
980 case retrieveListOfLocationIDs:
982 if(RXCalculatedPayloadLength != 3){
983 errorID = payloadLengthTypeMismatch;
984 break;
987 // Extract the type of list that we want
988 unsigned char listType = *((unsigned char*)RXBufferCurrentPosition);
989 RXBufferCurrentPosition++;
991 // Extract the mask for the qualities that we want
992 unsigned short blockDetailsMask = *((unsigned short*)RXBufferCurrentPosition);
993 RXBufferCurrentPosition += 2;
995 // This type must have a length field, set that up
996 unsigned short * listLength = (unsigned short*)TXBufferCurrentPositionHandler;
997 *TXHeaderFlags |= HEADER_HAS_LENGTH;
998 TXBufferCurrentPositionHandler += 2;
1000 // Zero the counter before we start, woops!
1001 *listLength = 0;
1003 unsigned long locationID;
1004 blockDetails details;
1005 for(locationID = 0;locationID < 65536;locationID++){
1006 unsigned short locationIDDoesntExist;
1007 locationIDDoesntExist = lookupBlockDetails((unsigned short)locationID, &details);
1009 if(!locationIDDoesntExist){
1010 if((listType == 0x00) || // get all
1011 ((listType == 0x01) && (details.flags & blockDetailsMask)) || // get OR of bits
1012 ((listType == 0x02) && (!(~(details.flags) & blockDetailsMask)))){ // get AND of bits
1013 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short)locationID;
1014 TXBufferCurrentPositionHandler += 2;
1015 *listLength += 2;
1020 break;
1022 case retrieveLocationIDDetails:
1024 if(RXCalculatedPayloadLength != 2){
1025 errorID = payloadLengthTypeMismatch;
1026 break;
1029 // Extract the RAM location ID
1030 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
1031 RXBufferCurrentPosition += 2;
1033 // This type must have a length field, set that up
1034 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(blockDetails);
1035 *TXHeaderFlags |= HEADER_HAS_LENGTH;
1036 TXBufferCurrentPositionHandler += 2;
1038 // Write straight to output buffer to save time/code
1039 errorID = lookupBlockDetails(locationID, (blockDetails*)TXBufferCurrentPositionHandler);
1041 if(errorID != 0){
1042 break;
1045 // Adjust TX buffer position if successful
1046 TXBufferCurrentPositionHandler += sizeof(blockDetails);
1048 break;
1050 case requestUnitTestOverSerial:
1053 * The idea here is to call this function with arguments, and data
1054 * and have the result sent back for comparison with an expected
1055 * result that isn't divulged to the firmware.
1057 * It is intended that all testable functions be callable through
1058 * this mechanism and that any number of test executions can be
1059 * performed by an external suite using different parameters and
1060 * data sets and matching expected results.
1062 * The usual error mechanism shall be used to indicate some sort of
1063 * either internal or test failure and returned errors shall be
1064 * suitably descriptive to allow diagnosis and fixing of issues.
1067 // Must at least have test ID
1068 if(RXCalculatedPayloadLength < 2){
1069 errorID = payloadLengthTypeMismatch;
1070 break;
1073 // grab unit test ID from payload
1074 unsigned short unitTestID = *((unsigned short*)RXBufferCurrentPosition);
1075 RXBufferCurrentPosition += 2;
1077 switch(unitTestID){
1078 case testEmptyTest:
1080 // Must be only the ID
1081 if(RXCalculatedPayloadLength != 2){
1082 errorID = payloadShorterThanRequiredForTest;
1083 break;
1086 *((unsigned short*)TXBufferCurrentPositionHandler) = unitTestID;
1087 TXBufferCurrentPositionHandler +=2;
1089 break;
1091 case testTwoDTableUSLookup:
1093 // ID + Value + Table
1094 if(RXCalculatedPayloadLength != (2 + 2 + sizeof(twoDTableUS))){
1095 errorID = payloadShorterThanRequiredForTest;
1096 break;
1099 unsigned short Value = *((unsigned short*)RXBufferCurrentPosition);
1100 RXBufferCurrentPosition += 2;
1102 twoDTableUS* Table = ((twoDTableUS*)RXBufferCurrentPosition);
1103 RXBufferCurrentPosition += sizeof(twoDTableUS);
1105 unsigned short result = lookupTwoDTableUS(Table, Value);
1107 *((unsigned short*)TXBufferCurrentPositionHandler) = result;
1108 TXBufferCurrentPositionHandler +=2;
1110 break;
1112 // http://issues.freeems.org/view.php?id=156
1114 /// TODO @todo test all things listed below:
1115 // lookupPagedMainTableCellValue - pass this RPAGE so that it remains unchanged
1116 // validateMainTable
1117 // validateTwoDTable
1118 // set table values - leave this till last, currently unused by mtx, likely to be removed anyway
1119 // generateDerivedVars - convert to pointers, remove headers, privatise a lot of data!
1120 // calculateFuelAndIgnition - ditto
1121 // scheduling algorithm - ditto
1122 // safeAdd
1123 // safeTrim
1124 // safeScale
1125 // sleep (milliseconds)
1126 // sleepMicro (microseconds)
1127 // checksum
1128 // stringCopy
1129 // compare
1130 // utils that can't be checked: sampleLoopADC sampleBlockADC sampleEachADC - can check for how long each takes! adjustPWM (test only anyway), resetToNonRunningState and setupPagedRAM (would interfere with functioning of device)
1131 // init code may be able to be partially checked
1132 // most other code at this stage is ISR code, flash writing code, or could interfere with the running of the engine
1133 // more testable code will appear with time, such as the HAL layer, and most accessory functions.
1134 default:
1136 errorID = noSuchUnitTestID;
1139 // each case:
1140 // checks length, fails if wrong
1141 // parses data into args
1142 // calls function on data/args
1143 // assembles response OR sets error
1144 // breaks
1146 break;
1148 case startBenchTestSequence:
1150 // see TODO on include at top and modify this line appropriately
1151 if(!(compare((unsigned char*)&decoderName, (unsigned char*)BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME)))){
1152 if(RXCalculatedPayloadLength < 1){
1153 errorID = payloadLengthTypeMismatch;
1154 break;
1157 unsigned char localTestMode = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1158 RXBufferCurrentPosition++;
1159 if(localTestMode > TEST_MODE_BUMP_UP_CYCLES){
1160 errorID = unimplementedTestMode;
1161 break;
1162 }else if((localTestMode == TEST_MODE_STOP) && (RXCalculatedPayloadLength == 1)){
1163 if(!(coreStatusA & BENCH_TEST_ON)){
1164 errorID = benchTestNotRunningToStop;
1165 break;
1168 // Ensure we succeed at stopping it as quickly as possible.
1169 ATOMIC_START();
1170 KeyUserDebugs.currentEvent = testEventsPerCycle - 1; // Gets incremented then compared with testEventsPerCycle
1171 testNumberOfCycles = 1; // Gets decremented then compared with zero
1172 ATOMIC_END();
1174 // eventually save and return where it got to
1175 break;
1176 }else if((localTestMode == TEST_MODE_BUMP_UP_CYCLES) && (RXCalculatedPayloadLength == 2)){
1177 if(!(coreStatusA & BENCH_TEST_ON)){
1178 errorID = benchTestNotRunningToBump;
1179 break;
1182 // Get bump value from payload
1183 unsigned char bumpCycles = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1184 RXBufferCurrentPosition++;
1186 if(bumpCycles == 0){
1187 errorID = bumpingByZeroMakesNoSense;
1188 break;
1191 // Bump count by value from payload
1192 testNumberOfCycles += bumpCycles;
1193 // Given that this function is only for situations when A it's getting near to
1194 // zero and B the user is watching, not checking for overflow is reasonable.
1195 break;
1196 }else if((localTestMode == TEST_MODE_ITERATIONS) && (RXCalculatedPayloadLength == 24)){
1197 testMode = localTestMode;
1198 // do nothing to fall through, or move other code into here
1199 }else{
1200 errorID = packetSizeWrongForTestMode;
1201 break;
1204 if(coreStatusA & BENCH_TEST_ON){
1205 errorID = benchTestAlreadyRunning;
1206 break;
1209 testEventsPerCycle = *((unsigned char*)RXBufferCurrentPosition); //100; // @ 10ms = 1s
1210 RXBufferCurrentPosition++;
1211 if(testEventsPerCycle == 0){
1212 errorID = invalidEventsPerCycle;
1213 break;
1216 testNumberOfCycles = *((unsigned short*)RXBufferCurrentPosition); //20; // @ 1s = 20s
1217 RXBufferCurrentPosition += 2;
1218 if(testNumberOfCycles == 0){
1219 errorID = invalidNumberOfCycles;
1220 break;
1223 testTicksPerEvent = *((unsigned short*)RXBufferCurrentPosition); //12500; // @ 0.8us = 10ms
1224 RXBufferCurrentPosition += 2;
1225 if(testTicksPerEvent < decoderMaxCodeTime){
1226 errorID = tooShortOfAnEventPeriod;
1227 break;
1230 // Pluck the arrays out of the packet for the loop below
1231 unsigned char* testEventNumbers = RXBufferCurrentPosition;
1232 RXBufferCurrentPosition += 6;
1233 unsigned short* testPulseWidths = (unsigned short*)RXBufferCurrentPosition;
1234 RXBufferCurrentPosition += 12;
1236 // Reset the clock for reading timeout
1237 Clocks.timeoutADCreadingClock = 0; // make this optional, such that we can use real inputs to determine pw and/or dwell.
1239 // Validate and transfer the per-channel data
1240 unsigned char channel;
1241 unsigned char configuredChannels = 6;
1242 for(channel = 0;channel < 6;channel++){
1243 if(testPulseWidths[channel] > injectorSwitchOnCodeTime){ // See next block for warning.
1244 // use as-is
1245 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1246 outputEventPulseWidthsMath[channel] = testPulseWidths[channel];
1247 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1248 }else if(testPulseWidths[channel] > 3){
1249 // less than the code time, and not special, error!
1250 errorID = tooShortOfAPulseWidthToTest;
1251 // Warning, PWs close to this could be slightly longer than requested, that will change in later revisions.
1252 break;
1253 }else if(testPulseWidths[channel] == 3){
1254 testMode++; // Dirty hack to avoid dealing with Dave for the time being.
1255 testNumberOfMissing = channel;
1256 }else if(testPulseWidths[channel] == 2){
1257 // use the dwell from the core maths and input vars.
1258 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1259 outputEventPulseWidthsMath[channel] = DerivedVars->Dwell;
1260 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1261 }else if(testPulseWidths[channel] == 1){
1262 // use the reference pulse width from the core maths and input vars.
1263 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1264 outputEventPulseWidthsMath[channel] = DerivedVars->RefPW;
1265 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1266 }else{ // is zero
1267 // Set this channel to zero for and therefore off, don't set this channel.
1268 outputEventInputEventNumbers[channel] = 0xFF; // Off.
1269 configuredChannels--;
1273 if(configuredChannels == 0){
1274 errorID = noChannelsConfiguredToTest;
1275 break;
1278 if(errorID == 0){
1279 // Let the first iteration roll it over to zero.
1280 KeyUserDebugs.currentEvent = 0xFF; // Needs to be here in case of multiple runs, init is not sufficient
1282 if(testMode == TEST_MODE_DODGY_MISSING_TOOTH){
1283 if(testEventsPerCycle <= 127){
1284 testEventsPerCycle *= 2;
1285 }else{
1286 errorID = tooManyEventsPerCycleMissingTth;
1287 break;
1290 // Store the time per event in RPM such that it can be updated dynamically
1291 CoreVars->RPM = testTicksPerEvent;
1293 // The channels to use rely on the defaults from initialisers! Custom builds can break BenchTest mode!
1295 // Un-schedule anything that got scheduled
1296 outputEventInputEventNumbers[2] = 0xFF;
1297 outputEventInputEventNumbers[3] = 0xFF;
1298 outputEventInputEventNumbers[4] = 0xFF;
1299 outputEventInputEventNumbers[5] = 0xFF;
1300 }else if(testMode > TEST_MODE_DODGY_MISSING_TOOTH){
1301 errorID = unimplementedTestMode;
1302 break;
1305 // Trigger decoder interrupt to fire thus starting the loop!
1306 TIE = 0x01; // The ISR does the rest!
1308 // Nothing went wrong, now set flag.
1309 coreStatusA |= BENCH_TEST_ON;
1310 }else{
1311 break;
1315 /* http://issues.freeems.org/view.php?id=155
1317 * The following block has been left in, as I still do not know why it won't work as intended:
1319 * - It should fire all 6 output pins with a 52ms duration pulse, exactly once.
1320 * - The SAME code run from anywhere else (pre main loop, in main loop, in rtc, in decoder) works fine, just not here in commsCore.c
1321 * - The interrupts run, but the pin doesn't change state, despite the registers being configured correctly
1323 * I've tried quite a bit:
1325 * - Moving this code around
1326 * - Checking memory definitions
1327 * - Completely rewriting the output ISR
1328 * - Adding significant debug to output ISR
1329 * - Checking for register contents in output ISR
1330 * - Checking for key things modified in this file
1331 * - General head scratching and confused searching
1334 // outputEventPinNumbers[0] = 0; // 1 ign
1335 // outputEventPinNumbers[1] = 1; // 2 ign
1336 // outputEventPinNumbers[2] = 2; // 3 ign/1 fuel
1337 // outputEventPinNumbers[3] = 3; // 4 ign/2 fuel
1338 // outputEventPinNumbers[4] = 4; // 3 fuel
1339 // outputEventPinNumbers[5] = 5; // 4 fuel
1340 // outputEventDelayFinalPeriod[0] = decoderMaxCodeTime;
1341 // outputEventDelayFinalPeriod[1] = decoderMaxCodeTime;
1342 // outputEventDelayFinalPeriod[2] = decoderMaxCodeTime;
1343 // outputEventDelayFinalPeriod[3] = decoderMaxCodeTime;
1344 // outputEventDelayFinalPeriod[4] = decoderMaxCodeTime;
1345 // outputEventDelayFinalPeriod[5] = decoderMaxCodeTime;
1346 // outputEventPulseWidthsMath[0] = SHORTMAX;
1347 // outputEventPulseWidthsMath[1] = SHORTMAX;
1348 // outputEventPulseWidthsMath[2] = SHORTMAX;
1349 // outputEventPulseWidthsMath[3] = SHORTMAX;
1350 // outputEventPulseWidthsMath[4] = SHORTMAX;
1351 // outputEventPulseWidthsMath[5] = SHORTMAX;
1353 // unsigned short edgeTimeStamp = TCNT;
1354 // // call sched output with args
1355 // LongTime timeStamp;
1356 // /* Install the low word */
1357 // timeStamp.timeShorts[1] = edgeTimeStamp;
1358 // /* Find out what our timer value means and put it in the high word */
1359 // if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
1360 // timeStamp.timeShorts[0] = timerExtensionClock + 1;
1361 // }else{
1362 // timeStamp.timeShorts[0] = timerExtensionClock;
1363 // }
1365 // schedulePortTPin(0, timeStamp);
1366 // schedulePortTPin(1, timeStamp);
1367 // schedulePortTPin(2, timeStamp);
1368 // schedulePortTPin(3, timeStamp);
1369 // schedulePortTPin(4, timeStamp);
1370 // schedulePortTPin(5, timeStamp);
1372 // sleep(1000);
1373 }else{
1374 errorID = thisIsNotTheBenchTestDecoder;
1376 break;
1378 default:
1380 if((RXHeaderPayloadID % 2) == 1){
1381 errorID = invalidPayloadID;
1382 }else{
1383 errorID = unrecognisedPayloadID;
1385 break;
1389 // Always reply, if errorID is zero it's just an ack.
1390 finaliseAndSend(errorID);
1392 /* Switch reception back on now that we are done with the received data */
1393 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
1397 /* This function should be period limited to about 10 seconds internally (or by scheduler) */
1398 //void checkCountersAndSendErrors(){
1399 // compare time stamps with current time stamps and execute if old enough. (if no scheduler)
1401 // compare counters with counters cache (from last time) sending an error packet when they differ
1403 // copy counters to counters cache for next time
1405 // send errors with busy wait on the basis that all errors should be taken care of and not be sent in fairly short order?
1407 // or send with isr but just busy wait for it to finish before sending the next?
1409 // debug messages, busy wait or isr or both, perhaps busy wait till able to send, lock sending (need semaphore for this as well as sending one?) and initiate send, then carry on? investigate timeframes for sends of smallish 100byte packets.
1411 // need to figure out how to queue received packets for processing when we are currently sending stuff out.
1413 // above notes don't belong here really.