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!
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
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"
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.
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
;
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!
105 // IO registers etc that can't be altered simply by reading from.
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
117 //logaddr = fixed.addr
120 //len = loglen OR 1 OR 2
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
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.
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
){
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
;
198 if(TXBufferInUseFlags
& COM_SET_SPARE2_INTERFACE_ID
){
199 // just clear up front for now
200 TXBufferInUseFlags
&= COM_CLEAR_SPARE2_INTERFACE_ID
;
203 if(TXBufferInUseFlags
& COM_SET_SPARE3_INTERFACE_ID
){
204 // just clear up front for now
205 TXBufferInUseFlags
&= COM_CLEAR_SPARE3_INTERFACE_ID
;
208 if(TXBufferInUseFlags
& COM_SET_SPARE4_INTERFACE_ID
){
209 // just clear up front for now
210 TXBufferInUseFlags
&= COM_CLEAR_SPARE4_INTERFACE_ID
;
213 if(TXBufferInUseFlags
& COM_SET_SPARE5_INTERFACE_ID
){
214 // just clear up front for now
215 TXBufferInUseFlags
&= COM_CLEAR_SPARE5_INTERFACE_ID
;
218 if(TXBufferInUseFlags
& COM_SET_SPARE6_INTERFACE_ID
){
219 // just clear up front for now
220 TXBufferInUseFlags
&= COM_CLEAR_SPARE6_INTERFACE_ID
;
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.
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
;
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
);
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
);
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
;
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
);
335 case requestFirmwareVersion
:
337 if(RXCalculatedPayloadLength
!= 0){
338 errorID
= payloadLengthTypeMismatch
;
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
);
350 case requestMaxPacketSize
:
352 if(RXCalculatedPayloadLength
!= 0){
353 errorID
= payloadLengthTypeMismatch
;
356 /* Load the size into place */
357 *((unsigned short*)TXBufferCurrentPositionHandler
) = RX_BUFFER_SIZE
;
358 TXBufferCurrentPositionHandler
+= 2;
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
;
374 case requestSoftSystemReset
:
376 if(RXCalculatedPayloadLength
!= 0){
377 errorID
= payloadLengthTypeMismatch
;
380 /* Perform soft system reset */
383 case requestHardSystemReset
:
385 if(RXCalculatedPayloadLength
!= 0){
386 errorID
= payloadLengthTypeMismatch
;
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
;
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
++){
415 KeyUserDebugs
.flaggableFlags
= 0;
416 unsigned char* flaggablePointer
= (char*) &Flaggables
;
417 for(zeroCounter
= 0;zeroCounter
< sizeof(Flaggable
);zeroCounter
++){
418 *flaggablePointer
= 0;
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
;
434 unsigned char* stringToSend
= 0;
435 switch (RXHeaderPayloadID
) {
436 case requestDecoderName
:
437 stringToSend
= (unsigned char*)decoderName
;
439 case requestFirmwareBuildDate
:
440 stringToSend
= (unsigned char*)buildTimeAndDate
;
442 case requestCompilerVersion
:
443 stringToSend
= (unsigned char*)compilerVersion
;
445 case requestOperatingSystem
:
446 stringToSend
= (unsigned char*)operatingSystem
;
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
);
456 case updateBlockInRAM
:
458 // Subtract six to allow for the locationID, size, offset
459 if(RXCalculatedPayloadLength
< 7){
460 errorID
= payloadLengthTypeMismatch
;
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
;
486 // Subtract six to allow for the locationID, size, offset
487 if((RXCalculatedPayloadLength
- 6) != size
){
488 errorID
= payloadNotEqualToSpecifiedValue
;
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
;
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
;
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
;
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
)){
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
;
530 bufferToCheck
= RXBufferCurrentPosition
;
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
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
556 errorID
= MEMORY_WRITE_ERROR
;
560 case updateBlockInFlash
:
562 // Subtract six to allow for the locationID, size, offset
563 if(RXCalculatedPayloadLength
< 7){
564 errorID
= payloadLengthTypeMismatch
;
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
;
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
;
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
;
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
;
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
)){
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
;
630 bufferToCheck
= RXBufferCurrentPosition
;
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
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
);
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 */
677 errorID
= MEMORY_WRITE_ERROR
;
683 case retrieveBlockFromRAM
:
685 if(RXCalculatedPayloadLength
!= 6){
686 errorID
= payloadLengthTypeMismatch
;
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
;
711 // Special behaviour for size of zero which returns the whole block
712 if((size
== 0) && (offset
== 0)){
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
;
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
;
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 */
746 case retrieveBlockFromFlash
:
748 if(RXCalculatedPayloadLength
!= 6){
749 errorID
= payloadLengthTypeMismatch
;
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
;
774 // Special behaviour for size of zero which returns the whole block
775 if((size
== 0) && (offset
== 0)){
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
;
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
;
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
;
809 case burnBlockFromRamToFlash
:
811 if(RXCalculatedPayloadLength
!= 6){
812 errorID
= payloadLengthTypeMismatch
;
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
;
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
;
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
;
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
;
856 /* Write the block down from RAM to Flash */
857 errorID
= writeBlock(&details
, leftOverBuffer
);
860 case requestDatalogPacket
: // Set type through standard configuration methods
862 if((RXCalculatedPayloadLength
> 2) || (RXCalculatedPayloadLength
== 1)){
863 errorID
= payloadLengthTypeMismatch
;
865 }else if(RXCalculatedPayloadLength
== 2){
866 unsigned short newConfiguredLength
= *((unsigned short*)RXBufferCurrentPosition
);
867 if(newConfiguredLength
> maxBasicDatalogLength
){
868 errorID
= datalogLengthExceedsMax
;
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
884 case setAsyncDatalogType
:
886 if(RXCalculatedPayloadLength
!= 1){
887 errorID
= payloadLengthTypeMismatch
;
891 unsigned char newDatalogType
= *((unsigned char*)RXBufferCurrentPosition
);
892 if(newDatalogType
> asyncDatalogLastType
){
893 errorID
= noSuchAsyncDatalogType
;
897 TablesB
.SmallTablesB
.loggingSettings
.datalogStreamType
= newDatalogType
;
900 case forwardPacketOverCAN
:
902 /// perform function TODO @todo REWORK review this
903 errorID
= unimplementedFunction
;
906 case forwardPacketOverOtherUART
:
908 /// perform function TODO @todo REWORK review this
909 errorID
= unimplementedFunction
;
912 case retrieveArbitraryMemory
:
914 if(RXCalculatedPayloadLength
!= 6){
915 errorID
= payloadLengthTypeMismatch
;
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
;
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
;
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
;
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
;
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
;
973 case retrieveListOfLocationIDs
:
975 if(RXCalculatedPayloadLength
!= 3){
976 errorID
= payloadLengthTypeMismatch
;
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!
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;
1015 case retrieveLocationIDDetails
:
1017 if(RXCalculatedPayloadLength
!= 2){
1018 errorID
= payloadLengthTypeMismatch
;
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
);
1038 // Adjust TX buffer position if successful
1039 TXBufferCurrentPositionHandler
+= sizeof(blockDetails
);
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
;
1066 // grab unit test ID from payload
1067 unsigned short unitTestID
= *((unsigned short*)RXBufferCurrentPosition
);
1068 RXBufferCurrentPosition
+= 2;
1073 // Must be only the ID
1074 if(RXCalculatedPayloadLength
!= 2){
1075 errorID
= payloadShorterThanRequiredForTest
;
1079 *((unsigned short*)TXBufferCurrentPositionHandler
) = unitTestID
;
1080 TXBufferCurrentPositionHandler
+=2;
1084 case testTwoDTableUSLookup
:
1086 // ID + Value + Table
1087 if(RXCalculatedPayloadLength
!= (2 + 2 + sizeof(twoDTableUS
))){
1088 errorID
= payloadShorterThanRequiredForTest
;
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;
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
1118 // sleep (milliseconds)
1119 // sleepMicro (microseconds)
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.
1129 errorID
= noSuchUnitTestID
;
1133 // checks length, fails if wrong
1134 // parses data into args
1135 // calls function on data/args
1136 // assembles response OR sets error
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
;
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
;
1155 }else if((localTestMode
== TEST_MODE_STOP
) && (RXCalculatedPayloadLength
== 1)){
1156 if(!(coreStatusA
& BENCH_TEST_ON
)){
1157 errorID
= benchTestNotRunningToStop
;
1161 // Ensure we succeed at stopping it as quickly as possible.
1163 KeyUserDebugs
.currentEvent
= testEventsPerCycle
- 1; // Gets incremented then compared with testEventsPerCycle
1164 testNumberOfCycles
= 1; // Gets decremented then compared with zero
1167 // eventually save and return where it got to
1169 }else if((localTestMode
== TEST_MODE_BUMP_UP_CYCLES
) && (RXCalculatedPayloadLength
== 2)){
1170 if(!(coreStatusA
& BENCH_TEST_ON
)){
1171 errorID
= benchTestNotRunningToBump
;
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
;
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.
1189 }else if((localTestMode
== TEST_MODE_ITERATIONS
) && (RXCalculatedPayloadLength
== 24)){
1190 testMode
= localTestMode
;
1191 // do nothing to fall through, or move other code into here
1193 errorID
= packetSizeWrongForTestMode
;
1197 if(coreStatusA
& BENCH_TEST_ON
){
1198 errorID
= benchTestAlreadyRunning
;
1201 coreStatusA
|= BENCH_TEST_ON
;
1204 testEventsPerCycle
= *((unsigned char*)RXBufferCurrentPosition
); //100; // @ 10ms = 1s
1205 RXBufferCurrentPosition
++;
1206 if(testEventsPerCycle
== 0){
1207 errorID
= invalidEventsPerCycle
;
1211 testNumberOfCycles
= *((unsigned short*)RXBufferCurrentPosition
); //20; // @ 1s = 20s
1212 RXBufferCurrentPosition
+= 2;
1213 if(testNumberOfCycles
== 0){
1214 errorID
= invalidNumberOfCycles
;
1218 testTicksPerEvent
= *((unsigned short*)RXBufferCurrentPosition
); //12500; // @ 0.8us = 10ms
1219 RXBufferCurrentPosition
+= 2;
1220 if(testTicksPerEvent
< decoderMaxCodeTime
){
1221 errorID
= tooShortOfAnEventPeriod
;
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.
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.
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
];
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
;
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!
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;
1331 // timeStamp.timeShorts[0] = timerExtensionClock;
1334 // schedulePortTPin(0, timeStamp);
1335 // schedulePortTPin(1, timeStamp);
1336 // schedulePortTPin(2, timeStamp);
1337 // schedulePortTPin(3, timeStamp);
1338 // schedulePortTPin(4, timeStamp);
1339 // schedulePortTPin(5, timeStamp);
1343 errorID
= thisIsNotTheBenchTestDecoder
;
1349 if((RXHeaderPayloadID
% 2) == 1){
1350 errorID
= invalidPayloadID
;
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
);
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. */
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 */
1454 *TXBufferCurrentPositionHandler
= 0x00;
1455 TXBufferCurrentPositionHandler
++;
1456 /* Set the payload ID */
1457 *((unsigned short*)TXBufferCurrentPositionHandler
) = asyncErrorCodePacket
;
1458 TXBufferCurrentPositionHandler
+= 2;
1460 finaliseAndSend(errorID
);
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
);
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
1525 // Counters.serialDebugUnsentCounter++;
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){
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;
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
;
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)) {
1599 // if ((!receiving) && (datalogMask & Mask)) {
1603 // if ((!receiving) && (datalogMask & Mask)) {
1607 // if ((!receiving) && (datalogMask & Mask)) {
1611 // if ((!receiving) && (datalogMask & Mask)) {
1615 // if ((!receiving) && (datalogMask & Mask)) {
1619 // if ((!receiving) && (datalogMask & Mask)) {
1623 // if ((!receiving) && (datalogMask & Mask)) {
1627 // // set the length
1628 // // the pointer should be correct already