1 /* FreeEMS - the open source engine management system
3 Copyright 2008 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 * @ingroup communicationsFiles
29 * @brief Core communications functions.
31 * This file contains most of the core comms functionality. Currently that is
32 * only for UART serial style communication. It is already too big and needs
33 * to be split up somewhat. This will happen fairly soon during the serial
34 * refactoring and protocol fine tuning.
36 * @todo TODO function to setup a packet and send it fn(populateBodyFunctionPointer(), header, other, fields, here, and, use, or, not, within){}
37 * @todo TODO factor many things into functions and move the receive delegator to its own file
44 #include "inc/freeEMS.h"
45 #include "inc/flashWrite.h"
46 #include "inc/interrupts.h"
47 #include "inc/utils.h"
48 #include "inc/tableLookup.h"
49 #include "inc/blockDetailsLookup.h"
50 #include "inc/commsCore.h"
54 /** @brief Populate a basic datalog packet
56 * Copies various chunks of data to the transmission buffer and truncates to
57 * the configured length. If changing this, update the maxBasicDatalogLength.
61 * @warning This function is only a skeleton at this time.
63 void populateBasicDatalog(){
64 /* Save the current position */
65 unsigned char* position
= TXBufferCurrentPositionHandler
;
68 memcpy(TXBufferCurrentPositionHandler
, CoreVars
, sizeof(CoreVar
));
69 TXBufferCurrentPositionHandler
+= sizeof(CoreVar
);
70 /* Get derived vars */
71 memcpy(TXBufferCurrentPositionHandler
, DerivedVars
, sizeof(DerivedVar
));
72 TXBufferCurrentPositionHandler
+= sizeof(DerivedVar
);
73 /* Get raw adc counts */
74 memcpy(TXBufferCurrentPositionHandler
, ADCArrays
, sizeof(ADCArray
));
75 TXBufferCurrentPositionHandler
+= sizeof(ADCArray
);
77 /* Set/Truncate the log to the specified length */
78 TXBufferCurrentPositionHandler
= position
+ configuredBasicDatalogLength
;
82 //void populateLogicAnalyser(){
83 // // get portT rpm input and inj main
86 // // get portK inj staged
90 // All of these require some range checking, eg only some registers, and all ram, not flash, not other regs
91 // TODO pointer for one byte
92 // TODO pointer for one short
93 // TODO function to log generic memory region by location and size ? requires length!
97 // IO registers etc that can't be altered simply by reading from.
99 // flash makes no sense
100 // some regs are sensitive
101 // some ram is unused
102 // serial buffers make no sense
103 // eeprom makes no sense
105 // 2k of regs max - user beware for now
109 //logaddr = fixed.addr
112 //len = loglen OR 1 OR 2
115 //if((addr < 0x0800) && (length < (0x0800 - addr))){
116 // // reg space is OK
117 //}else if(((0x1000 < addr) && (addr < 0x4000)) && (length < (0x4000 - addr))){
118 // // ram space is OK
120 // // send an error instead
123 //run check at init and set time, not run time or just not check?? maybe its silly to check at all
125 // /* Just dump the ADC channels as fast as possible */
126 //void populateScopeLogADCAll(){
127 // sampleBlockADC(TXBufferCurrentPositionHandler);
128 // TXBufferCurrentPositionHandler += sizeof(ADCArray);
132 // 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.
135 /** @brief Checksum a packet and send it
137 * This functions job is to finalise the main loop part of the packet sending
138 * process. It runs a checksum over the packet data and tags it to the end
139 * before configuring the various ISRs that need to send the data out.
143 * @bug http://freeems.aaronb.info/tracker/view.php?id=81
144 * @todo TODO fix the double/none start byte bug and remove the hack!
146 void checksumAndSend(){
147 /* Get the length from the pointer */
148 unsigned short TXPacketLengthToSend
= (unsigned short)TXBufferCurrentPositionHandler
- (unsigned short)&TXBuffer
;
150 /* Tag the checksum on the end */
151 *TXBufferCurrentPositionHandler
= checksum((unsigned char*)&TXBuffer
, TXPacketLengthToSend
);
152 TXPacketLengthToSend
++;
154 /* Send it out on all the channels required. */
156 /* SCI0 - Main serial interface */
157 if(TXBufferInUseFlags
& COM_SET_SCI0_INTERFACE_ID
){
158 /* Copy numbers to interface specific vars */
159 TXPacketLengthToSendSCI0
= TXPacketLengthToSend
;
160 TXPacketLengthToSendCAN0
= TXPacketLengthToSend
;
162 /* Queue preamble by clearing and then setting transmit enable */
163 /* See section 11.4.5.2 of the xdp512 specification document */
164 //SCI0CR2 &= SCICR2_TX_DISABLE;
165 //SCI0CR2 |= SCICR2_TX_ENABLE;
167 /* Initiate transmission */
168 SCI0DRL
= START_BYTE
;
169 while(!(SCI0SR1
& 0x80)){/* Wait for ever until able to send then move on */}
170 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.
172 /* Note : Order Is Important! */
173 /* TX empty flag is already set, so we must clear it by writing out before enabling the interrupt */
174 SCI0CR2
|= SCICR2_TX_ISR_ENABLE
;
176 /* CAN0 - Main CAN interface */
177 if(TXBufferInUseFlags
& COM_SET_CAN0_INTERFACE_ID
){
178 // just clear up front for now
179 TXBufferInUseFlags
&= COM_CLEAR_CAN0_INTERFACE_ID
;
182 if(TXBufferInUseFlags
& COM_SET_SPARE2_INTERFACE_ID
){
183 // just clear up front for now
184 TXBufferInUseFlags
&= COM_CLEAR_SPARE2_INTERFACE_ID
;
187 if(TXBufferInUseFlags
& COM_SET_SPARE3_INTERFACE_ID
){
188 // just clear up front for now
189 TXBufferInUseFlags
&= COM_CLEAR_SPARE3_INTERFACE_ID
;
192 if(TXBufferInUseFlags
& COM_SET_SPARE4_INTERFACE_ID
){
193 // just clear up front for now
194 TXBufferInUseFlags
&= COM_CLEAR_SPARE4_INTERFACE_ID
;
197 if(TXBufferInUseFlags
& COM_SET_SPARE5_INTERFACE_ID
){
198 // just clear up front for now
199 TXBufferInUseFlags
&= COM_CLEAR_SPARE5_INTERFACE_ID
;
202 if(TXBufferInUseFlags
& COM_SET_SPARE6_INTERFACE_ID
){
203 // just clear up front for now
204 TXBufferInUseFlags
&= COM_CLEAR_SPARE6_INTERFACE_ID
;
207 if(TXBufferInUseFlags
& COM_SET_SPARE7_INTERFACE_ID
){
208 // just clear up front for now
209 TXBufferInUseFlags
&= COM_CLEAR_SPARE7_INTERFACE_ID
;
214 /** @brief Decode a packet and respond
216 * This is the core function that controls what functionality is run when a
217 * packet is received in full by the ISR code and control is passed back to the
218 * main loop code. The vast majority of communications action happens here.
222 void decodePacketAndRespond(){
223 /* Extract and build up the header fields */
224 RXBufferCurrentPosition
= (unsigned char*)&RXBuffer
;
225 TXBufferCurrentPositionHandler
= (unsigned char*)&TXBuffer
;
227 /* Initialised here such that override is possible */
228 TXBufferCurrentPositionSCI0
= (unsigned char*)&TXBuffer
;
229 TXBufferCurrentPositionCAN0
= (unsigned char*)&TXBuffer
;
231 /* Start this off as full packet length and build down to the actual length */
232 RXCalculatedPayloadLength
= RXPacketLengthReceived
;
234 /* Grab the RX header flags out of the RX buffer */
235 RXHeaderFlags
= *RXBufferCurrentPosition
;
236 RXBufferCurrentPosition
++;
237 RXCalculatedPayloadLength
--;
239 /* Flag that we are transmitting! */
240 TXBufferInUseFlags
|= COM_SET_SCI0_INTERFACE_ID
;
241 // SCI0 only for now...
243 /* Load a blank header into the TX buffer ready for masking */
244 unsigned char* TXHeaderFlags
= TXBufferCurrentPositionHandler
;
246 TXBufferCurrentPositionHandler
++;
248 /* Grab the payload ID for processing and load the return ID */
249 RXHeaderPayloadID
= *((unsigned short*)RXBufferCurrentPosition
);
250 *((unsigned short*)TXBufferCurrentPositionHandler
) = RXHeaderPayloadID
+ 1;
251 RXBufferCurrentPosition
+= 2;
252 TXBufferCurrentPositionHandler
+= 2;
253 RXCalculatedPayloadLength
-= 2;
255 /* If there is an ack, copy it to the return packet */
256 if(RXHeaderFlags
& HEADER_HAS_ACK
){
257 *TXBufferCurrentPositionHandler
= *RXBufferCurrentPosition
;
258 *TXHeaderFlags
|= HEADER_HAS_ACK
;
259 RXBufferCurrentPosition
++;
260 TXBufferCurrentPositionHandler
++;
261 RXCalculatedPayloadLength
--;
264 /* If the header has addresses, check them and if OK copy them */
265 if(RXHeaderFlags
& HEADER_HAS_ADDRS
){
266 /* Check the destination address against our address */
267 if(*RXBufferCurrentPosition
!= fixedConfigs1
.serialSettings
.networkAddress
){
268 /* Addresses do not match, discard packet without error */
269 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS
);
270 TXBufferInUseFlags
= 0;
273 RXBufferCurrentPosition
++;
275 /* Save and check the source address */
276 RXHeaderSourceAddress
= *RXBufferCurrentPosition
;
277 RXBufferCurrentPosition
++;
278 if(RXHeaderSourceAddress
== 0){
279 sendErrorInternal(sourceAddressIsBroadcast
);
280 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS
);
283 if(RXHeaderSourceAddress
== fixedConfigs1
.serialSettings
.networkAddress
){
284 sendErrorInternal(sourceAddressIsDuplicate
);
285 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS
);
289 /* All is well, setup reply addresses */
290 *TXHeaderFlags
|= HEADER_HAS_ADDRS
;
291 /* TX destination = RX source */
292 *TXBufferCurrentPositionHandler
= RXHeaderSourceAddress
;
293 TXBufferCurrentPositionHandler
++;
294 /* TX source = our address */
295 *TXBufferCurrentPositionHandler
= fixedConfigs1
.serialSettings
.networkAddress
;
296 TXBufferCurrentPositionHandler
++;
297 /* Decrement for both at once to save a cycle */
298 RXCalculatedPayloadLength
-= 2;
301 /* Subtract checksum to get final length */
302 RXCalculatedPayloadLength
--;
304 /* Grab the length if available */
305 if(RXHeaderFlags
& HEADER_HAS_LENGTH
){
306 RXHeaderPayloadLength
= *((unsigned short*)RXBufferCurrentPosition
);
307 RXBufferCurrentPosition
+= 2;
308 RXCalculatedPayloadLength
-= 2;
309 /* Already subtracted one for checksum */
310 if(RXHeaderPayloadLength
!= RXCalculatedPayloadLength
){
311 sendErrorInternal(payloadLengthHeaderMismatch
);
312 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS
);
318 /* length (and it's flag) should be set by each return packet type handler if required or desired. */
319 /* If an ack has been requested, ensure the negative ack flag is set if the opration failed. */
321 /* Perform the requested action based on payload ID */
322 if (RXHeaderFlags
& HEADER_IS_PROTO
){ /* Protocol payload types */
323 /* Set the return type to be protocol too */
324 *TXHeaderFlags
|= HEADER_IS_PROTO
;
326 switch (RXHeaderPayloadID
){
327 case requestInterfaceVersion
:
329 if(RXCalculatedPayloadLength
!= 0){
330 sendErrorInternal(payloadLengthTypeMismatch
);
334 /* This type must have a length field, set that up */
335 *((unsigned short*)TXBufferCurrentPositionHandler
) = sizeof(interfaceVersionAndType
);
336 *TXHeaderFlags
|= HEADER_HAS_LENGTH
;
337 TXBufferCurrentPositionHandler
+= 2;
338 /* Load the body into place */
339 memcpy((void*)TXBufferCurrentPositionHandler
, (void*)&interfaceVersionAndType
, sizeof(interfaceVersionAndType
));
340 TXBufferCurrentPositionHandler
+= sizeof(interfaceVersionAndType
);
344 case requestFirmwareVersion
:
346 if(RXCalculatedPayloadLength
!= 0){
347 sendErrorInternal(payloadLengthTypeMismatch
);
350 /* This type must have a length field, set that up */
351 *((unsigned short*)TXBufferCurrentPositionHandler
) = sizeof(firmwareVersion
);
352 *TXHeaderFlags
|= HEADER_HAS_LENGTH
;
353 TXBufferCurrentPositionHandler
+= 2;
354 /* Load the body into place */
355 memcpy((void*)TXBufferCurrentPositionHandler
, (void*)&firmwareVersion
, sizeof(firmwareVersion
));
356 TXBufferCurrentPositionHandler
+= sizeof(firmwareVersion
);
360 case requestMaxPacketSize
:
362 if(RXCalculatedPayloadLength
!= 0){
363 sendErrorInternal(payloadLengthTypeMismatch
);
366 /* Load the size into place */
367 *((unsigned short*)TXBufferCurrentPositionHandler
) = RX_BUFFER_SIZE
;
368 TXBufferCurrentPositionHandler
+= 2;
372 case requestEchoPacketReturn
:
374 /* This type must have a length field, set that up */
375 *((unsigned short*)TXBufferCurrentPositionHandler
) = RXPacketLengthReceived
;
376 *TXHeaderFlags
|= HEADER_HAS_LENGTH
;
377 TXBufferCurrentPositionHandler
+= 2;
378 /* Load the body into place */
379 memcpy((void*)TXBufferCurrentPositionHandler
, (void*)&RXBuffer
, RXPacketLengthReceived
);
380 /* Note, there is no overflow check here because the TX buffer is slightly */
381 /* bigger than the RX buffer and there is overflow checking for receives anyway. */
382 TXBufferCurrentPositionHandler
+= RXPacketLengthReceived
;
386 case requestSoftSystemReset
:
388 // hack to allow datalog on/off from the orange button (thank christ I asked for that button when I did)
389 if(asyncDatalogType
){
390 asyncDatalogType
= asyncDatalogOff
;
392 asyncDatalogType
= asyncDatalogBasic
;
394 sendAckIfRequired(); // TODO implement
397 // // hack to use soft reset to request registers
398 // /* This type must have a length field, set that up */
399 // *((unsigned short*)TXBufferCurrentPositionHandler) = memdumplength;
400 // *TXHeaderFlags |= HEADER_HAS_LENGTH;
401 // TXBufferCurrentPositionHandler += 2;
402 // /* Load the body into place */
403 // memcpy((void*)TXBufferCurrentPositionHandler, memdumpaddr, memdumplength);
404 // TXBufferCurrentPositionHandler += memdumplength;
405 // memdumpaddr += memdumplength;
406 // checksumAndSend();
409 // if(RXCalculatedPayloadLength != 0){
410 // sendErrorInternal(payloadLengthTypeMismatch);
413 // /* Perform soft system reset */
416 case requestHardSystemReset
:
418 if(RXCalculatedPayloadLength
!= 0){
419 sendErrorInternal(payloadLengthTypeMismatch
);
423 /* This is how the serial monitor does it. */
424 COPCTL
= 0x01; /* Arm with shortest time */
425 ARMCOP
= 0xFF; /* Write bad value, should cause immediate reset */
426 /* Using _start() only resets the app ignoring the monitor switch. It does not work */
427 /* properly because the location of _start is not the master reset vector location. */
431 if((RXHeaderPayloadID
% 2) == 1){
432 sendErrorInternal(invalidProtocolPayloadID
);
434 sendErrorInternal(unrecognisedProtocolPayloadID
);
438 }else{ /* Otherwise firmware payload types */
439 switch (RXHeaderPayloadID
) {
440 case replaceBlockInRAM
:
442 /* Extract the ram location ID from the received data */
443 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
444 RXBufferCurrentPosition
+= 2;
446 /* Look up the memory location details */
447 blockDetails details
;
448 lookupBlockDetails(locationID
, &details
);
450 /* Subtract two to allow for the locationID */
451 if((RXCalculatedPayloadLength
- 2) != details
.size
){
452 sendErrorInternal(payloadLengthTypeMismatch
);
456 if((details
.RAMPage
== 0) || (details
.RAMAddress
== 0)){
457 sendErrorInternal(invalidMemoryActionForID
);
461 // TODO factor this out into validation delegation function once the number of types increases somewhat
462 unsigned short errorID
= 0;
465 errorID
= validateMainTable((mainTable
*)RXBufferCurrentPosition
);
466 }else if((locationID
> 399) && (locationID
< 900)){
467 // twoDTableUS aTable;
468 errorID
= validateTwoDTable((twoDTableUS
*)RXBufferCurrentPosition
);
469 }// TODO add other table types here
470 /* If the validation failed, report it */
472 sendErrorInternal(errorID
);
476 /* Save page values for restore */
477 unsigned char oldRamPage
= RPAGE
;
478 /* Set the viewable ram page */
479 RPAGE
= details
.RAMPage
;
480 /* Copy from the RX buffer to the block of ram */
481 memcpy(details
.RAMAddress
, RXBufferCurrentPosition
, details
.size
);
482 /* Restore the original ram and flash pages */
485 sendAckIfRequired(); // TODO implement
488 case replaceBlockInFlash
:
490 /* Extract the ram location ID from the received data */
491 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
492 RXBufferCurrentPosition
+= 2;
494 /* Look up the memory location details */
495 blockDetails details
;
496 lookupBlockDetails(locationID
, &details
);
498 /* Subtract two to allow for the locationID */
499 if((RXCalculatedPayloadLength
- 2) != details
.size
){
500 sendErrorInternal(payloadLengthTypeMismatch
);
504 if((details
.FlashPage
== 0) || (details
.FlashAddress
== 0)){
505 sendErrorInternal(invalidMemoryActionForID
);
509 // TODO factor this out into validation delegation function once the number of types increases somewhat
510 unsigned short errorID
= 0;
513 errorID
= validateMainTable((mainTable
*)RXBufferCurrentPosition
);
514 }else if((locationID
> 399) && (locationID
< 900)){
515 // twoDTableUS aTable;
516 errorID
= validateTwoDTable((twoDTableUS
*)RXBufferCurrentPosition
);
517 }// TODO add other table types here
518 /* If the validation failed, report it */
520 sendErrorInternal(errorID
);
524 /* Calculate the position of the end of the stored packet for use as a buffer */
525 void* buffer
= (void*)((unsigned short)&RXBuffer
+ RXPacketLengthReceived
);
527 /* Swap the RAM details such that the block gets pulled down from the buffer */
528 unsigned char originalRAMPage
= details
.RAMPage
;
529 void* originalRAMAddress
= details
.RAMAddress
;
530 details
.RAMPage
= RPAGE
;
531 details
.RAMAddress
= RXBufferCurrentPosition
;
533 /* Copy from the RX buffer to the block of flash */
534 errorID
= writeBlock(&details
, buffer
);
536 sendErrorInternal(errorID
);
540 /* If present in RAM, update that too */
541 if((originalRAMPage
!= 0) && (originalRAMAddress
!= 0)){
542 /* Save page values for restore */
543 unsigned char oldRamPage
= RPAGE
;
544 /* Set the viewable ram page */
545 RPAGE
= originalRAMPage
;
546 /* Copy from the RX buffer to the block of ram */
547 memcpy(originalRAMAddress
, RXBufferCurrentPosition
, details
.size
);
548 /* Restore the original ram and flash pages */
553 // TODO document errors can always be returned and add error check in to send as response for ack and async otherwise
556 case retrieveBlockFromRAM
:
558 if(RXCalculatedPayloadLength
!= 2){
559 sendErrorInternal(payloadLengthTypeMismatch
);
563 /* Extract the ram location ID from the received data */
564 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
565 /* Store it back into the output data */
566 *(unsigned short*)TXBufferCurrentPositionHandler
= locationID
;
567 TXBufferCurrentPositionHandler
+= 2;
569 /* If it's a main table we are returning, specify the limits explicitly */
571 /* Store it back into the output data */
572 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_RPM_LENGTH
;
573 TXBufferCurrentPositionHandler
+= 2;
574 /* Store it back into the output data */
575 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_LOAD_LENGTH
;
576 TXBufferCurrentPositionHandler
+= 2;
577 /* Store it back into the output data */
578 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_MAIN_LENGTH
;
579 TXBufferCurrentPositionHandler
+= 2;
582 /* Look up the memory location details */
583 blockDetails details
;
584 lookupBlockDetails(locationID
, &details
);
586 if((details
.RAMPage
== 0) || (details
.RAMAddress
== 0)){
587 sendErrorInternal(invalidMemoryActionForID
);
591 /* Save page value for restore and set the visible page */
592 unsigned char oldRamPage
= RPAGE
;
593 RPAGE
= details
.RAMPage
;
595 /* Copy the block of ram to the TX buffer */
596 memcpy(TXBufferCurrentPositionHandler
, details
.RAMAddress
, details
.size
);
597 TXBufferCurrentPositionHandler
+= details
.size
;
599 /* Restore the original ram and flash pages */
605 case retrieveBlockFromFlash
:
607 if(RXCalculatedPayloadLength
!= 2){
608 sendErrorInternal(payloadLengthTypeMismatch
);
612 /* Extract the flash location ID from the received data */
613 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
614 /* Store it back into the output data */
615 *(unsigned short*)TXBufferCurrentPositionHandler
= locationID
;
616 TXBufferCurrentPositionHandler
+= 2;
618 /* If it's a main table we are returning, specify the limits explicitly */
620 /* Store it back into the output data */
621 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_RPM_LENGTH
;
622 TXBufferCurrentPositionHandler
+= 2;
623 /* Store it back into the output data */
624 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_LOAD_LENGTH
;
625 TXBufferCurrentPositionHandler
+= 2;
626 /* Store it back into the output data */
627 *(unsigned short*)TXBufferCurrentPositionHandler
= MAINTABLE_MAX_MAIN_LENGTH
;
628 TXBufferCurrentPositionHandler
+= 2;
631 /* Look up the memory location details */
632 blockDetails details
;
633 lookupBlockDetails(locationID
, &details
);
635 if((details
.FlashPage
== 0) || (details
.FlashAddress
== 0)){
636 sendErrorInternal(invalidMemoryActionForID
);
640 /* Save page value for restore and set the visible page */
641 unsigned char oldFlashPage
= PPAGE
;
642 PPAGE
= details
.FlashPage
;
644 /* Copy the block of flash to the TX buffer */
645 memcpy(TXBufferCurrentPositionHandler
, details
.FlashAddress
, details
.size
);
646 TXBufferCurrentPositionHandler
+= details
.size
;
648 /* Restore the original ram and flash pages */
649 PPAGE
= oldFlashPage
;
654 case burnBlockFromRamToFlash
:
656 if(RXCalculatedPayloadLength
!= 2){
657 sendErrorInternal(payloadLengthTypeMismatch
);
661 /* Extract the flash location ID from the received data */
662 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
664 /* Look up the memory location details */
665 blockDetails details
;
666 lookupBlockDetails(locationID
, &details
);
668 /* Check that all data we need is present */
669 if((details
.RAMPage
== 0) || (details
.RAMAddress
== 0) || (details
.FlashPage
== 0) || (details
.FlashAddress
== 0)){
670 sendErrorInternal(invalidMemoryActionForID
);
674 /* Calculate the position of the end of the stored packet for use as a buffer */
675 void* buffer
= (void*)((unsigned short)&RXBuffer
+ RXPacketLengthReceived
);
677 /* Write the block down from RAM to Flash */
678 unsigned short errorID
= writeBlock(&details
, buffer
);
681 sendErrorInternal(errorID
);
688 case eraseAllBlocksFromFlash
:
690 if(RXCalculatedPayloadLength
!= 0){
691 sendErrorInternal(payloadLengthTypeMismatch
);
695 // perform function TODO
696 unsigned char page
= 0xE0;
697 unsigned short start
= 0x8000;
698 unsigned short end
= 0xC000;
699 unsigned short inc
= 0x0400;
700 for(;page
< 0xF8;page
++){
702 for(addr
= start
;addr
< end
; addr
+= inc
){
703 // TODO create selfDestruct() function for loading larger code to the device using all flash pages.
704 eraseSector(page
, (unsigned short*)addr
);
707 sendDebugInternal("Erased three 128k Flash blocks!");
710 case burnAllBlocksOfFlash
:
712 if(RXCalculatedPayloadLength
!= 0){
713 sendErrorInternal(payloadLengthTypeMismatch
);
717 // perform function TODO
718 unsigned char page
= 0xE0;
719 unsigned short start
= 0x8000;
720 unsigned short end
= 0xC000;
721 unsigned short inc
= 0x0400;
722 for(;page
< 0xF8;page
++){
724 for(addr
= start
;addr
< end
; addr
+= inc
){
725 writeSector(RPAGE
, (unsigned short*)0xc000, page
, (unsigned short*)addr
);
728 sendDebugInternal("Overwrote three 128k Flash blocks!");
731 case adjustMainTableCell
:
733 if(RXCalculatedPayloadLength
!= 8){
734 sendErrorInternal(payloadLengthTypeMismatch
);
738 /* Extract the flash location ID from the received data */
739 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
740 RXBufferCurrentPosition
+= 2;
742 /* Check the ID to ensure it is a main table */
744 sendErrorInternal(invalidIDForMainTableAction
);
748 /* Extract the cell value and coordinates */
749 unsigned short RPMIndex
= *((unsigned short*)RXBufferCurrentPosition
);
750 RXBufferCurrentPosition
+= 2;
751 unsigned short LoadIndex
= *((unsigned short*)RXBufferCurrentPosition
);
752 RXBufferCurrentPosition
+= 2;
753 unsigned short cellValue
= *((unsigned short*)RXBufferCurrentPosition
);
755 /* Look up the memory location details */
756 blockDetails details
;
757 lookupBlockDetails(locationID
, &details
);
759 /* Attempt to set the value */
760 unsigned short errorID
= setPagedMainTableCellValue(details
.RAMPage
, details
.RAMAddress
, RPMIndex
, LoadIndex
, cellValue
);
762 sendErrorInternal(errorID
);
768 case adjustMainTableRPMAxis
:
770 if(RXCalculatedPayloadLength
!= 6){
771 sendErrorInternal(payloadLengthTypeMismatch
);
775 /* Extract the flash location ID from the received data */
776 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
777 RXBufferCurrentPosition
-= 2;
779 /* Check the ID to ensure it is a main table */
781 sendErrorInternal(invalidIDForMainTableAction
);
785 /* Extract the cell value and coordinates */
786 unsigned short RPMIndex
= *((unsigned short*)RXBufferCurrentPosition
);
787 RXBufferCurrentPosition
-= 2;
788 unsigned short RPMValue
= *((unsigned short*)RXBufferCurrentPosition
);
790 /* Look up the memory location details */
791 blockDetails details
;
792 lookupBlockDetails(locationID
, &details
);
794 /* Attempt to set the value */
795 unsigned short errorID
= setPagedMainTableRPMValue(details
.RAMPage
, details
.RAMAddress
, RPMIndex
, RPMValue
);
797 sendErrorInternal(errorID
);
803 case adjustMainTableLoadAxis
:
805 if(RXCalculatedPayloadLength
!= 6){
806 sendErrorInternal(payloadLengthTypeMismatch
);
810 /* Extract the flash location ID from the received data */
811 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
812 RXBufferCurrentPosition
-= 2;
814 /* Check the ID to ensure it is a main table */
816 sendErrorInternal(invalidIDForMainTableAction
);
820 /* Extract the cell value and coordinates */
821 unsigned short LoadIndex
= *((unsigned short*)RXBufferCurrentPosition
);
822 RXBufferCurrentPosition
-= 2;
823 unsigned short LoadValue
= *((unsigned short*)RXBufferCurrentPosition
);
825 /* Look up the memory location details */
826 blockDetails details
;
827 lookupBlockDetails(locationID
, &details
);
829 /* Attempt to set the value */
830 unsigned short errorID
= setPagedMainTableLoadValue(details
.RAMPage
, details
.RAMAddress
, LoadIndex
, LoadValue
);
832 sendErrorInternal(errorID
);
838 case adjust2dTableAxis
:
840 if(RXCalculatedPayloadLength
!= 6){
841 sendErrorInternal(payloadLengthTypeMismatch
);
845 /* Extract the flash location ID from the received data */
846 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
847 RXBufferCurrentPosition
-= 2;
849 /* Check the ID to ensure it is a 2d table */
850 if((locationID
> 899) || (locationID
< 400)){
851 sendErrorInternal(invalidIDForTwoDTableAction
);
855 /* Extract the cell value and coordinates */
856 unsigned short axisIndex
= *((unsigned short*)RXBufferCurrentPosition
);
857 RXBufferCurrentPosition
-= 2;
858 unsigned short axisValue
= *((unsigned short*)RXBufferCurrentPosition
);
860 /* Look up the memory location details */
861 blockDetails details
;
862 lookupBlockDetails(locationID
, &details
);
864 /* Attempt to set the value */
865 unsigned short errorID
= setPagedTwoDTableAxisValue(details
.RAMPage
, details
.RAMAddress
, axisIndex
, axisValue
);
867 sendErrorInternal(errorID
);
873 case adjust2dTableCell
:
875 if(RXCalculatedPayloadLength
!= 6){
876 sendErrorInternal(payloadLengthTypeMismatch
);
880 /* Extract the flash location ID from the received data */
881 unsigned short locationID
= *((unsigned short*)RXBufferCurrentPosition
);
882 RXBufferCurrentPosition
-= 2;
884 /* Check the ID to ensure it is a 2d table */
885 if((locationID
> 899) || (locationID
< 400)){
886 sendErrorInternal(invalidIDForTwoDTableAction
);
890 /* Extract the cell value and coordinates */
891 unsigned short cellIndex
= *((unsigned short*)RXBufferCurrentPosition
);
892 RXBufferCurrentPosition
-= 2;
893 unsigned short cellValue
= *((unsigned short*)RXBufferCurrentPosition
);
895 /* Look up the memory location details */
896 blockDetails details
;
897 lookupBlockDetails(locationID
, &details
);
899 /* Attempt to set the value */
900 unsigned short errorID
= setPagedTwoDTableCellValue(details
.RAMPage
, details
.RAMAddress
, cellIndex
, cellValue
);
902 sendErrorInternal(errorID
);
908 case requestBasicDatalog
:
910 if((RXCalculatedPayloadLength
> 2) || (RXCalculatedPayloadLength
== 1)){
911 sendErrorInternal(payloadLengthTypeMismatch
);
913 }else if(RXCalculatedPayloadLength
== 2){
914 unsigned short newConfiguredLength
= *((unsigned short*)RXBufferCurrentPosition
);
915 if(newConfiguredLength
> maxBasicDatalogLength
){
916 sendErrorInternal(datalogLengthExceedsMax
);
919 configuredBasicDatalogLength
= newConfiguredLength
;
923 /* Set the length field up */
924 *TXHeaderFlags
|= HEADER_HAS_LENGTH
;
925 *(unsigned short*)TXBufferCurrentPositionHandler
= configuredBasicDatalogLength
;
927 /* Fill out the log and send */
928 populateBasicDatalog();
932 case requestConfigurableDatalog
:
934 // perform function TODO
935 sendErrorInternal(unimplementedFunction
);
938 case forwardPacketOverCAN
:
940 // perform function TODO
941 sendErrorInternal(unimplementedFunction
);
944 case forwardPacketOverOtherUART
:
946 // perform function TODO
947 sendErrorInternal(unimplementedFunction
);
950 case setAsyncDatalogType
:
952 if(RXCalculatedPayloadLength
!= 1){
953 sendErrorInternal(payloadLengthTypeMismatch
);
957 unsigned char newDatalogType
= *((unsigned char*)RXBufferCurrentPosition
);
958 if(newDatalogType
> 0x03){
959 sendErrorInternal(noSuchAsyncDatalogType
);
962 asyncDatalogType
= newDatalogType
;
969 if((RXHeaderPayloadID
% 2) == 1){
970 sendErrorInternal(invalidFirmwarePayloadID
);
972 sendErrorInternal(unrecognisedFirmwarePayloadID
);
976 /* Switch reception back on now that we are done with the received data */
977 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS
);
982 /** @brief Send an error if buffer free
984 * 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.
988 * @warning Use of this function signifies that the error you are trying to propagate is not urgent and can be forgotten.
990 * @note Consider not throwing an error if it seems appropriate to use this.
992 * @param errorID is the error ID to be passed out to listening devices.
994 void sendErrorIfClear(unsigned short errorID
){
995 if(!TXBufferInUseFlags
){
996 TXBufferInUseFlags
= ONES
;
997 sendErrorInternal(errorID
);
999 Counters
.commsErrorMessagesNotSent
++;
1004 /** @brief Send an error even if we must wait
1006 * This is a wrapper for use outside the communication handler function. This
1007 * function will block until the error is able to be sent. This behaviour is
1008 * not recommended as it will interfere with engine operation somewhat.
1010 * @author Fred Cooke
1012 * @warning Use of this function signifies that the error you are trying to propagate is extremely urgent and can not be forgotten.
1014 * @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.
1016 * @param errorID is the error ID to be passed out to listening devices.
1018 void sendErrorBusyWait(unsigned short errorID
){
1019 while(TXBufferInUseFlags
){} /* Wait till clear to send */
1020 TXBufferInUseFlags
= ONES
;
1021 sendErrorInternal(errorID
);
1025 /** @brief Send an error
1027 * This function is only for use inside the communication handling function.
1028 * Use of it outside this environment is not supported and behaviour when used
1029 * as such is undefined.
1031 * @author Fred Cooke
1033 * @warning ONLY use this function from within the communication handler.
1035 * @see sendErrorIfClear()
1036 * @see sendErrorBusyWait()
1038 * @todo TODO clean up the mess of commented out crap in here!
1039 * @todo TODO decide on errorCode or errorID and consistencise it everywhere.
1041 * @param errorCode is the error ID to be passed out to listening devices.
1043 void sendErrorInternal(unsigned short errorCode
){
1044 // set buffer in use, consider blocking interrupts to do this cleanly
1047 // TXBufferInUseFlags = 0;
1048 /* No need for atomic block here as one of two conditions will always be */
1049 /* true when calling this. Either we have been flagged to receive and */
1050 /* decode a packet, or we are in an ISR. In either case it is safe to */
1051 /* check the flags and initiate the sequence if they are clear. */
1052 // if(RXTXSerialStateFlags & TX_IN_PROGRESS){
1053 /* It's OK to return without resetting as it will be done by */
1054 /* either of those processes if they are underway. The other */
1055 /* processes are not overridden because they have priority. */
1057 // }else{ /* Turn off reception */
1058 /* It's OK to turn this off if nothing was currently being received */
1059 // SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
1060 // SCI0CR2 &= SCICR2_RX_DISABLE;
1062 /* Build up the packet */
1063 /* Set the pointer to the start */
1064 TXBufferCurrentPositionHandler
= (unsigned char*)&TXBuffer
;
1065 /* Set the length */
1066 // TXPacketLengthToSend = 5; /* Flags + Payload ID + Error Code */
1067 /* Flags = protocol with no extra fields */
1068 *TXBufferCurrentPositionHandler
= 0x01;
1069 TXBufferCurrentPositionHandler
++;
1070 /* Set the payload ID */
1071 *((unsigned short*)TXBufferCurrentPositionHandler
) = asyncErrorCodePacket
;
1072 TXBufferCurrentPositionHandler
+= 2;
1073 /* Set the error code */
1074 *((unsigned short*)TXBufferCurrentPositionHandler
) = errorCode
;
1075 TXBufferCurrentPositionHandler
+= 2;
1081 /** @brief Send a debug message if buffer free
1083 * 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.
1085 * @author Fred Cooke
1087 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1089 * @param message is a pointer to the null terminated debug message string.
1091 void sendDebugIfClear(unsigned char* message
){
1092 if(!TXBufferInUseFlags
){
1093 TXBufferInUseFlags
= ONES
;
1094 sendDebugInternal(message
);
1096 Counters
.commsDebugMessagesNotSent
++;
1101 /** Send a debug message even if we must wait
1103 * This is a wrapper for use outside the communication handler function. This
1104 * function will block until the debug message is able to be sent.
1106 * @author Fred Cooke
1108 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1110 * @param message is a pointer to the null terminated debug message string.
1112 void sendDebugBusyWait(unsigned char* message
){
1113 while(TXBufferInUseFlags
){} /* Wait till clear to send */
1114 TXBufferInUseFlags
= ONES
;
1115 sendDebugInternal(message
);
1119 /** @brief Send a debug message
1121 * Sends a null terminated debug message out on the broadcast address of all available interfaces.
1123 * @author Fred Cooke
1125 * @warning ONLY use this function from within the communication handler.
1127 * @see sendDebugIfClear()
1128 * @see sendDebugBusyWait()
1130 * @note This function exists as a convenience to developers, do not publish code that calls this function.
1132 * @todo TODO clean up the mess of commented out crap in here!
1134 * @param message is a pointer to the null terminated debug message string.
1136 void sendDebugInternal(unsigned char* message
){
1138 // set buffer in use, consider blocking interrupts to do this cleanly
1141 // Counters.serialDebugUnsentCounter++;
1145 /* No need for atomic block here as one of two conditions will always be */
1146 /* true when calling this. Either we have been flagged to receive and */
1147 /* decode a packet, or we are in an ISR. In either case it is safe to */
1148 /* check the flags and initiate the sequence if they are clear. */
1149 //if(RXTXSerialStateFlags & TX_IN_PROGRESS){
1151 /* It's OK to return without resetting as it will be done by */
1152 /* either of those processes if they are underway. The other */
1153 /* processes are not overridden because they have priority. */
1154 //TXBufferInUseFlags = 0;
1156 // }else{ /* Turn off reception */
1157 /* It's OK to turn this off if nothing was currently being received */
1158 // SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
1159 // SCI0CR2 &= SCICR2_RX_DISABLE;
1161 /* Build up the packet */
1162 /* Set the pointer to the start and init the length */
1163 TXBufferCurrentPositionHandler
= (unsigned char*)&TXBuffer
;
1165 /* Load a protocol with length header into the TX buffer ready for masking */
1166 *TXBufferCurrentPositionHandler
= 0x11;
1167 TXBufferCurrentPositionHandler
++;
1169 /* Set the payload ID */
1170 *((unsigned short*)TXBufferCurrentPositionHandler
) = asyncDebugInfoPacket
;
1171 TXBufferCurrentPositionHandler
+= 2;
1173 /* Store the length location */
1174 unsigned short* TXLength
= (unsigned short*)TXBufferCurrentPositionHandler
;
1175 TXBufferCurrentPositionHandler
+= 2;
1177 /* Copy the string into place and record the length copied */
1178 unsigned short messageLength
= stringCopy(TXBufferCurrentPositionHandler
, message
);
1179 *TXLength
= messageLength
;
1180 TXBufferCurrentPositionHandler
+= messageLength
;
1187 /* This function should be period limited to about 10 seconds internally (or by scheduler) */
1188 //void checkCountersAndSendErrors(){
1189 // compare time stamps with current time stamps and execute if old enough. (if no scheduler)
1191 // compare counters with counters cache (from last time) sending an error packet when they differ
1193 // copy counters to counters cache for next time
1195 // send errors with busy wait on the basis that all errors should be taken care of and not be sent in fairly short order?
1197 // or send with isr but just busy wait for it to finish before sending the next?
1199 // 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.
1201 // need to figure out how to queue received packets for processing when we are currently sending stuff out.
1203 // above notes don't belong here really.
1207 //void prepareDatalog(){
1208 // // send data log by default otherwise
1209 // unsigned char chunksExpected = 8; // based on configuration, yet to determine how to calculate this number
1210 // unsigned char chunksLoaded = 0;
1211 // if ((!receiving) && (datalogMask & rawVarsMask)) {
1215 // if ((!receiving) && (datalogMask & Mask)) {
1219 // if ((!receiving) && (datalogMask & Mask)) {
1223 // if ((!receiving) && (datalogMask & Mask)) {
1227 // if ((!receiving) && (datalogMask & Mask)) {
1231 // if ((!receiving) && (datalogMask & Mask)) {
1235 // if ((!receiving) && (datalogMask & Mask)) {
1239 // if ((!receiving) && (datalogMask & Mask)) {
1243 // // set the length
1244 // // the pointer should be correct already
1248 /** @brief Send an ack if required
1250 * Currently only used to clear the TX buffer flags if we no longer need it.
1252 * @author Fred Cooke
1254 * @todo TODO when implementing, check that ppage is OK!!!
1256 void sendAckIfRequired(){
1257 TXBufferInUseFlags
= 0;
1258 // check PPAGE while implementing TODO