Add in return of the number of cycles added when bumping a bench test.
[freeems-vanilla.git] / src / main / commsCore.c
blob3f18ad56dca2be43dba53abff87368e887c535e3
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 KeyUserDebugs.coreStatusA = coreStatusA;
67 KeyUserDebugs.clockIn8thsOfAMilli = Clocks.realTimeClockMain;
68 KeyUserDebugs.clockInMilliSeconds = Clocks.realTimeClockMillis;
70 unsigned short confSize = 0;
71 unsigned char chunkLimit = TablesB.SmallTablesB.loggingSettings.firstChunk + TablesB.SmallTablesB.loggingSettings.numberOfChunks;
72 unsigned char chunks;
73 for(chunks=TablesB.SmallTablesB.loggingSettings.firstChunk;chunks<chunkLimit;chunks++){
74 unsigned short localSize = TablesB.SmallTablesB.loggingSettings.logChunks[chunks].size;
75 confSize += localSize;
76 if(confSize > 2048){
77 confSize -= localSize;
78 break;
80 memcpy(TXBufferCurrentPositionHandler, TablesB.SmallTablesB.loggingSettings.logChunks[chunks].address, localSize);
81 TXBufferCurrentPositionHandler += localSize;
83 // After copying data, otherwise tempClock is NEVER zero and reset detection does NOT work
84 KeyUserDebugs.tempClock++;
85 return confSize;
89 // All of these require some range checking, eg only some registers, and all RAM, not flash, not other regs
90 // TODO pointer for one byte
91 // TODO pointer for one short
92 // TODO function to log generic memory region by location and size ? requires length!
93 // Ranges are :
94 // RAM window
95 // bss/data region
96 // IO registers etc that can't be altered simply by reading from.
97 // NOT :
98 // flash makes no sense
99 // some regs are sensitive
100 // some RAM is unused
101 // serial buffers make no sense
102 // eeprom makes no sense
104 // 2k of regs max - user beware for now
105 // 12k of RAM max
107 //init :
108 //logaddr = fixed.addr
109 //loglen = fixed.len
111 //len = loglen OR 1 OR 2
113 //check :
114 //if((addr < 0x0800) && (length < (0x0800 - addr))){
115 // // reg space is OK
116 //}else if(((0x1000 < addr) && (addr < 0x4000)) && (length < (0x4000 - addr))){
117 // // RAM space is OK
118 //}else{
119 // // send an error instead
122 //run check at init and set time, not run time or just not check?? maybe its silly to check at all
124 // /* Just dump the ADC channels as fast as possible */
125 //void populateScopeLogADCAll(){
126 // sampleBlockADC(TXBufferCurrentPositionHandler);
127 // TXBufferCurrentPositionHandler += sizeof(ADCBuffer);
131 // 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.
134 /** @brief Finalise a packet and send it
136 * This functions job is to finalise the main loop part of the packet sending
137 * process. It configures the pos/neg ack header bit, adds the code if neg,
138 * runs a checksum over the packet data and tags it to the end before
139 * configuring the various ISRs that need to send the data out.
141 * @bug http://issues.freeems.org/view.php?id=81
142 * @todo TODO fix the double/none start byte bug and remove the hack!
144 void finaliseAndSend(unsigned short errorID){
146 if(errorID != 0){
147 *TXHeaderFlags |= HEADER_IS_NACK;
148 *((unsigned short*)TXBufferCurrentPositionHandler) = errorID;
149 TXBufferCurrentPositionHandler += 2;
152 /* Tag the checksum on the end */
153 *TXBufferCurrentPositionHandler = checksum((unsigned char*)&TXBuffer, ((unsigned short)TXBufferCurrentPositionHandler - (unsigned short)&TXBuffer));
155 /* Send it out on all the channels required. */
157 /* SCI0 - Main serial interface */
158 if(TXBufferInUseFlags & COM_SET_SCI0_INTERFACE_ID){
159 /* Initiate transmission */
160 SCI0DRL = START_BYTE;
162 /* Note : Order Is Important! */
163 /* TX empty flag is already set, so we must clear it by writing out before enabling the interrupt */
164 SCI0CR2 |= (SCICR2_TX_ENABLE | SCICR2_TX_ISR_ENABLE);
166 /* CAN0 - Main CAN interface */
167 if(TXBufferInUseFlags & COM_SET_CAN0_INTERFACE_ID){
168 // just clear up front for now
169 TXBufferInUseFlags &= COM_CLEAR_CAN0_INTERFACE_ID;
171 /* spare2 */
172 if(TXBufferInUseFlags & COM_SET_SPARE2_INTERFACE_ID){
173 // just clear up front for now
174 TXBufferInUseFlags &= COM_CLEAR_SPARE2_INTERFACE_ID;
176 /* spare3 */
177 if(TXBufferInUseFlags & COM_SET_SPARE3_INTERFACE_ID){
178 // just clear up front for now
179 TXBufferInUseFlags &= COM_CLEAR_SPARE3_INTERFACE_ID;
181 /* spare4 */
182 if(TXBufferInUseFlags & COM_SET_SPARE4_INTERFACE_ID){
183 // just clear up front for now
184 TXBufferInUseFlags &= COM_CLEAR_SPARE4_INTERFACE_ID;
186 /* spare5 */
187 if(TXBufferInUseFlags & COM_SET_SPARE5_INTERFACE_ID){
188 // just clear up front for now
189 TXBufferInUseFlags &= COM_CLEAR_SPARE5_INTERFACE_ID;
191 /* spare6 */
192 if(TXBufferInUseFlags & COM_SET_SPARE6_INTERFACE_ID){
193 // just clear up front for now
194 TXBufferInUseFlags &= COM_CLEAR_SPARE6_INTERFACE_ID;
196 /* spare7 */
197 if(TXBufferInUseFlags & COM_SET_SPARE7_INTERFACE_ID){
198 // just clear up front for now
199 TXBufferInUseFlags &= COM_CLEAR_SPARE7_INTERFACE_ID;
204 /** @brief Decode a packet and respond
206 * This is the core function that controls which functionality is run when a
207 * packet is received in full by the ISR code and control is passed back to the
208 * main loop code. The vast majority of communications action happens here.
210 void decodePacketAndRespond(){
211 /* Extract and build up the header fields */
212 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
214 /* Initialised here such that override is possible */
215 TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer;
216 TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer;
218 // How big was the packet that we got back
219 unsigned short RXPacketLengthReceived = (unsigned short)RXBufferCurrentPosition - (unsigned short)&RXBuffer;
221 /* Check that the packet is big enough for header,ID,checksum */
222 if(RXPacketLengthReceived < 4){
223 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
224 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_PACKETS_UNDER_LENGTH_OFFSET);
225 KeyUserDebugs.serialAndCommsCodeErrors++;
226 return;
229 /* Pull out the received checksum and calculate the real one, then check */
230 unsigned char RXReceivedChecksum = (unsigned char)*(RXBufferCurrentPosition - 1);
231 unsigned char RXCalculatedChecksum = checksum((unsigned char*)&RXBuffer, RXPacketLengthReceived - 1);
232 if(RXCalculatedChecksum != RXReceivedChecksum){
233 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
234 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_CHECKSUM_MISMATCHES_OFFSET);
235 KeyUserDebugs.serialAndCommsCodeErrors++;
236 return;
239 /* Start this off as full packet length and build down to the actual length */
240 RXCalculatedPayloadLength = RXPacketLengthReceived;
242 /* Grab the RX header flags out of the RX buffer */
243 RXBufferCurrentPosition = (unsigned char*)&RXBuffer;
244 RXHeaderFlags = *RXBufferCurrentPosition;
245 RXBufferCurrentPosition++;
246 RXCalculatedPayloadLength--;
248 /* Flag that we are transmitting! */
249 TXBufferInUseFlags |= COM_SET_SCI0_INTERFACE_ID;
250 // SCI0 only for now...
252 /* Load a blank header into the TX buffer ready for masking */
253 TXHeaderFlags = TXBufferCurrentPositionHandler;
254 *TXHeaderFlags = 0;
255 TXBufferCurrentPositionHandler++;
257 /* Grab the payload ID for processing and load the return ID */
258 RXHeaderPayloadID = *((unsigned short*)RXBufferCurrentPosition);
259 *((unsigned short*)TXBufferCurrentPositionHandler) = RXHeaderPayloadID + 1;
260 RXBufferCurrentPosition += 2;
261 TXBufferCurrentPositionHandler += 2;
262 RXCalculatedPayloadLength -= 2;
264 /* Check that the length is sufficient for the fields configured. Packets
265 * that are too long will be caught and rejected on an individual payload
266 * ID basis as the information required to handle that is not available at
267 * this point. Packets that are too short are rejected immediately!
269 if(((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 7))
270 || ((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXPacketLengthReceived < 6))
271 || ((RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 5))){
272 finaliseAndSend(packetTooShortForSpecifiedFields);
273 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
274 return;
277 /* Subtract checksum to get final length */
278 RXCalculatedPayloadLength--;
280 if(RXHeaderFlags & HEADER_HAS_SEQUENCE){
281 *TXBufferCurrentPositionHandler = *RXBufferCurrentPosition;
282 RXBufferCurrentPosition++;
283 TXBufferCurrentPositionHandler++;
284 RXCalculatedPayloadLength--;
285 *TXHeaderFlags |= HEADER_HAS_SEQUENCE;
288 if(RXHeaderFlags & HEADER_HAS_LENGTH){
289 RXHeaderPayloadLength = *((unsigned short*)RXBufferCurrentPosition);
290 RXBufferCurrentPosition += 2;
291 RXCalculatedPayloadLength -= 2;
292 /* Already subtracted one for checksum */
293 if(RXHeaderPayloadLength != RXCalculatedPayloadLength){
294 finaliseAndSend(payloadLengthHeaderMismatch);
295 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
296 return;
300 /* Calculate the position of the end of the stored packet for later use as a buffer */
301 void* leftOverBuffer = (void*)((unsigned short)&RXBuffer + RXPacketLengthReceived);
303 unsigned short errorID = 0;
304 /* This is where all the communication logic resides.
306 * Please Note: Length and its flag should be set by each return packet
307 * type handler if required or desired. If an ack has been requested,
308 * ensure the negative ack flag is set if the operation failed.
310 switch (RXHeaderPayloadID){
311 // FreeEMS Core Comms Interface cases
312 case requestInterfaceVersion:
314 if(RXCalculatedPayloadLength != 0){
315 errorID = payloadLengthTypeMismatch;
316 break;
319 /* This type must have a length field, set that up */
320 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(interfaceVersion);
321 *TXHeaderFlags |= HEADER_HAS_LENGTH;
322 TXBufferCurrentPositionHandler += 2;
323 /* Load the body into place */
324 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&interfaceVersion, sizeof(interfaceVersion));
325 TXBufferCurrentPositionHandler += sizeof(interfaceVersion);
326 break;
328 case requestFirmwareVersion:
330 if(RXCalculatedPayloadLength != 0){
331 errorID = payloadLengthTypeMismatch;
332 break;
334 /* This type must have a length field, set that up */
335 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(firmwareVersion);
336 *TXHeaderFlags |= HEADER_HAS_LENGTH;
337 TXBufferCurrentPositionHandler += 2;
338 /* Load the body into place */
339 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&firmwareVersion, sizeof(firmwareVersion));
340 TXBufferCurrentPositionHandler += sizeof(firmwareVersion);
341 break;
343 case requestMaxPacketSize:
345 if(RXCalculatedPayloadLength != 0){
346 errorID = payloadLengthTypeMismatch;
347 break;
349 /* Load the size into place */
350 *((unsigned short*)TXBufferCurrentPositionHandler) = RX_BUFFER_SIZE;
351 TXBufferCurrentPositionHandler += 2;
352 break;
354 case requestEchoPacketReturn:
356 /* This type must have a length field, set that up */
357 *((unsigned short*)TXBufferCurrentPositionHandler) = RXPacketLengthReceived;
358 *TXHeaderFlags |= HEADER_HAS_LENGTH;
359 TXBufferCurrentPositionHandler += 2;
360 /* Load the body into place */
361 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&RXBuffer, RXPacketLengthReceived);
362 /* Note, there is no overflow check here because the TX buffer is slightly */
363 /* bigger than the RX buffer and there is overflow checking for receives anyway. */
364 TXBufferCurrentPositionHandler += RXPacketLengthReceived;
365 break;
367 case requestSoftSystemReset:
369 if(RXCalculatedPayloadLength != 0){
370 errorID = payloadLengthTypeMismatch;
371 }else{ // Perform soft system reset
372 _start();
374 break;
376 case requestHardSystemReset:
378 if(RXCalculatedPayloadLength != 0){
379 errorID = payloadLengthTypeMismatch;
380 }else{
381 /* This is how the serial monitor does it. */
382 COPCTL = 0x01; /* Arm with shortest time */
383 ARMCOP = 0xFF; /* Write bad value, should cause immediate reset */
384 /* Using _start() only resets the app ignoring the monitor switch. It does not work */
385 /* properly because the location of _start is not the master reset vector location. */
387 break;
389 case requestReInitOfSystem:
391 if(RXCalculatedPayloadLength != 0){
392 errorID = payloadLengthTypeMismatch;
393 }else{
394 init();
396 break;
398 // FreeEMS Vanilla Firmware Specific cases
399 case clearCountersAndFlagsToZero:
401 if(RXCalculatedPayloadLength != 0){
402 errorID = payloadLengthTypeMismatch;
403 break;
406 unsigned short zeroCounter;
407 unsigned char* counterPointer;
409 counterPointer = (unsigned char*) &Counters;
410 for(zeroCounter = 0;zeroCounter < sizeof(Counter);zeroCounter++){
411 *counterPointer = 0;
412 counterPointer++;
415 KeyUserDebugs.flaggableFlags = 0;
416 counterPointer = (unsigned char*) &Flaggables;
417 for(zeroCounter = 0;zeroCounter < sizeof(Flaggable);zeroCounter++){
418 *counterPointer = 0;
419 counterPointer++;
422 KeyUserDebugs.flaggableFlags2 = 0;
423 counterPointer = (unsigned char*) &Flaggables2;
424 for(zeroCounter = 0;zeroCounter < sizeof(Flaggable2);zeroCounter++){
425 *counterPointer = 0;
426 counterPointer++;
428 break;
430 case requestDecoderName:
431 case requestFirmwareBuildDate:
432 case requestCompilerVersion:
433 case requestOperatingSystem:
435 if(RXCalculatedPayloadLength != 0){
436 errorID = payloadLengthTypeMismatch;
437 break;
440 unsigned char* stringToSend = 0;
441 switch (RXHeaderPayloadID) {
442 case requestDecoderName:
443 stringToSend = (unsigned char*)decoderName;
444 break;
445 case requestFirmwareBuildDate:
446 stringToSend = (unsigned char*)buildTimeAndDate;
447 break;
448 case requestCompilerVersion:
449 stringToSend = (unsigned char*)compilerVersion;
450 break;
451 case requestOperatingSystem:
452 stringToSend = (unsigned char*)operatingSystem;
453 break;
455 /* This type must have a length field, set that up and load the body into place at the same time */
456 *((unsigned short*)TXBufferCurrentPositionHandler) = stringCopy((TXBufferCurrentPositionHandler + 2), stringToSend);
457 *TXHeaderFlags |= HEADER_HAS_LENGTH;
458 // Update with length field and string length.
459 TXBufferCurrentPositionHandler += 2 + *((unsigned short*)TXBufferCurrentPositionHandler);
460 break;
462 case updateBlockInRAM:
464 // Subtract six to allow for the locationID, size, offset
465 if(RXCalculatedPayloadLength < 7){
466 errorID = payloadLengthTypeMismatch;
467 break;
470 // Extract the RAM location ID
471 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
472 RXBufferCurrentPosition += 2;
474 // Extract the offset to place the data at
475 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
476 RXBufferCurrentPosition += 2;
478 // Extract the size of the data to be stored
479 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
480 RXBufferCurrentPosition += 2;
482 // Look up the memory location details
483 blockDetails details;
484 lookupBlockDetails(locationID, &details);
486 // Don't let anyone write to running variables unless we are running BenchTest firmware!
487 if((details.flags & block_is_read_only) && compare((unsigned char*)&decoderName, (unsigned char*)BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME))){
488 errorID = attemptToWriteToReadOnlyBlock;
489 break;
492 // Subtract six to allow for the locationID, size, offset
493 if((RXCalculatedPayloadLength - 6) != size){
494 errorID = payloadNotEqualToSpecifiedValue;
495 break;
498 // If either of these is zero then this block is not in RAM!
499 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
500 errorID = invalidMemoryActionForID;
501 break;
504 // Check that size and offset describe a region that is not out of bounds
505 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
506 errorID = invalidSizeOffsetCombination;
507 break;
510 // Don't allow sub region manipulation where it does not make sense or is unsafe.
511 if((size != details.size) && !(details.flags & block_is_indexable)){
512 errorID = uncheckedTableManipulationNotAllowed;
513 break;
516 // Save page values for restore
517 unsigned char oldRamPage = RPAGE;
518 // Set the viewable RAM page
519 RPAGE = details.RAMPage;
521 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
523 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
524 void* bufferToCheck;
526 // For sub regions, construct an image for verification
527 if(size != details.size){
528 // Copy data from destination location to buffer
529 memcpy(leftOverBuffer, details.RAMAddress, details.size);
531 // Copy data from rx buffer to buffer over writing old data
532 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
534 bufferToCheck = leftOverBuffer;
535 }else{
536 bufferToCheck = RXBufferCurrentPosition;
539 // Verify all tables
540 if(details.flags & block_is_main_table){
541 errorID = validateMainTable((mainTable*)bufferToCheck);
542 }else if(details.flags & block_is_2dus_table){
543 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
544 }// TODO add other table types here
546 // If the validation failed, report it
547 if(errorID != 0){
548 RPAGE = oldRamPage; // Restore the original RAM page, even when getting an error condition.
549 break;
553 // Copy from the RX buffer to the block of RAM
554 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
556 // Check that the write was successful
557 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
559 // Restore the original RAM and flash pages
560 RPAGE = oldRamPage;
562 if(index != 0){
563 errorID = MEMORY_WRITE_ERROR;
565 break;
567 case updateBlockInFlash:
569 // Subtract six to allow for the locationID, size, offset
570 if(RXCalculatedPayloadLength < 7){
571 errorID = payloadLengthTypeMismatch;
572 break;
575 // Extract the RAM location ID
576 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
577 RXBufferCurrentPosition += 2;
579 // Extract the offset to place the data at
580 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
581 RXBufferCurrentPosition += 2;
583 // Extract the size of the data to be stored
584 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
585 RXBufferCurrentPosition += 2;
587 // Look up the memory location details
588 blockDetails details;
589 lookupBlockDetails(locationID, &details);
591 // Subtract six to allow for the locationID, size, offset
592 if((RXCalculatedPayloadLength - 6) != size){
593 errorID = payloadNotEqualToSpecifiedValue;
594 break;
597 // If either of these is zero then this block is not in flash!
598 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
599 errorID = invalidMemoryActionForID;
600 break;
603 // Check that size and offset describe a region that is not out of bounds
604 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
605 errorID = invalidSizeOffsetCombination;
606 break;
609 // Don't allow sub region manipulation where it does not make sense or is unsafe.
610 if((size != details.size) && !(details.flags & block_is_indexable)){
611 errorID = uncheckedTableManipulationNotAllowed;
612 break;
615 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
617 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
618 void* bufferToCheck;
620 // For sub regions, construct an image for verification
621 if(size != details.size){
622 /* Save page value for restore and set the visible page */
623 unsigned char oldFlashPage = PPAGE;
624 PPAGE = details.FlashPage;
626 // Copy data from destination location to buffer
627 memcpy(leftOverBuffer, details.FlashAddress, details.size);
629 /* Restore the original flash page */
630 PPAGE = oldFlashPage;
632 // Copy data from rx buffer to buffer over writing old data
633 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
635 bufferToCheck = leftOverBuffer;
636 }else{
637 bufferToCheck = RXBufferCurrentPosition;
640 // Verify all tables
641 if(details.flags & block_is_main_table){
642 errorID = validateMainTable((mainTable*)bufferToCheck);
643 }else if(details.flags & block_is_2dus_table){
644 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
645 }// TODO add other table types here
647 // If the validation failed, report it
648 if(errorID != 0){
649 break;
653 /* Copy the flash details and populate the RAM details with the buffer location */
654 blockDetails burnDetails;
655 burnDetails.FlashPage = details.FlashPage;
656 burnDetails.FlashAddress = details.FlashAddress + offset;
657 burnDetails.RAMPage = RPAGE;
658 burnDetails.RAMAddress = RXBufferCurrentPosition;
659 burnDetails.size = size;
661 /* Copy from the RX buffer to the block of flash */
662 errorID = writeBlock(&burnDetails, leftOverBuffer);
663 if(errorID != 0){
664 break;
667 /* If present in RAM, update that too */
668 if((details.RAMPage != 0) && (details.RAMAddress != 0)){
669 /* Save page values for restore */
670 unsigned char oldRamPage = RPAGE;
671 /* Set the viewable RAM page */
672 RPAGE = details.RAMPage;
674 /* Copy from the RX buffer to the block of RAM */
675 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
677 /* Check that the write was successful */
678 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
680 /* Restore the original RAM and flash pages */
681 RPAGE = oldRamPage;
683 if(index != 0){
684 errorID = MEMORY_WRITE_ERROR;
688 break;
690 case retrieveBlockFromRAM:
692 if(RXCalculatedPayloadLength != 6){
693 errorID = payloadLengthTypeMismatch;
694 break;
697 // Extract the RAM location ID
698 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
699 RXBufferCurrentPosition += 2;
701 // Extract the offset to place the data at
702 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
703 RXBufferCurrentPosition += 2;
705 // Extract the size of the data to be stored
706 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
707 RXBufferCurrentPosition += 2;
709 /* Look up the memory location details */
710 blockDetails details;
711 lookupBlockDetails(locationID, &details);
713 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
714 errorID = invalidMemoryActionForID;
715 break;
718 // Special behaviour for size of zero which returns the whole block
719 if((size == 0) && (offset == 0)){
720 size = details.size;
723 // Check that size and offset describe a region that is not out of bounds
724 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
725 errorID = invalidSizeOffsetCombination;
726 break;
729 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
730 if((size != details.size) && !(details.flags & block_is_indexable)){
731 errorID = doesNotMakeSenseToRetrievePartially;
732 break;
735 // This type must have a length field, set that up
736 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
737 *TXHeaderFlags |= HEADER_HAS_LENGTH;
738 TXBufferCurrentPositionHandler += 2;
740 /* Save page value for restore and set the visible page */
741 unsigned char oldRamPage = RPAGE;
742 RPAGE = details.RAMPage;
744 /* Copy the block of RAM to the TX buffer */
745 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.RAMAddress + offset), size);
746 TXBufferCurrentPositionHandler += size;
748 /* Restore the original RAM and flash pages */
749 RPAGE = oldRamPage;
751 break;
753 case retrieveBlockFromFlash:
755 if(RXCalculatedPayloadLength != 6){
756 errorID = payloadLengthTypeMismatch;
757 break;
760 // Extract the RAM location ID
761 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
762 RXBufferCurrentPosition += 2;
764 // Extract the offset to place the data at
765 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
766 RXBufferCurrentPosition += 2;
768 // Extract the size of the data to be stored
769 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
770 RXBufferCurrentPosition += 2;
772 /* Look up the memory location details */
773 blockDetails details;
774 lookupBlockDetails(locationID, &details);
776 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
777 errorID = invalidMemoryActionForID;
778 break;
781 // Special behaviour for size of zero which returns the whole block
782 if((size == 0) && (offset == 0)){
783 size = details.size;
786 // Check that size and offset describe a region that is not out of bounds
787 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
788 errorID = invalidSizeOffsetCombination;
789 break;
792 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
793 if((size != details.size) && !(details.flags & block_is_indexable)){
794 errorID = doesNotMakeSenseToRetrievePartially;
795 break;
798 // This type must have a length field, set that up
799 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
800 *TXHeaderFlags |= HEADER_HAS_LENGTH;
801 TXBufferCurrentPositionHandler += 2;
803 /* Save page value for restore and set the visible page */
804 unsigned char oldFlashPage = PPAGE;
805 PPAGE = details.FlashPage;
807 /* Copy the block of flash to the TX buffer */
808 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.FlashAddress + offset), size);
809 TXBufferCurrentPositionHandler += size;
811 /* Restore the original RAM and flash pages */
812 PPAGE = oldFlashPage;
814 break;
816 case burnBlockFromRamToFlash:
818 if(RXCalculatedPayloadLength != 6){
819 errorID = payloadLengthTypeMismatch;
820 break;
823 // Extract the RAM location ID
824 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
825 RXBufferCurrentPosition += 2;
827 // Extract the offset to place the data at
828 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
829 RXBufferCurrentPosition += 2;
831 // Extract the size of the data to be stored
832 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
833 RXBufferCurrentPosition += 2;
835 /* Look up the memory location details */
836 blockDetails details;
837 lookupBlockDetails(locationID, &details);
839 /* Check that all data we need is present */
840 if((details.RAMPage == 0) || (details.RAMAddress == 0) || (details.FlashPage == 0) || (details.FlashAddress == 0)){
841 errorID = invalidMemoryActionForID;
842 break;
845 // Special behaviour for size of zero which burns the whole block
846 if((size == 0) && (offset == 0)){
847 size = details.size;
850 // Check that size and offset describe a region that is not out of bounds
851 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
852 errorID = invalidSizeOffsetCombination;
853 break;
856 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
857 if((size != details.size) && !(details.flags & block_is_indexable)){
858 errorID = doesNotMakeSenseToRetrievePartially;
859 break;
863 // adjust details block to feed to represent the subsection of ram and flash that we want to burn down.
864 details.RAMAddress += offset;
865 details.FlashAddress += offset;
866 details.size = size;
868 /* Write the block down from RAM to Flash */
869 errorID = writeBlock(&details, leftOverBuffer);
870 break;
872 case requestDatalogPacket: // Set type through standard configuration methods
874 if(RXCalculatedPayloadLength != 0){
875 errorID = payloadLengthTypeMismatch;
876 break;
879 /* Set the length field up */
880 *TXHeaderFlags |= HEADER_HAS_LENGTH;
881 unsigned short* localLength = (unsigned short*)TXBufferCurrentPositionHandler;
882 TXBufferCurrentPositionHandler += 2;
884 /* Fill out the log and send */
885 *localLength = populateBasicDatalog();
886 break;
888 case setAsyncDatalogType:
890 if(RXCalculatedPayloadLength != 1){
891 errorID = payloadLengthTypeMismatch;
892 break;
895 unsigned char newDatalogType = *((unsigned char*)RXBufferCurrentPosition);
896 if(newDatalogType > asyncDatalogLastType){
897 errorID = noSuchAsyncDatalogType;
898 break;
901 TablesB.SmallTablesB.loggingSettings.datalogStreamType = newDatalogType;
902 break;
904 case retrieveArbitraryMemory:
906 if(RXCalculatedPayloadLength != 6){
907 errorID = payloadLengthTypeMismatch;
908 break;
911 unsigned short length = *((unsigned short*)RXBufferCurrentPosition);
912 RXBufferCurrentPosition += 2;
913 // Make sure the buffer can handle the block
914 if(length > TX_MAX_PAYLOAD_SIZE){
915 errorID = requestedLengthTooLarge;
916 break;
919 void* address = (void*) *((unsigned short*)RXBufferCurrentPosition);
920 RXBufferCurrentPosition += 2;
921 // Ensure we don't try to read past the end of the address space
922 if(((unsigned short)address) <= ((0xFFFF - length) + 1)){
923 // TODO Possibly check and limit ranges
924 errorID = requestedAddressDisallowed;
925 break;
928 unsigned char RAMPage = *((unsigned char*)RXBufferCurrentPosition);
929 RXBufferCurrentPosition++;
930 // Ensure RAM page is valid. Being too high is not possible.
931 if(RAMPage < RPAGE_MIN){
932 errorID = requestedRAMPageInvalid;
933 break;
936 unsigned char FlashPage = *((unsigned char*)RXBufferCurrentPosition);
937 RXBufferCurrentPosition++;
938 // Ensure Flash page is valid. Being too high is not possible.
939 if(FlashPage < PPAGE_MIN){
940 errorID = requestedFlashPageInvalid;
941 break;
944 /* This type must have a length field, set that up */
945 *((unsigned short*)TXBufferCurrentPositionHandler) = length + 6;
946 *TXHeaderFlags |= HEADER_HAS_LENGTH;
947 TXBufferCurrentPositionHandler += 2;
949 /* Put the request payload into the reply */
950 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short) address;
951 TXBufferCurrentPositionHandler += 2;
952 *((unsigned short*)TXBufferCurrentPositionHandler) = length;
953 TXBufferCurrentPositionHandler += 2;
954 *((unsigned char*)TXBufferCurrentPositionHandler) = RAMPage;
955 TXBufferCurrentPositionHandler++;
956 *((unsigned char*)TXBufferCurrentPositionHandler) = FlashPage;
957 TXBufferCurrentPositionHandler++;
959 /* Load the body into place */
960 memcpy((void*)TXBufferCurrentPositionHandler, address, length);
961 TXBufferCurrentPositionHandler += length;
963 break;
965 case retrieveListOfLocationIDs:
967 if(RXCalculatedPayloadLength != 3){
968 errorID = payloadLengthTypeMismatch;
969 break;
972 // Extract the type of list that we want
973 unsigned char listType = *((unsigned char*)RXBufferCurrentPosition);
974 RXBufferCurrentPosition++;
976 // Extract the mask for the qualities that we want
977 unsigned short blockDetailsMask = *((unsigned short*)RXBufferCurrentPosition);
978 RXBufferCurrentPosition += 2;
980 // This type must have a length field, set that up
981 unsigned short * listLength = (unsigned short*)TXBufferCurrentPositionHandler;
982 *TXHeaderFlags |= HEADER_HAS_LENGTH;
983 TXBufferCurrentPositionHandler += 2;
985 // Zero the counter before we start, woops!
986 *listLength = 0;
988 unsigned long locationID;
989 blockDetails details;
990 for(locationID = 0;locationID < 65536;locationID++){
991 unsigned short locationIDDoesntExist;
992 locationIDDoesntExist = lookupBlockDetails((unsigned short)locationID, &details);
994 if(!locationIDDoesntExist){
995 if((listType == 0x00) || // get all
996 ((listType == 0x01) && (details.flags & blockDetailsMask)) || // get OR of bits
997 ((listType == 0x02) && (!(~(details.flags) & blockDetailsMask)))){ // get AND of bits
998 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short)locationID;
999 TXBufferCurrentPositionHandler += 2;
1000 *listLength += 2;
1005 break;
1007 case retrieveLocationIDDetails:
1009 if(RXCalculatedPayloadLength != 2){
1010 errorID = payloadLengthTypeMismatch;
1011 break;
1014 // Extract the RAM location ID
1015 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
1016 RXBufferCurrentPosition += 2;
1018 // This type must have a length field, set that up
1019 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(blockDetails);
1020 *TXHeaderFlags |= HEADER_HAS_LENGTH;
1021 TXBufferCurrentPositionHandler += 2;
1023 // Write straight to output buffer to save time/code
1024 errorID = lookupBlockDetails(locationID, (blockDetails*)TXBufferCurrentPositionHandler);
1026 if(errorID != 0){
1027 break;
1030 // Adjust TX buffer position if successful
1031 TXBufferCurrentPositionHandler += sizeof(blockDetails);
1033 break;
1035 case requestUnitTestOverSerial:
1038 * The idea here is to call this function with arguments, and data
1039 * and have the result sent back for comparison with an expected
1040 * result that isn't divulged to the firmware.
1042 * It is intended that all testable functions be callable through
1043 * this mechanism and that any number of test executions can be
1044 * performed by an external suite using different parameters and
1045 * data sets and matching expected results.
1047 * The usual error mechanism shall be used to indicate some sort of
1048 * either internal or test failure and returned errors shall be
1049 * suitably descriptive to allow diagnosis and fixing of issues.
1052 // Must at least have test ID
1053 if(RXCalculatedPayloadLength < 2){
1054 errorID = payloadLengthTypeMismatch;
1055 break;
1058 // grab unit test ID from payload
1059 unsigned short unitTestID = *((unsigned short*)RXBufferCurrentPosition);
1060 RXBufferCurrentPosition += 2;
1062 switch(unitTestID){
1063 case testEmptyTest:
1065 // Must be only the ID
1066 if(RXCalculatedPayloadLength != 2){
1067 errorID = payloadShorterThanRequiredForTest;
1068 break;
1071 *((unsigned short*)TXBufferCurrentPositionHandler) = unitTestID;
1072 TXBufferCurrentPositionHandler +=2;
1074 break;
1076 case testTwoDTableUSLookup:
1078 // ID + Value + Table
1079 if(RXCalculatedPayloadLength != (2 + 2 + sizeof(twoDTableUS))){
1080 errorID = payloadShorterThanRequiredForTest;
1081 break;
1084 unsigned short Value = *((unsigned short*)RXBufferCurrentPosition);
1085 RXBufferCurrentPosition += 2;
1087 twoDTableUS* Table = ((twoDTableUS*)RXBufferCurrentPosition);
1088 RXBufferCurrentPosition += sizeof(twoDTableUS);
1090 unsigned short result = lookupTwoDTableUS(Table, Value);
1092 *((unsigned short*)TXBufferCurrentPositionHandler) = result;
1093 TXBufferCurrentPositionHandler +=2;
1095 break;
1097 // http://issues.freeems.org/view.php?id=156
1099 /// TODO @todo test all things listed below:
1100 // lookupPagedMainTableCellValue - pass this RPAGE so that it remains unchanged
1101 // validateMainTable
1102 // validateTwoDTable
1103 // set table values - leave this till last, currently unused by mtx, likely to be removed anyway
1104 // generateDerivedVars - convert to pointers, remove headers, privatise a lot of data!
1105 // calculateFuelAndIgnition - ditto
1106 // scheduling algorithm - ditto
1107 // safeAdd
1108 // safeTrim
1109 // safeScale
1110 // sleep (milliseconds)
1111 // sleepMicro (microseconds)
1112 // checksum
1113 // stringCopy
1114 // compare
1115 // 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)
1116 // init code may be able to be partially checked
1117 // most other code at this stage is ISR code, flash writing code, or could interfere with the running of the engine
1118 // more testable code will appear with time, such as the HAL layer, and most accessory functions.
1119 default:
1121 errorID = noSuchUnitTestID;
1124 // each case:
1125 // checks length, fails if wrong
1126 // parses data into args
1127 // calls function on data/args
1128 // assembles response OR sets error
1129 // breaks
1131 break;
1133 case startBenchTestSequence:
1135 // see TODO on include at top and modify this line appropriately
1136 if(!(compare((unsigned char*)&decoderName, (unsigned char*)BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME)))){
1137 if(RXCalculatedPayloadLength < 1){
1138 errorID = payloadLengthTypeMismatch;
1139 break;
1142 unsigned char localTestMode = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1143 RXBufferCurrentPosition++;
1144 if(localTestMode > TEST_MODE_BUMP_UP_CYCLES){
1145 errorID = unimplementedTestMode;
1146 break;
1147 }else if((localTestMode == TEST_MODE_STOP) && (RXCalculatedPayloadLength == 1)){
1148 if(!(coreStatusA & BENCH_TEST_ON)){
1149 errorID = benchTestNotRunningToStop;
1150 break;
1153 // Ensure we succeed at stopping it as quickly as possible.
1154 ATOMIC_START();
1155 // Stash mid-test details for return
1156 *((unsigned short*)TXBufferCurrentPositionHandler) = testNumberOfCycles; // Save and return the remaining cycle count
1157 TXBufferCurrentPositionHandler +=2;
1158 *((unsigned char*)TXBufferCurrentPositionHandler) = KeyUserDebugs.currentEvent; // Save the current event for the ultra-fussy
1159 TXBufferCurrentPositionHandler++;
1160 // Setup the test to stop ASAP
1161 KeyUserDebugs.currentEvent = testEventsPerCycle - 1; // Gets incremented then compared with testEventsPerCycle
1162 testNumberOfCycles = 1; // Gets decremented then compared with zero
1163 ATOMIC_END();
1165 break;
1166 }else if((localTestMode == TEST_MODE_BUMP_UP_CYCLES) && (RXCalculatedPayloadLength == 2)){
1167 if(!(coreStatusA & BENCH_TEST_ON)){
1168 errorID = benchTestNotRunningToBump;
1169 break;
1172 // Get bump value from payload
1173 unsigned char bumpCycles = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1174 RXBufferCurrentPosition++;
1176 if(bumpCycles == 0){
1177 errorID = bumpingByZeroMakesNoSense;
1178 break;
1181 // Bump count by value from payload
1182 testNumberOfCycles += bumpCycles;
1183 // Given that this function is only for situations when A it's getting near to
1184 // zero and B the user is watching, not checking for overflow is reasonable.
1186 *((unsigned char*)TXBufferCurrentPositionHandler) = bumpCycles; // Return the bump size for achaelogical purposes
1187 TXBufferCurrentPositionHandler++;
1189 break;
1190 }else if((localTestMode == TEST_MODE_ITERATIONS) && (RXCalculatedPayloadLength == 24)){
1191 testMode = localTestMode;
1192 // do nothing to fall through, or move other code into here
1193 }else{
1194 errorID = packetSizeWrongForTestMode;
1195 break;
1198 if(coreStatusA & BENCH_TEST_ON){
1199 errorID = benchTestAlreadyRunning;
1200 break;
1203 testEventsPerCycle = *((unsigned char*)RXBufferCurrentPosition); //100; // @ 10ms = 1s
1204 RXBufferCurrentPosition++;
1205 if(testEventsPerCycle == 0){
1206 errorID = invalidEventsPerCycle;
1207 break;
1210 testNumberOfCycles = *((unsigned short*)RXBufferCurrentPosition); //20; // @ 1s = 20s
1211 RXBufferCurrentPosition += 2;
1212 if(testNumberOfCycles == 0){
1213 errorID = invalidNumberOfCycles;
1214 break;
1217 testTicksPerEvent = *((unsigned short*)RXBufferCurrentPosition); //12500; // @ 0.8us = 10ms
1218 RXBufferCurrentPosition += 2;
1219 if(testTicksPerEvent < decoderMaxCodeTime){
1220 errorID = tooShortOfAnEventPeriod;
1221 break;
1224 // Pluck the arrays out of the packet for the loop below
1225 unsigned char* testEventNumbers = RXBufferCurrentPosition;
1226 RXBufferCurrentPosition += 6;
1227 unsigned short* testPulseWidths = (unsigned short*)RXBufferCurrentPosition;
1228 RXBufferCurrentPosition += 12;
1230 // Reset the clock for reading timeout
1231 Clocks.timeoutADCreadingClock = 0; // make this optional, such that we can use real inputs to determine pw and/or dwell.
1233 // Validate and transfer the per-channel data
1234 unsigned char channel;
1235 unsigned char configuredChannels = 6;
1236 for(channel = 0;channel < 6;channel++){
1237 if(testPulseWidths[channel] > injectorSwitchOnCodeTime){ // See next block for warning.
1238 // use as-is
1239 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1240 outputEventPulseWidthsMath[channel] = testPulseWidths[channel];
1241 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1242 }else if(testPulseWidths[channel] > 3){
1243 // less than the code time, and not special, error!
1244 errorID = tooShortOfAPulseWidthToTest;
1245 // Warning, PWs close to this could be slightly longer than requested, that will change in later revisions.
1246 break;
1247 }else if(testPulseWidths[channel] == 3){
1248 testMode++; // Dirty hack to avoid dealing with Dave for the time being.
1249 testNumberOfMissing = channel;
1250 }else if(testPulseWidths[channel] == 2){
1251 // use the dwell from the core maths and input vars.
1252 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1253 outputEventPulseWidthsMath[channel] = DerivedVars->Dwell;
1254 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1255 }else if(testPulseWidths[channel] == 1){
1256 // use the reference pulse width from the core maths and input vars.
1257 outputEventDelayFinalPeriod[channel] = decoderMaxCodeTime;
1258 outputEventPulseWidthsMath[channel] = DerivedVars->RefPW;
1259 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1260 }else{ // is zero
1261 // Set this channel to zero for and therefore off, don't set this channel.
1262 outputEventInputEventNumbers[channel] = 0xFF; // Off.
1263 configuredChannels--;
1267 if(configuredChannels == 0){
1268 errorID = noChannelsConfiguredToTest;
1269 break;
1272 if(errorID == 0){
1273 // Let the first iteration roll it over to zero.
1274 KeyUserDebugs.currentEvent = 0xFF; // Needs to be here in case of multiple runs, init is not sufficient
1276 if(testMode == TEST_MODE_DODGY_MISSING_TOOTH){
1277 if(testEventsPerCycle <= 127){
1278 testEventsPerCycle *= 2;
1279 }else{
1280 errorID = tooManyEventsPerCycleMissingTth;
1281 break;
1284 // Store the time per event in RPM such that it can be updated dynamically
1285 CoreVars->RPM = testTicksPerEvent;
1287 // The channels to use rely on the defaults from initialisers! Custom builds can break BenchTest mode!
1289 // Un-schedule anything that got scheduled
1290 outputEventInputEventNumbers[2] = 0xFF;
1291 outputEventInputEventNumbers[3] = 0xFF;
1292 outputEventInputEventNumbers[4] = 0xFF;
1293 outputEventInputEventNumbers[5] = 0xFF;
1294 }else if(testMode > TEST_MODE_DODGY_MISSING_TOOTH){
1295 errorID = unimplementedTestMode;
1296 break;
1299 // Trigger decoder interrupt to fire thus starting the loop!
1300 TIE = 0x01; // The ISR does the rest!
1302 // Nothing went wrong, now set flag.
1303 coreStatusA |= BENCH_TEST_ON;
1304 }else{
1305 break;
1309 /* http://issues.freeems.org/view.php?id=155
1311 * The following block has been left in, as I still do not know why it won't work as intended:
1313 * - It should fire all 6 output pins with a 52ms duration pulse, exactly once.
1314 * - 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
1315 * - The interrupts run, but the pin doesn't change state, despite the registers being configured correctly
1317 * I've tried quite a bit:
1319 * - Moving this code around
1320 * - Checking memory definitions
1321 * - Completely rewriting the output ISR
1322 * - Adding significant debug to output ISR
1323 * - Checking for register contents in output ISR
1324 * - Checking for key things modified in this file
1325 * - General head scratching and confused searching
1328 // outputEventPinNumbers[0] = 0; // 1 ign
1329 // outputEventPinNumbers[1] = 1; // 2 ign
1330 // outputEventPinNumbers[2] = 2; // 3 ign/1 fuel
1331 // outputEventPinNumbers[3] = 3; // 4 ign/2 fuel
1332 // outputEventPinNumbers[4] = 4; // 3 fuel
1333 // outputEventPinNumbers[5] = 5; // 4 fuel
1334 // outputEventDelayFinalPeriod[0] = decoderMaxCodeTime;
1335 // outputEventDelayFinalPeriod[1] = decoderMaxCodeTime;
1336 // outputEventDelayFinalPeriod[2] = decoderMaxCodeTime;
1337 // outputEventDelayFinalPeriod[3] = decoderMaxCodeTime;
1338 // outputEventDelayFinalPeriod[4] = decoderMaxCodeTime;
1339 // outputEventDelayFinalPeriod[5] = decoderMaxCodeTime;
1340 // outputEventPulseWidthsMath[0] = SHORTMAX;
1341 // outputEventPulseWidthsMath[1] = SHORTMAX;
1342 // outputEventPulseWidthsMath[2] = SHORTMAX;
1343 // outputEventPulseWidthsMath[3] = SHORTMAX;
1344 // outputEventPulseWidthsMath[4] = SHORTMAX;
1345 // outputEventPulseWidthsMath[5] = SHORTMAX;
1347 // unsigned short edgeTimeStamp = TCNT;
1348 // // call sched output with args
1349 // LongTime timeStamp;
1350 // /* Install the low word */
1351 // timeStamp.timeShorts[1] = edgeTimeStamp;
1352 // /* Find out what our timer value means and put it in the high word */
1353 // if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
1354 // timeStamp.timeShorts[0] = timerExtensionClock + 1;
1355 // }else{
1356 // timeStamp.timeShorts[0] = timerExtensionClock;
1357 // }
1359 // schedulePortTPin(0, timeStamp);
1360 // schedulePortTPin(1, timeStamp);
1361 // schedulePortTPin(2, timeStamp);
1362 // schedulePortTPin(3, timeStamp);
1363 // schedulePortTPin(4, timeStamp);
1364 // schedulePortTPin(5, timeStamp);
1366 // sleep(1000);
1367 }else{
1368 errorID = thisIsNotTheBenchTestDecoder;
1370 break;
1372 default:
1374 if((RXHeaderPayloadID % 2) == 1){
1375 errorID = invalidPayloadID;
1376 }else{
1377 errorID = unrecognisedPayloadID;
1379 break;
1383 // Always reply, if errorID is zero it's just an ack.
1384 finaliseAndSend(errorID);
1386 /* Switch reception back on now that we are done with the received data */
1387 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
1391 /* This function should be period limited to about 10 seconds internally (or by scheduler) */
1392 //void checkCountersAndSendErrors(){
1393 // compare time stamps with current time stamps and execute if old enough. (if no scheduler)
1395 // compare counters with counters cache (from last time) sending an error packet when they differ
1397 // copy counters to counters cache for next time
1399 // send errors with busy wait on the basis that all errors should be taken care of and not be sent in fairly short order?
1401 // or send with isr but just busy wait for it to finish before sending the next?
1403 // 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.
1405 // need to figure out how to queue received packets for processing when we are currently sending stuff out.
1407 // above notes don't belong here really.