Moved interface version to new string format with trailing textual 0.0.0 version...
[freeems-vanilla.git] / src / commsCore.c
blobe4f8da1ce51a69437ac657d1467b8c00e2dd5254
1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2011 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 commsCore.c
28 * @ingroup communicationsFiles
30 * @brief Core communications functions.
32 * This file contains most of the core comms functionality. Currently that is
33 * only for UART serial style communication. It is already too big and needs
34 * to be split up somewhat. This will happen fairly soon during the serial
35 * refactoring and protocol fine tuning.
37 * @todo TODO function to setup a packet and send it fn(populateBodyFunctionPointer(), header, other, fields, here, and, use, or, not, within){}
38 * @todo TODO factor many things into functions and move the receive delegator to its own file
40 * @author Fred Cooke
44 #define COMMSCORE_C
45 #include "inc/freeEMS.h"
46 #include "inc/flashWrite.h"
47 #include "inc/interrupts.h"
48 #include "inc/utils.h"
49 #include "inc/tableLookup.h"
50 #include "inc/locationIDs.h"
51 #include "inc/blockDetailsLookup.h"
52 #include "inc/decoderInterface.h"
53 #include "inc/commsCore.h"
54 #include "inc/init.h"
55 #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
56 #include <datalogPopulator.c>
57 #include "decoders/inc/BenchTest.h"
60 /** @brief Populate a basic datalog packet
62 * Copies various chunks of data to the transmission buffer and truncates to
63 * the configured length. If changing this, update the maxBasicDatalogLength.
65 * @author Fred Cooke
67 * @warning This function is only a skeleton at this time.
69 void populateBasicDatalog(){
70 /* Save the current position */
71 unsigned char* position = TXBufferCurrentPositionHandler;
73 /// @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.
75 // By default, default values are populated, but if you drop code into the custom directory, that replaces the defaults.
76 populateCustomDatalog();
77 // Done here to overwrite cheeky custom users data:
78 KeyUserDebugs.coreStatusA = coreStatusA;
79 KeyUserDebugs.tempClock++;
80 KeyUserDebugs.clockIn8thsOfAMilli = Clocks.realTimeClockMain;
81 KeyUserDebugs.clockInMilliSeconds = Clocks.realTimeClockMillis;
83 /* Get core vars */
84 memcpy(TXBufferCurrentPositionHandler, CoreVars, sizeof(CoreVar));
85 TXBufferCurrentPositionHandler += sizeof(CoreVar);
86 /* Get derived vars */
87 memcpy(TXBufferCurrentPositionHandler, DerivedVars, sizeof(DerivedVar));
88 TXBufferCurrentPositionHandler += sizeof(DerivedVar);
89 /* Get raw adc counts */
90 memcpy(TXBufferCurrentPositionHandler, &KeyUserDebugs, sizeof(KeyUserDebug));
91 TXBufferCurrentPositionHandler += sizeof(KeyUserDebug);
93 /* Set/Truncate the log to the specified length */
94 TXBufferCurrentPositionHandler = position + TablesB.SmallTablesB.loggingSettings.basicDatalogLength;
98 // All of these require some range checking, eg only some registers, and all RAM, not flash, not other regs
99 // TODO pointer for one byte
100 // TODO pointer for one short
101 // TODO function to log generic memory region by location and size ? requires length!
102 // Ranges are :
103 // RAM window
104 // bss/data region
105 // IO registers etc that can't be altered simply by reading from.
106 // NOT :
107 // flash makes no sense
108 // some regs are sensitive
109 // some RAM is unused
110 // serial buffers make no sense
111 // eeprom makes no sense
113 // 2k of regs max - user beware for now
114 // 12k of RAM max
116 //init :
117 //logaddr = fixed.addr
118 //loglen = fixed.len
120 //len = loglen OR 1 OR 2
122 //check :
123 //if((addr < 0x0800) && (length < (0x0800 - addr))){
124 // // reg space is OK
125 //}else if(((0x1000 < addr) && (addr < 0x4000)) && (length < (0x4000 - addr))){
126 // // RAM space is OK
127 //}else{
128 // // send an error instead
131 //run check at init and set time, not run time or just not check?? maybe its silly to check at all
133 // /* Just dump the ADC channels as fast as possible */
134 //void populateScopeLogADCAll(){
135 // sampleBlockADC(TXBufferCurrentPositionHandler);
136 // TXBufferCurrentPositionHandler += sizeof(ADCBuffer);
140 // 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.
143 /** @brief Finalise a packet and send it
145 * This functions job is to finalise the main loop part of the packet sending
146 * process. It configures the pos/neg ack header bit, adds the code if neg,
147 * runs a checksum over the packet data and tags it to the end before
148 * configuring the various ISRs that need to send the data out.
150 * @author Fred Cooke
152 * @bug http://issues.freeems.org/view.php?id=81
153 * @todo TODO fix the double/none start byte bug and remove the hack!
155 void finaliseAndSend(unsigned short errorID){
157 if(errorID != 0){
158 *TXHeaderFlags |= HEADER_IS_NACK;
159 *((unsigned short*)TXBufferCurrentPositionHandler) = errorID;
160 TXBufferCurrentPositionHandler += 2;
163 /* Get the length from the pointer */
164 unsigned short TXPacketLengthToSend = (unsigned short)TXBufferCurrentPositionHandler - (unsigned short)&TXBuffer;
166 /* Tag the checksum on the end */
167 *TXBufferCurrentPositionHandler = checksum((unsigned char*)&TXBuffer, TXPacketLengthToSend);
168 TXPacketLengthToSend++;
170 /* Send it out on all the channels required. */
172 /* SCI0 - Main serial interface */
173 if(TXBufferInUseFlags & COM_SET_SCI0_INTERFACE_ID){
174 /* Copy numbers to interface specific vars */
175 TXPacketLengthToSendSCI0 = TXPacketLengthToSend;
176 TXPacketLengthToSendCAN0 = TXPacketLengthToSend;
178 /* Queue preamble by clearing and then setting transmit enable */
179 /* See section 11.4.5.2 of the xdp512 specification document */
180 //SCI0CR2 &= SCICR2_TX_DISABLE;
181 //SCI0CR2 |= SCICR2_TX_ENABLE;
183 /* Initiate transmission */
184 SCI0DRL = START_BYTE;
185 while(!(SCI0SR1 & 0x80)){/* Wait for ever until able to send then move on */}
186 SCI0DRL = START_BYTE; // nasty hack that works... means at least one and most 2 starts are sent so stuff works, but is messy... there must be a better way.
188 /* Note : Order Is Important! */
189 /* TX empty flag is already set, so we must clear it by writing out before enabling the interrupt */
190 SCI0CR2 |= SCICR2_TX_ISR_ENABLE;
192 /* CAN0 - Main CAN interface */
193 if(TXBufferInUseFlags & COM_SET_CAN0_INTERFACE_ID){
194 // just clear up front for now
195 TXBufferInUseFlags &= COM_CLEAR_CAN0_INTERFACE_ID;
197 /* spare2 */
198 if(TXBufferInUseFlags & COM_SET_SPARE2_INTERFACE_ID){
199 // just clear up front for now
200 TXBufferInUseFlags &= COM_CLEAR_SPARE2_INTERFACE_ID;
202 /* spare3 */
203 if(TXBufferInUseFlags & COM_SET_SPARE3_INTERFACE_ID){
204 // just clear up front for now
205 TXBufferInUseFlags &= COM_CLEAR_SPARE3_INTERFACE_ID;
207 /* spare4 */
208 if(TXBufferInUseFlags & COM_SET_SPARE4_INTERFACE_ID){
209 // just clear up front for now
210 TXBufferInUseFlags &= COM_CLEAR_SPARE4_INTERFACE_ID;
212 /* spare5 */
213 if(TXBufferInUseFlags & COM_SET_SPARE5_INTERFACE_ID){
214 // just clear up front for now
215 TXBufferInUseFlags &= COM_CLEAR_SPARE5_INTERFACE_ID;
217 /* spare6 */
218 if(TXBufferInUseFlags & COM_SET_SPARE6_INTERFACE_ID){
219 // just clear up front for now
220 TXBufferInUseFlags &= COM_CLEAR_SPARE6_INTERFACE_ID;
222 /* spare7 */
223 if(TXBufferInUseFlags & COM_SET_SPARE7_INTERFACE_ID){
224 // just clear up front for now
225 TXBufferInUseFlags &= COM_CLEAR_SPARE7_INTERFACE_ID;
230 /** @brief Decode a packet and respond
232 * This is the core function that controls which functionality is run when a
233 * packet is received in full by the ISR code and control is passed back to the
234 * main loop code. The vast majority of communications action happens here.
236 * @author Fred Cooke
238 void decodePacketAndRespond(){
239 /* Extract and build up the header fields */
240 RXBufferCurrentPosition = (unsigned char*)&RXBuffer;
241 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
243 /* Initialised here such that override is possible */
244 TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer;
245 TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer;
247 /* Start this off as full packet length and build down to the actual length */
248 RXCalculatedPayloadLength = RXPacketLengthReceived;
250 /* Grab the RX header flags out of the RX buffer */
251 RXHeaderFlags = *RXBufferCurrentPosition;
252 RXBufferCurrentPosition++;
253 RXCalculatedPayloadLength--;
255 /* Flag that we are transmitting! */
256 TXBufferInUseFlags |= COM_SET_SCI0_INTERFACE_ID;
257 // SCI0 only for now...
259 /* Load a blank header into the TX buffer ready for masking */
260 TXHeaderFlags = TXBufferCurrentPositionHandler;
261 *TXHeaderFlags = 0;
262 TXBufferCurrentPositionHandler++;
264 /* Grab the payload ID for processing and load the return ID */
265 RXHeaderPayloadID = *((unsigned short*)RXBufferCurrentPosition);
266 *((unsigned short*)TXBufferCurrentPositionHandler) = RXHeaderPayloadID + 1;
267 RXBufferCurrentPosition += 2;
268 TXBufferCurrentPositionHandler += 2;
269 RXCalculatedPayloadLength -= 2;
271 /* Check that the length is sufficient for the fields configured. Packets
272 * that are too long will be caught and rejected on an individual payload
273 * ID basis as the information required to handle that is not available at
274 * this point. Packets that are too short are rejected immediately!
276 if(((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 7))
277 || ((RXHeaderFlags & HEADER_HAS_LENGTH) && (RXPacketLengthReceived < 6))
278 || ((RXHeaderFlags & HEADER_HAS_SEQUENCE) && (RXPacketLengthReceived < 5))){
279 finaliseAndSend(packetTooShortForSpecifiedFields);
280 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
281 return;
284 /* Subtract checksum to get final length */
285 RXCalculatedPayloadLength--;
287 if(RXHeaderFlags & HEADER_HAS_SEQUENCE){
288 *TXBufferCurrentPositionHandler = *RXBufferCurrentPosition;
289 RXBufferCurrentPosition++;
290 TXBufferCurrentPositionHandler++;
291 RXCalculatedPayloadLength--;
292 *TXHeaderFlags |= HEADER_HAS_SEQUENCE;
295 if(RXHeaderFlags & HEADER_HAS_LENGTH){
296 RXHeaderPayloadLength = *((unsigned short*)RXBufferCurrentPosition);
297 RXBufferCurrentPosition += 2;
298 RXCalculatedPayloadLength -= 2;
299 /* Already subtracted one for checksum */
300 if(RXHeaderPayloadLength != RXCalculatedPayloadLength){
301 finaliseAndSend(payloadLengthHeaderMismatch);
302 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
303 return;
307 /* Calculate the position of the end of the stored packet for later use as a buffer */
308 void* leftOverBuffer = (void*)((unsigned short)&RXBuffer + RXPacketLengthReceived);
310 unsigned short errorID = 0;
311 /* This is where all the communication logic resides.
313 * Please Note: Length and it's flag should be set by each return packet
314 * type handler if required or desired. If an ack has been requested,
315 * ensure the negative ack flag is set if the operation failed.
317 switch (RXHeaderPayloadID){
318 // FreeEMS Core Comms Interface cases
319 case requestInterfaceVersion:
321 if(RXCalculatedPayloadLength != 0){
322 errorID = payloadLengthTypeMismatch;
323 break;
326 /* This type must have a length field, set that up */
327 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(interfaceVersion);
328 *TXHeaderFlags |= HEADER_HAS_LENGTH;
329 TXBufferCurrentPositionHandler += 2;
330 /* Load the body into place */
331 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&interfaceVersion, sizeof(interfaceVersion));
332 TXBufferCurrentPositionHandler += sizeof(interfaceVersion);
333 break;
335 case requestFirmwareVersion:
337 if(RXCalculatedPayloadLength != 0){
338 errorID = payloadLengthTypeMismatch;
339 break;
341 /* This type must have a length field, set that up */
342 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(firmwareVersion);
343 *TXHeaderFlags |= HEADER_HAS_LENGTH;
344 TXBufferCurrentPositionHandler += 2;
345 /* Load the body into place */
346 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&firmwareVersion, sizeof(firmwareVersion));
347 TXBufferCurrentPositionHandler += sizeof(firmwareVersion);
348 break;
350 case requestMaxPacketSize:
352 if(RXCalculatedPayloadLength != 0){
353 errorID = payloadLengthTypeMismatch;
354 break;
356 /* Load the size into place */
357 *((unsigned short*)TXBufferCurrentPositionHandler) = RX_BUFFER_SIZE;
358 TXBufferCurrentPositionHandler += 2;
359 break;
361 case requestEchoPacketReturn:
363 /* This type must have a length field, set that up */
364 *((unsigned short*)TXBufferCurrentPositionHandler) = RXPacketLengthReceived;
365 *TXHeaderFlags |= HEADER_HAS_LENGTH;
366 TXBufferCurrentPositionHandler += 2;
367 /* Load the body into place */
368 memcpy((void*)TXBufferCurrentPositionHandler, (void*)&RXBuffer, RXPacketLengthReceived);
369 /* Note, there is no overflow check here because the TX buffer is slightly */
370 /* bigger than the RX buffer and there is overflow checking for receives anyway. */
371 TXBufferCurrentPositionHandler += RXPacketLengthReceived;
372 break;
374 case requestSoftSystemReset:
376 if(RXCalculatedPayloadLength != 0){
377 errorID = payloadLengthTypeMismatch;
378 break;
380 /* Perform soft system reset */
381 _start();
383 case requestHardSystemReset:
385 if(RXCalculatedPayloadLength != 0){
386 errorID = payloadLengthTypeMismatch;
387 break;
390 /* This is how the serial monitor does it. */
391 COPCTL = 0x01; /* Arm with shortest time */
392 ARMCOP = 0xFF; /* Write bad value, should cause immediate reset */
393 /* Using _start() only resets the app ignoring the monitor switch. It does not work */
394 /* properly because the location of _start is not the master reset vector location. */
396 case requestReInitOfSystem:
398 if(RXCalculatedPayloadLength != 0){
399 errorID = payloadLengthTypeMismatch;
400 break;
403 init();
404 break;
406 // FreeEMS Vanilla Firmware Specific cases
407 case clearCountersAndFlagsToZero:
409 unsigned short zeroCounter;
410 unsigned char* counterPointer = (char*) &Counters;
411 for(zeroCounter = 0;zeroCounter < sizeof(Counter);zeroCounter++){
412 *counterPointer = 0;
413 counterPointer++;
415 KeyUserDebugs.flaggableFlags = 0;
416 unsigned char* flaggablePointer = (char*) &Flaggables;
417 for(zeroCounter = 0;zeroCounter < sizeof(Flaggable);zeroCounter++){
418 *flaggablePointer = 0;
419 flaggablePointer++;
421 break;
423 case requestDecoderName:
424 case requestFirmwareBuildDate:
425 case requestCompilerVersion:
426 case requestOperatingSystem:
428 /// @todo TODO add this call to the documentation, John maybe?
429 if(RXCalculatedPayloadLength != 0){
430 errorID = payloadLengthTypeMismatch;
431 break;
434 unsigned char* stringToSend = 0;
435 switch (RXHeaderPayloadID) {
436 case requestDecoderName:
437 stringToSend = (unsigned char*)decoderName;
438 break;
439 case requestFirmwareBuildDate:
440 stringToSend = (unsigned char*)buildTimeAndDate;
441 break;
442 case requestCompilerVersion:
443 stringToSend = (unsigned char*)compilerVersion;
444 break;
445 case requestOperatingSystem:
446 stringToSend = (unsigned char*)operatingSystem;
447 break;
449 /* This type must have a length field, set that up and load the body into place at the same time */
450 *((unsigned short*)TXBufferCurrentPositionHandler) = stringCopy((TXBufferCurrentPositionHandler + 2), stringToSend);
451 *TXHeaderFlags |= HEADER_HAS_LENGTH;
452 // Update with length field and string length.
453 TXBufferCurrentPositionHandler += 2 + *((unsigned short*)TXBufferCurrentPositionHandler);
454 break;
456 case updateBlockInRAM:
458 // Subtract six to allow for the locationID, size, offset
459 if(RXCalculatedPayloadLength < 7){
460 errorID = payloadLengthTypeMismatch;
461 break;
464 // Extract the RAM location ID
465 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
466 RXBufferCurrentPosition += 2;
468 // Extract the offset to place the data at
469 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
470 RXBufferCurrentPosition += 2;
472 // Extract the size of the data to be stored
473 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
474 RXBufferCurrentPosition += 2;
476 // Look up the memory location details
477 blockDetails details;
478 lookupBlockDetails(locationID, &details);
480 // Don't let anyone write to running variables unless we are running BenchTest firmware!
481 if((details.flags & block_is_read_only) && !(compare((char*)&decoderName, BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME)))){
482 errorID = attemptToWriteToReadOnlyBlock;
483 break;
486 // Subtract six to allow for the locationID, size, offset
487 if((RXCalculatedPayloadLength - 6) != size){
488 errorID = payloadNotEqualToSpecifiedValue;
489 break;
492 // If either of these is zero then this block is not in RAM!
493 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
494 errorID = invalidMemoryActionForID;
495 break;
498 // Check that size and offset describe a region that is not out of bounds
499 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
500 errorID = invalidSizeOffsetCombination;
501 break;
504 // Don't allow sub region manipulation where it does not make sense or is unsafe.
505 if((size != details.size) && !(details.flags & block_is_indexable)){
506 errorID = uncheckedTableManipulationNotAllowed;
507 break;
510 // Save page values for restore
511 unsigned char oldRamPage = RPAGE;
512 // Set the viewable RAM page
513 RPAGE = details.RAMPage;
515 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
517 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
518 void* bufferToCheck;
520 // For sub regions, construct an image for verification
521 if(size != details.size){
522 // Copy data from destination location to buffer
523 memcpy(leftOverBuffer, details.RAMAddress, details.size);
525 // Copy data from rx buffer to buffer over writing old data
526 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
528 bufferToCheck = leftOverBuffer;
529 }else{
530 bufferToCheck = RXBufferCurrentPosition;
533 // Verify all tables
534 if(details.flags & block_is_main_table){
535 errorID = validateMainTable((mainTable*)bufferToCheck);
536 }else if(details.flags & block_is_2dus_table){
537 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
538 }// TODO add other table types here
540 // If the validation failed, report it
541 if(errorID != 0){
542 break;
546 // Copy from the RX buffer to the block of RAM
547 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
549 // Check that the write was successful
550 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
552 // Restore the original RAM and flash pages
553 RPAGE = oldRamPage;
555 if(index != 0){
556 errorID = MEMORY_WRITE_ERROR;
558 break;
560 case updateBlockInFlash:
562 // Subtract six to allow for the locationID, size, offset
563 if(RXCalculatedPayloadLength < 7){
564 errorID = payloadLengthTypeMismatch;
565 break;
568 // Extract the RAM location ID
569 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
570 RXBufferCurrentPosition += 2;
572 // Extract the offset to place the data at
573 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
574 RXBufferCurrentPosition += 2;
576 // Extract the size of the data to be stored
577 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
578 RXBufferCurrentPosition += 2;
580 // Look up the memory location details
581 blockDetails details;
582 lookupBlockDetails(locationID, &details);
584 // Subtract six to allow for the locationID, size, offset
585 if((RXCalculatedPayloadLength - 6) != size){
586 errorID = payloadNotEqualToSpecifiedValue;
587 break;
590 // If either of these is zero then this block is not in flash!
591 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
592 errorID = invalidMemoryActionForID;
593 break;
596 // Check that size and offset describe a region that is not out of bounds
597 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
598 errorID = invalidSizeOffsetCombination;
599 break;
602 // Don't allow sub region manipulation where it does not make sense or is unsafe.
603 if((size != details.size) && !(details.flags & block_is_indexable)){
604 errorID = uncheckedTableManipulationNotAllowed;
605 break;
608 /// TODO @todo factor this out into validation delegation function once the number of types increases somewhat
610 if((details.flags & block_is_main_table) || (details.flags & block_is_2dus_table)){
611 void* bufferToCheck;
613 // For sub regions, construct an image for verification
614 if(size != details.size){
615 /* Save page value for restore and set the visible page */
616 unsigned char oldFlashPage = PPAGE;
617 PPAGE = details.FlashPage;
619 // Copy data from destination location to buffer
620 memcpy(leftOverBuffer, details.FlashAddress, details.size);
622 /* Restore the original flash page */
623 PPAGE = oldFlashPage;
625 // Copy data from rx buffer to buffer over writing old data
626 memcpy(leftOverBuffer + offset, RXBufferCurrentPosition, size);
628 bufferToCheck = leftOverBuffer;
629 }else{
630 bufferToCheck = RXBufferCurrentPosition;
633 // Verify all tables
634 if(details.flags & block_is_main_table){
635 errorID = validateMainTable((mainTable*)bufferToCheck);
636 }else if(details.flags & block_is_2dus_table){
637 errorID = validateTwoDTable((twoDTableUS*)bufferToCheck);
638 }// TODO add other table types here
640 // If the validation failed, report it
641 if(errorID != 0){
642 break;
646 /* Copy the flash details and populate the RAM details with the buffer location */
647 blockDetails burnDetails;
648 burnDetails.FlashPage = details.FlashPage;
649 burnDetails.FlashAddress = details.FlashAddress + offset;
650 burnDetails.RAMPage = RPAGE;
651 burnDetails.RAMAddress = RXBufferCurrentPosition;
652 burnDetails.size = size;
654 /* Copy from the RX buffer to the block of flash */
655 errorID = writeBlock(&burnDetails, leftOverBuffer);
656 if(errorID != 0){
657 break;
660 /* If present in RAM, update that too */
661 if((details.RAMPage != 0) && (details.RAMAddress != 0)){
662 /* Save page values for restore */
663 unsigned char oldRamPage = RPAGE;
664 /* Set the viewable RAM page */
665 RPAGE = details.RAMPage;
667 /* Copy from the RX buffer to the block of RAM */
668 memcpy((unsigned char*)(details.RAMAddress + offset), RXBufferCurrentPosition, size);
670 /* Check that the write was successful */
671 unsigned char index = compare(RXBufferCurrentPosition, (unsigned char*)(details.RAMAddress + offset), size);
673 /* Restore the original RAM and flash pages */
674 RPAGE = oldRamPage;
676 if(index != 0){
677 errorID = MEMORY_WRITE_ERROR;
681 break;
683 case retrieveBlockFromRAM:
685 if(RXCalculatedPayloadLength != 6){
686 errorID = payloadLengthTypeMismatch;
687 break;
690 // Extract the RAM location ID
691 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
692 RXBufferCurrentPosition += 2;
694 // Extract the offset to place the data at
695 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
696 RXBufferCurrentPosition += 2;
698 // Extract the size of the data to be stored
699 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
700 RXBufferCurrentPosition += 2;
702 /* Look up the memory location details */
703 blockDetails details;
704 lookupBlockDetails(locationID, &details);
706 if((details.RAMPage == 0) || (details.RAMAddress == 0)){
707 errorID = invalidMemoryActionForID;
708 break;
711 // Special behaviour for size of zero which returns the whole block
712 if((size == 0) && (offset == 0)){
713 size = details.size;
716 // Check that size and offset describe a region that is not out of bounds
717 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
718 errorID = invalidSizeOffsetCombination;
719 break;
722 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
723 if((size != details.size) && !(details.flags & block_is_indexable)){
724 errorID = doesNotMakeSenseToRetrievePartially;
725 break;
728 // This type must have a length field, set that up
729 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
730 *TXHeaderFlags |= HEADER_HAS_LENGTH;
731 TXBufferCurrentPositionHandler += 2;
733 /* Save page value for restore and set the visible page */
734 unsigned char oldRamPage = RPAGE;
735 RPAGE = details.RAMPage;
737 /* Copy the block of RAM to the TX buffer */
738 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.RAMAddress + offset), size);
739 TXBufferCurrentPositionHandler += size;
741 /* Restore the original RAM and flash pages */
742 RPAGE = oldRamPage;
744 break;
746 case retrieveBlockFromFlash:
748 if(RXCalculatedPayloadLength != 6){
749 errorID = payloadLengthTypeMismatch;
750 break;
753 // Extract the RAM location ID
754 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
755 RXBufferCurrentPosition += 2;
757 // Extract the offset to place the data at
758 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
759 RXBufferCurrentPosition += 2;
761 // Extract the size of the data to be stored
762 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
763 RXBufferCurrentPosition += 2;
765 /* Look up the memory location details */
766 blockDetails details;
767 lookupBlockDetails(locationID, &details);
769 if((details.FlashPage == 0) || (details.FlashAddress == 0)){
770 errorID = invalidMemoryActionForID;
771 break;
774 // Special behaviour for size of zero which returns the whole block
775 if((size == 0) && (offset == 0)){
776 size = details.size;
779 // Check that size and offset describe a region that is not out of bounds
780 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
781 errorID = invalidSizeOffsetCombination;
782 break;
785 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
786 if((size != details.size) && !(details.flags & block_is_indexable)){
787 errorID = doesNotMakeSenseToRetrievePartially;
788 break;
791 // This type must have a length field, set that up
792 *((unsigned short*)TXBufferCurrentPositionHandler) = size;
793 *TXHeaderFlags |= HEADER_HAS_LENGTH;
794 TXBufferCurrentPositionHandler += 2;
796 /* Save page value for restore and set the visible page */
797 unsigned char oldFlashPage = PPAGE;
798 PPAGE = details.FlashPage;
800 /* Copy the block of flash to the TX buffer */
801 memcpy(TXBufferCurrentPositionHandler, (unsigned char*)(details.FlashAddress + offset), size);
802 TXBufferCurrentPositionHandler += size;
804 /* Restore the original RAM and flash pages */
805 PPAGE = oldFlashPage;
807 break;
809 case burnBlockFromRamToFlash:
811 if(RXCalculatedPayloadLength != 6){
812 errorID = payloadLengthTypeMismatch;
813 break;
816 // Extract the RAM location ID
817 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
818 RXBufferCurrentPosition += 2;
820 // Extract the offset to place the data at
821 unsigned short offset = *((unsigned short*)RXBufferCurrentPosition);
822 RXBufferCurrentPosition += 2;
824 // Extract the size of the data to be stored
825 unsigned short size = *((unsigned short*)RXBufferCurrentPosition);
826 RXBufferCurrentPosition += 2;
828 /* Look up the memory location details */
829 blockDetails details;
830 lookupBlockDetails(locationID, &details);
832 /* Check that all data we need is present */
833 if((details.RAMPage == 0) || (details.RAMAddress == 0) || (details.FlashPage == 0) || (details.FlashAddress == 0)){
834 errorID = invalidMemoryActionForID;
835 break;
838 // Check that size and offset describe a region that is not out of bounds
839 if((size == 0) || (offset > (details.size - 1)) || (size > (details.size - offset))){
840 errorID = invalidSizeOffsetCombination;
841 break;
844 // Don't allow sub region retrieval where it does not make sense or is unsafe. (keep it symmetric for djandruczyk)
845 if((size != details.size) && !(details.flags & block_is_indexable)){
846 errorID = doesNotMakeSenseToRetrievePartially;
847 break;
851 // adjust details block to feed to represent the subsection of ram and flash that we want to burn down.
852 details.RAMAddress += offset;
853 details.FlashAddress += offset;
854 details.size = size;
856 /* Write the block down from RAM to Flash */
857 errorID = writeBlock(&details, leftOverBuffer);
858 break;
860 case requestDatalogPacket: // Set type through standard configuration methods
862 if((RXCalculatedPayloadLength > 2) || (RXCalculatedPayloadLength == 1)){
863 errorID = payloadLengthTypeMismatch;
864 break;
865 }else if(RXCalculatedPayloadLength == 2){
866 unsigned short newConfiguredLength = *((unsigned short*)RXBufferCurrentPosition);
867 if(newConfiguredLength > maxBasicDatalogLength){
868 errorID = datalogLengthExceedsMax;
869 break;
870 }else{
871 TablesB.SmallTablesB.loggingSettings.basicDatalogLength = newConfiguredLength;
873 }// fall through to use existing configured length
875 /* Set the length field up */
876 *TXHeaderFlags |= HEADER_HAS_LENGTH;
877 *(unsigned short*)TXBufferCurrentPositionHandler = TablesB.SmallTablesB.loggingSettings.basicDatalogLength;
878 TXBufferCurrentPositionHandler += 2;
880 /* Fill out the log and send */
881 populateBasicDatalog(); // TODO change this to pull type from settings and call generic populator which populates with passed in type
882 break;
884 case setAsyncDatalogType:
886 if(RXCalculatedPayloadLength != 1){
887 errorID = payloadLengthTypeMismatch;
888 break;
891 unsigned char newDatalogType = *((unsigned char*)RXBufferCurrentPosition);
892 if(newDatalogType > asyncDatalogLastType){
893 errorID = noSuchAsyncDatalogType;
894 break;
897 TablesB.SmallTablesB.loggingSettings.datalogStreamType = newDatalogType;
898 break;
900 case forwardPacketOverCAN:
902 /// perform function TODO @todo REWORK review this
903 errorID = unimplementedFunction;
904 break;
906 case forwardPacketOverOtherUART:
908 /// perform function TODO @todo REWORK review this
909 errorID = unimplementedFunction;
910 break;
912 case retrieveArbitraryMemory:
914 if(RXCalculatedPayloadLength != 6){
915 errorID = payloadLengthTypeMismatch;
916 break;
919 unsigned short length = *((unsigned short*)RXBufferCurrentPosition);
920 RXBufferCurrentPosition += 2;
921 // Make sure the buffer can handle the block
922 if(length > TX_MAX_PAYLOAD_SIZE){
923 errorID = requestedLengthTooLarge;
924 break;
927 void* address = (void*) *((unsigned short*)RXBufferCurrentPosition);
928 RXBufferCurrentPosition += 2;
929 // Ensure we don't try to read past the end of the address space
930 if(((unsigned short)address) <= ((0xFFFF - length) + 1)){
931 // TODO Possibly check and limit ranges
932 errorID = requestedAddressDisallowed;
933 break;
936 unsigned char RAMPage = *((unsigned char*)RXBufferCurrentPosition);
937 RXBufferCurrentPosition++;
938 // Ensure RAM page is valid. Being too high is not possible.
939 if(RAMPage < RPAGE_MIN){
940 errorID = requestedRAMPageInvalid;
941 break;
944 unsigned char FlashPage = *((unsigned char*)RXBufferCurrentPosition);
945 RXBufferCurrentPosition++;
946 // Ensure Flash page is valid. Being too high is not possible.
947 if(FlashPage < PPAGE_MIN){
948 errorID = requestedFlashPageInvalid;
949 break;
952 /* This type must have a length field, set that up */
953 *((unsigned short*)TXBufferCurrentPositionHandler) = length + 6;
954 *TXHeaderFlags |= HEADER_HAS_LENGTH;
955 TXBufferCurrentPositionHandler += 2;
957 /* Put the request payload into the reply */
958 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short) address;
959 TXBufferCurrentPositionHandler += 2;
960 *((unsigned short*)TXBufferCurrentPositionHandler) = length;
961 TXBufferCurrentPositionHandler += 2;
962 *((unsigned char*)TXBufferCurrentPositionHandler) = RAMPage;
963 TXBufferCurrentPositionHandler++;
964 *((unsigned char*)TXBufferCurrentPositionHandler) = FlashPage;
965 TXBufferCurrentPositionHandler++;
967 /* Load the body into place */
968 memcpy((void*)TXBufferCurrentPositionHandler, address, length);
969 TXBufferCurrentPositionHandler += length;
971 break;
973 case retrieveListOfLocationIDs:
975 if(RXCalculatedPayloadLength != 3){
976 errorID = payloadLengthTypeMismatch;
977 break;
980 // Extract the type of list that we want
981 unsigned char listType = *((unsigned char*)RXBufferCurrentPosition);
982 RXBufferCurrentPosition++;
984 // Extract the mask for the qualities that we want
985 unsigned short blockDetailsMask = *((unsigned short*)RXBufferCurrentPosition);
986 RXBufferCurrentPosition += 2;
988 // This type must have a length field, set that up
989 unsigned short * listLength = (unsigned short*)TXBufferCurrentPositionHandler;
990 *TXHeaderFlags |= HEADER_HAS_LENGTH;
991 TXBufferCurrentPositionHandler += 2;
993 // Zero the counter before we start, woops!
994 *listLength = 0;
996 unsigned long locationID;
997 blockDetails details;
998 for(locationID = 0;locationID < 65536;locationID++){
999 unsigned short locationIDDoesntExist;
1000 locationIDDoesntExist = lookupBlockDetails((unsigned short)locationID, &details);
1002 if(!locationIDDoesntExist){
1003 if((listType == 0x00) || // get all
1004 ((listType == 0x01) && (details.flags & blockDetailsMask)) || // get OR of bits
1005 ((listType == 0x02) && (!(~(details.flags) & blockDetailsMask)))){ // get AND of bits
1006 *((unsigned short*)TXBufferCurrentPositionHandler) = (unsigned short)locationID;
1007 TXBufferCurrentPositionHandler += 2;
1008 *listLength += 2;
1013 break;
1015 case retrieveLocationIDDetails:
1017 if(RXCalculatedPayloadLength != 2){
1018 errorID = payloadLengthTypeMismatch;
1019 break;
1022 // Extract the RAM location ID
1023 unsigned short locationID = *((unsigned short*)RXBufferCurrentPosition);
1024 RXBufferCurrentPosition += 2;
1026 // This type must have a length field, set that up
1027 *((unsigned short*)TXBufferCurrentPositionHandler) = sizeof(blockDetails);
1028 *TXHeaderFlags |= HEADER_HAS_LENGTH;
1029 TXBufferCurrentPositionHandler += 2;
1031 // Write straight to output buffer to save time/code
1032 errorID = lookupBlockDetails(locationID, (blockDetails*)TXBufferCurrentPositionHandler);
1034 if(errorID != 0){
1035 break;
1038 // Adjust TX buffer position if successful
1039 TXBufferCurrentPositionHandler += sizeof(blockDetails);
1041 break;
1043 case requestUnitTestOverSerial:
1046 * The idea here is to call this function with arguments, and data
1047 * and have the result sent back for comparison with an expected
1048 * result that isn't divulged to the firmware.
1050 * It is intended that all testable functions be callable through
1051 * this mechanism and that any number of test executions can be
1052 * performed by an external suite using different parameters and
1053 * data sets and matching expected results.
1055 * The usual error mechanism shall be used to indicate some sort of
1056 * either internal or test failure and returned errors shall be
1057 * suitably descriptive to allow diagnosis and fixing of issues.
1060 // Must at least have test ID
1061 if(RXCalculatedPayloadLength < 2){
1062 errorID = payloadLengthTypeMismatch;
1063 break;
1066 // grab unit test ID from payload
1067 unsigned short unitTestID = *((unsigned short*)RXBufferCurrentPosition);
1068 RXBufferCurrentPosition += 2;
1070 switch(unitTestID){
1071 case testEmptyTest:
1073 // Must be only the ID
1074 if(RXCalculatedPayloadLength != 2){
1075 errorID = payloadShorterThanRequiredForTest;
1076 break;
1079 *((unsigned short*)TXBufferCurrentPositionHandler) = unitTestID;
1080 TXBufferCurrentPositionHandler +=2;
1082 break;
1084 case testTwoDTableUSLookup:
1086 // ID + Value + Table
1087 if(RXCalculatedPayloadLength != (2 + 2 + sizeof(twoDTableUS))){
1088 errorID = payloadShorterThanRequiredForTest;
1089 break;
1092 unsigned short Value = *((unsigned short*)RXBufferCurrentPosition);
1093 RXBufferCurrentPosition += 2;
1095 twoDTableUS* Table = ((twoDTableUS*)RXBufferCurrentPosition);
1096 RXBufferCurrentPosition += sizeof(twoDTableUS);
1098 unsigned short result = lookupTwoDTableUS(Table, Value);
1100 *((unsigned short*)TXBufferCurrentPositionHandler) = result;
1101 TXBufferCurrentPositionHandler +=2;
1103 break;
1105 // http://issues.freeems.org/view.php?id=156
1107 /// TODO @todo test all things listed below:
1108 // lookupPagedMainTableCellValue - pass this RPAGE so that it remains unchanged
1109 // validateMainTable
1110 // validateTwoDTable
1111 // set table values - leave this till last, currently unused by mtx, likely to be removed anyway
1112 // generateDerivedVars - convert to pointers, remove headers, privatise a lot of data!
1113 // calculateFuelAndIgnition - ditto
1114 // scheduling algorithm - ditto
1115 // safeAdd
1116 // safeTrim
1117 // safeScale
1118 // sleep (milliseconds)
1119 // sleepMicro (microseconds)
1120 // checksum
1121 // stringCopy
1122 // compare
1123 // 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)
1124 // init code may be able to be partially checked
1125 // most other code at this stage is ISR code, flash writing code, or could interfere with the running of the engine
1126 // more testable code will appear with time, such as the HAL layer, and most accessory functions.
1127 default:
1129 errorID = noSuchUnitTestID;
1132 // each case:
1133 // checks length, fails if wrong
1134 // parses data into args
1135 // calls function on data/args
1136 // assembles response OR sets error
1137 // breaks
1139 break;
1141 case startBenchTestSequence:
1143 // see TODO on include at top and modify this line appropriately
1144 if(!(compare((char*)&decoderName, BENCH_TEST_NAME, sizeof(BENCH_TEST_NAME)))){
1145 if(RXCalculatedPayloadLength < 1){
1146 errorID = payloadLengthTypeMismatch;
1147 break;
1150 unsigned char localTestMode = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1151 RXBufferCurrentPosition++;
1152 if(localTestMode > TEST_MODE_BUMP_UP_CYCLES){
1153 errorID = unimplementedTestMode;
1154 break;
1155 }else if((localTestMode == TEST_MODE_STOP) && (RXCalculatedPayloadLength == 1)){
1156 if(!(coreStatusA & BENCH_TEST_ON)){
1157 errorID = benchTestNotRunningToStop;
1158 break;
1161 // Ensure we succeed at stopping it as quickly as possible.
1162 ATOMIC_START();
1163 KeyUserDebugs.currentEvent = testEventsPerCycle - 1; // Gets incremented then compared with testEventsPerCycle
1164 testNumberOfCycles = 1; // Gets decremented then compared with zero
1165 ATOMIC_END();
1167 // eventually save and return where it got to
1168 break;
1169 }else if((localTestMode == TEST_MODE_BUMP_UP_CYCLES) && (RXCalculatedPayloadLength == 2)){
1170 if(!(coreStatusA & BENCH_TEST_ON)){
1171 errorID = benchTestNotRunningToBump;
1172 break;
1175 // Get bump value from payload
1176 unsigned char bumpCycles = *((unsigned char*)RXBufferCurrentPosition); //1; // The only mode, for now.
1177 RXBufferCurrentPosition++;
1179 if(bumpCycles == 0){
1180 errorID = bumpingByZeroMakesNoSense;
1181 break;
1184 // Bump count by value from payload
1185 testNumberOfCycles += bumpCycles;
1186 // Given that this function is only for situations when A it's getting near to
1187 // zero and B the user is watching, not checking for overflow is reasonable.
1188 break;
1189 }else if((localTestMode == TEST_MODE_ITERATIONS) && (RXCalculatedPayloadLength == 24)){
1190 testMode = localTestMode;
1191 // do nothing to fall through, or move other code into here
1192 }else{
1193 errorID = packetSizeWrongForTestMode;
1194 break;
1197 if(coreStatusA & BENCH_TEST_ON){
1198 errorID = benchTestAlreadyRunning;
1199 break;
1200 }else{
1201 coreStatusA |= BENCH_TEST_ON;
1204 testEventsPerCycle = *((unsigned char*)RXBufferCurrentPosition); //100; // @ 10ms = 1s
1205 RXBufferCurrentPosition++;
1206 if(testEventsPerCycle == 0){
1207 errorID = invalidEventsPerCycle;
1208 break;
1211 testNumberOfCycles = *((unsigned short*)RXBufferCurrentPosition); //20; // @ 1s = 20s
1212 RXBufferCurrentPosition += 2;
1213 if(testNumberOfCycles == 0){
1214 errorID = invalidNumberOfCycles;
1215 break;
1218 testTicksPerEvent = *((unsigned short*)RXBufferCurrentPosition); //12500; // @ 0.8us = 10ms
1219 RXBufferCurrentPosition += 2;
1220 if(testTicksPerEvent < decoderMaxCodeTime){
1221 errorID = tooShortOfAnEventPeriod;
1222 break;
1225 // Pluck the arrays out of the packet for the loop below
1226 unsigned char* testEventNumbers = RXBufferCurrentPosition;
1227 RXBufferCurrentPosition += 6;
1228 unsigned short* testPulseWidths = (unsigned short*)RXBufferCurrentPosition;
1229 RXBufferCurrentPosition += 12;
1231 // Reset the clock for reading timeout
1232 Clocks.timeoutADCreadingClock = 0; // make this optional, such that we can use real inputs to determine pw and/or dwell.
1234 // Validate and transfer the per-channel data
1235 unsigned char channel;
1236 unsigned char configuredChannels = 6;
1237 for(channel = 0;channel < 6;channel++){
1238 if(testPulseWidths[channel] > injectorSwitchOnCodeTime){ // See next block for warning.
1239 // use as-is
1240 outputEventPinNumbers[channel] = channel;
1241 postReferenceEventDelays[channel] = decoderMaxCodeTime;
1242 injectorMainPulseWidthsMath[channel] = testPulseWidths[channel];
1243 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1244 }else if(testPulseWidths[channel] > 2){
1245 // less than the code time, and not special, error!
1246 errorID = tooShortOfAPulseWidthToTest;
1247 // Warning, PWs close to this could be slightly longer than requested, that will change in later revisions.
1248 break;
1249 }else if(testPulseWidths[channel] == 2){
1250 // use the dwell from the core maths and input vars.
1251 outputEventPinNumbers[channel] = channel;
1252 postReferenceEventDelays[channel] = decoderMaxCodeTime;
1253 injectorMainPulseWidthsMath[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 outputEventPinNumbers[channel] = channel;
1258 postReferenceEventDelays[channel] = decoderMaxCodeTime;
1259 injectorMainPulseWidthsMath[channel] = DerivedVars->RefPW;
1260 outputEventInputEventNumbers[channel] = testEventNumbers[channel];
1261 }else{ // is zero
1262 // Set this channel to zero for and therefore off, don't set this channel.
1263 outputEventInputEventNumbers[channel] = 0xFF; // Off.
1264 configuredChannels--;
1268 if(configuredChannels == 0){
1269 errorID = noChannelsConfiguredToTest;
1270 break;
1273 if(errorID == 0){
1274 // Let the first iteration roll it over to zero.
1275 KeyUserDebugs.currentEvent = 0xFF; // Needs to be here in case of multiple runs, init is not sufficient
1277 // Trigger decoder interrupt to fire thus starting the loop!
1278 TIE = 0x01; // The ISR does the rest!
1279 }else{
1280 break;
1284 /* http://issues.freeems.org/view.php?id=155
1286 * The following block has been left in, as I still do not know why it won't work as intended:
1288 * - It should fire all 6 output pins with a 52ms duration pulse, exactly once.
1289 * - 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
1290 * - The interrupts run, but the pin doesn't change state, despite the registers being configured correctly
1292 * I've tried quite a bit:
1294 * - Moving this code around
1295 * - Checking memory definitions
1296 * - Completely rewriting the output ISR
1297 * - Adding significant debug to output ISR
1298 * - Checking for register contents in output ISR
1299 * - Checking for key things modified in this file
1300 * - General head scratching and confused searching
1303 // outputEventPinNumbers[0] = 0; // 1 ign
1304 // outputEventPinNumbers[1] = 1; // 2 ign
1305 // outputEventPinNumbers[2] = 2; // 3 ign/1 fuel
1306 // outputEventPinNumbers[3] = 3; // 4 ign/2 fuel
1307 // outputEventPinNumbers[4] = 4; // 3 fuel
1308 // outputEventPinNumbers[5] = 5; // 4 fuel
1309 // postReferenceEventDelays[0] = decoderMaxCodeTime;
1310 // postReferenceEventDelays[1] = decoderMaxCodeTime;
1311 // postReferenceEventDelays[2] = decoderMaxCodeTime;
1312 // postReferenceEventDelays[3] = decoderMaxCodeTime;
1313 // postReferenceEventDelays[4] = decoderMaxCodeTime;
1314 // postReferenceEventDelays[5] = decoderMaxCodeTime;
1315 // injectorMainPulseWidthsMath[0] = SHORTMAX;
1316 // injectorMainPulseWidthsMath[1] = SHORTMAX;
1317 // injectorMainPulseWidthsMath[2] = SHORTMAX;
1318 // injectorMainPulseWidthsMath[3] = SHORTMAX;
1319 // injectorMainPulseWidthsMath[4] = SHORTMAX;
1320 // injectorMainPulseWidthsMath[5] = SHORTMAX;
1322 // unsigned short edgeTimeStamp = TCNT;
1323 // // call sched output with args
1324 // LongTime timeStamp;
1325 // /* Install the low word */
1326 // timeStamp.timeShorts[1] = edgeTimeStamp;
1327 // /* Find out what our timer value means and put it in the high word */
1328 // if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
1329 // timeStamp.timeShorts[0] = timerExtensionClock + 1;
1330 // }else{
1331 // timeStamp.timeShorts[0] = timerExtensionClock;
1332 // }
1334 // schedulePortTPin(0, timeStamp);
1335 // schedulePortTPin(1, timeStamp);
1336 // schedulePortTPin(2, timeStamp);
1337 // schedulePortTPin(3, timeStamp);
1338 // schedulePortTPin(4, timeStamp);
1339 // schedulePortTPin(5, timeStamp);
1341 // sleep(1000);
1342 }else{
1343 errorID = thisIsNotTheBenchTestDecoder;
1345 break;
1347 default:
1349 if((RXHeaderPayloadID % 2) == 1){
1350 errorID = invalidPayloadID;
1351 }else{
1352 errorID = unrecognisedPayloadID;
1357 // Always reply, if errorID is zero it's just an ack.
1358 finaliseAndSend(errorID);
1360 /* Switch reception back on now that we are done with the received data */
1361 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
1365 /** @brief Send an error if buffer free
1367 * This is a wrapper for use outside the communication handler function. The error will only be sent if the buffer is empty and available, if not, it will be discarded.
1369 * @author Fred Cooke
1371 * @warning Use of this function signifies that the error you are trying to propagate is not urgent and can be forgotten.
1373 * @note Consider not throwing an error if it seems appropriate to use this.
1375 * @todo TODO this is only used in coreVarGen, such errors should be caught at init time, NOT runtime, fix that...
1377 * @param errorID is the error ID to be passed out to listening devices.
1379 void sendErrorIfClear(unsigned short errorID){
1380 if(!TXBufferInUseFlags){
1381 TXBufferInUseFlags = ONES;
1382 sendErrorInternal(errorID);
1383 }else{
1384 FLAG_AND_INC_FLAGGABLE(FLAG_COMMS_ERROR_MESSAGES_NOT_SENT_OFFSET);
1389 /* not currently used...
1390 * @brief Send an error even if we must wait
1392 * This is a wrapper for use outside the communication handler function. This
1393 * function will block until the error is able to be sent. This behaviour is
1394 * not recommended as it will interfere with engine operation somewhat.
1396 * @author Fred Cooke
1398 * @warning Use of this function signifies that the error you are trying to propagate is extremely urgent and can not be forgotten.
1400 * @note Using this function blocks other main loop code from execution. Consider handling the error in another way if it seems appropriate to use this.
1402 * @param errorID is the error ID to be passed out to listening devices.
1404 //void sendErrorBusyWait(unsigned short errorID){
1405 // while(TXBufferInUseFlags){} /* Wait till clear to send */
1406 // TXBufferInUseFlags = ONES;
1407 // sendErrorInternal(errorID);
1411 /** @brief Send an error
1413 * This function is only for use inside the communication handling function.
1414 * Use of it outside this environment is not supported and behaviour when used
1415 * as such is undefined.
1417 * @author Fred Cooke
1419 * @warning ONLY use this function from within the communication handler.
1421 * @see sendErrorIfClear()
1422 * @see sendErrorBusyWait()
1424 * @todo TODO clean up the mess of commented out crap in here!
1425 * @todo TODO decide on errorCode or errorID and consistencise it everywhere.
1427 * @param errorID is the error ID to be passed out to listening devices.
1429 void sendErrorInternal(unsigned short errorID){
1430 // set buffer in use, consider blocking interrupts to do this cleanly
1433 // TXBufferInUseFlags = 0;
1434 /* No need for atomic block here as one of two conditions will always be */
1435 /* true when calling this. Either we have been flagged to receive and */
1436 /* decode a packet, or we are in an ISR. In either case it is safe to */
1437 /* check the flags and initiate the sequence if they are clear. */
1438 // if(RXTXSerialStateFlags & TX_IN_PROGRESS){
1439 /* It's OK to return without resetting as it will be done by */
1440 /* either of those processes if they are underway. The other */
1441 /* processes are not overridden because they have priority. */
1442 // return;
1443 // }else{ /* Turn off reception */
1444 /* It's OK to turn this off if nothing was currently being received */
1445 // SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
1446 // SCI0CR2 &= SCICR2_RX_DISABLE;
1448 /* Build up the packet */
1449 /* Set the pointer to the start */
1450 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
1451 /* Set the length */
1452 // TXPacketLengthToSend = 5; /* Flags + Payload ID + Error Code */
1453 // Flags = empty
1454 *TXBufferCurrentPositionHandler = 0x00;
1455 TXBufferCurrentPositionHandler++;
1456 /* Set the payload ID */
1457 *((unsigned short*)TXBufferCurrentPositionHandler) = asyncErrorCodePacket;
1458 TXBufferCurrentPositionHandler += 2;
1460 finaliseAndSend(errorID);
1461 // }
1465 /** @brief Send a debug message if buffer free
1467 * This is a wrapper for use outside the communication handler function. The debug message will only be sent if the buffer is empty and available, if not, it will be discarded.
1469 * @author Fred Cooke
1471 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1473 * @param message is a pointer to the null terminated debug message string.
1475 void sendDebugIfClear(unsigned char* message){
1476 if(!TXBufferInUseFlags){
1477 TXBufferInUseFlags = ONES;
1478 sendDebugInternal(message);
1479 }else{
1480 FLAG_AND_INC_FLAGGABLE(FLAG_COMMS_DEBUG_MESSAGES_NOT_SENT_OFFSET);
1485 /** Send a debug message even if we must wait
1487 * This is a wrapper for use outside the communication handler function. This
1488 * function will block until the debug message is able to be sent.
1490 * @author Fred Cooke
1492 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1494 * @param message is a pointer to the null terminated debug message string.
1496 //void sendDebugBusyWait(unsigned char* message){
1497 // while(TXBufferInUseFlags){} /* Wait till clear to send */
1498 // TXBufferInUseFlags = ONES;
1499 // sendDebugInternal(message);
1503 /** @brief Send a debug message
1505 * Sends a null terminated debug message out on the broadcast address of all available interfaces.
1507 * @author Fred Cooke
1509 * @warning ONLY use this function from within the communication handler.
1511 * @see sendDebugIfClear()
1512 * @see sendDebugBusyWait()
1514 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1516 * @todo TODO clean up the mess of commented out crap in here!
1518 * @param message is a pointer to the null terminated debug message string.
1520 void sendDebugInternal(unsigned char* message){
1522 // set buffer in use, consider blocking interrupts to do this cleanly
1524 // if(TRUE){
1525 // Counters.serialDebugUnsentCounter++;
1526 // return;
1527 // }
1528 // wrong :
1529 /* No need for atomic block here as one of two conditions will always be */
1530 /* true when calling this. Either we have been flagged to receive and */
1531 /* decode a packet, or we are in an ISR. In either case it is safe to */
1532 /* check the flags and initiate the sequence if they are clear. */
1533 //if(RXTXSerialStateFlags & TX_IN_PROGRESS){
1534 // wrong :
1535 /* It's OK to return without resetting as it will be done by */
1536 /* either of those processes if they are underway. The other */
1537 /* processes are not overridden because they have priority. */
1538 //TXBufferInUseFlags = 0;
1539 //return;
1540 // }else{ /* Turn off reception */
1541 /* It's OK to turn this off if nothing was currently being received */
1542 // SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
1543 // SCI0CR2 &= SCICR2_RX_DISABLE;
1545 /* Build up the packet */
1546 /* Set the pointer to the start and init the length */
1547 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer;
1549 /* Load a protocol with length header into the TX buffer ready for masking */
1550 *TXBufferCurrentPositionHandler = 0x11;
1551 TXBufferCurrentPositionHandler++;
1553 /* Set the payload ID */
1554 *((unsigned short*)TXBufferCurrentPositionHandler) = asyncDebugInfoPacket;
1555 TXBufferCurrentPositionHandler += 2;
1557 /* Store the length location */
1558 unsigned short* TXLength = (unsigned short*)TXBufferCurrentPositionHandler;
1559 TXBufferCurrentPositionHandler += 2;
1561 /* Copy the string into place and record the length copied */
1562 unsigned short messageLength = stringCopy(TXBufferCurrentPositionHandler, message);
1563 *TXLength = messageLength;
1564 TXBufferCurrentPositionHandler += messageLength;
1566 finaliseAndSend(0);
1571 /* This function should be period limited to about 10 seconds internally (or by scheduler) */
1572 //void checkCountersAndSendErrors(){
1573 // compare time stamps with current time stamps and execute if old enough. (if no scheduler)
1575 // compare counters with counters cache (from last time) sending an error packet when they differ
1577 // copy counters to counters cache for next time
1579 // send errors with busy wait on the basis that all errors should be taken care of and not be sent in fairly short order?
1581 // or send with isr but just busy wait for it to finish before sending the next?
1583 // 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.
1585 // need to figure out how to queue received packets for processing when we are currently sending stuff out.
1587 // above notes don't belong here really.
1591 //void prepareDatalog(){
1592 // // send data log by default otherwise
1593 // unsigned char chunksExpected = 8; // based on configuration, yet to determine how to calculate this number
1594 // unsigned char chunksLoaded = 0;
1595 // if ((!receiving) && (datalogMask & rawVarsMask)) {
1596 // //
1597 // chunksLoaded++;
1598 // }
1599 // if ((!receiving) && (datalogMask & Mask)) {
1600 // //
1601 // chunksLoaded++;
1602 // }
1603 // if ((!receiving) && (datalogMask & Mask)) {
1604 // //
1605 // chunksLoaded++;
1606 // }
1607 // if ((!receiving) && (datalogMask & Mask)) {
1608 // //
1609 // chunksLoaded++;
1610 // }
1611 // if ((!receiving) && (datalogMask & Mask)) {
1612 // //
1613 // chunksLoaded++;
1614 // }
1615 // if ((!receiving) && (datalogMask & Mask)) {
1616 // //
1617 // chunksLoaded++;
1618 // }
1619 // if ((!receiving) && (datalogMask & Mask)) {
1620 // //
1621 // chunksLoaded++;
1622 // }
1623 // if ((!receiving) && (datalogMask & Mask)) {
1624 // //
1625 // chunksLoaded++;
1626 // }
1627 // // set the length
1628 // // the pointer should be correct already