1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\r
6 * This source code is free software; you can redistribute it and/or modify it
\r
7 * under the terms of the GNU General Public License version 2 as published by the
\r
8 * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
\r
10 * This program is distributed in the hope that it will be useful, but
\r
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
\r
14 * -------------------------------- Arctic Core ------------------------------*/
\r
17 //lint -esym(960,8.7) PC-Lint misunderstanding of Misra 8.7 for Com_SystenEndianness and endianess_test
\r
22 #include "Com_Arc_Types.h"
\r
24 #include "Com_Internal.h"
\r
25 #include "Com_misc.h"
\r
30 void Com_ReadSignalDataFromPdu(
\r
31 const Com_SignalIdType signalId,
\r
35 const ComSignal_type * Signal = GET_Signal(signalId);
\r
36 uint8 pduSize = GET_IPdu(Signal->ComIPduHandleId)->ComIPduSize;
\r
38 Com_ReadSignalDataFromPduBuffer(
\r
42 GET_IPdu(Signal->ComIPduHandleId)->ComIPduDataPtr,
\r
46 void Com_ReadGroupSignalDataFromPdu(
\r
47 const Com_SignalIdType parentSignalId,
\r
48 const Com_SignalIdType groupSignalId,
\r
52 const ComSignal_type * Signal = GET_Signal(parentSignalId);
\r
53 uint8 pduSize = GET_IPdu(Signal->ComIPduHandleId)->ComIPduSize;
\r
55 Com_ReadSignalDataFromPduBuffer(
\r
59 GET_IPdu(Signal->ComIPduHandleId)->ComIPduDataPtr,
\r
63 void Com_ReadSignalDataFromPduBuffer(
\r
64 const uint16 signalId,
\r
65 const boolean isGroupSignal,
\r
67 const void *pduBuffer,
\r
70 Com_SignalType signalType;
\r
71 ComSignalEndianess_type signalEndianess;
\r
73 Com_BitPositionType bitPosition;
\r
76 if (!isGroupSignal) {
\r
77 const ComSignal_type * Signal = GET_Signal(signalId);
\r
78 signalType = Signal->ComSignalType;
\r
79 signalEndianess = Signal->ComSignalEndianess;
\r
80 signalLength = Signal->ComBitSize / 8;
\r
81 bitPosition = Signal->ComBitPosition;
\r
82 bitSize = Signal->ComBitSize;
\r
84 const ComGroupSignal_type *GroupSignal = GET_GroupSignal(signalId);
\r
85 signalType = GroupSignal->ComSignalType;
\r
86 signalEndianess = GroupSignal->ComSignalEndianess;
\r
87 signalLength = GroupSignal->ComBitSize / 8;
\r
88 bitPosition = GroupSignal->ComBitPosition;
\r
89 bitSize = GroupSignal->ComBitSize;
\r
92 uint8 destSize = SignalTypeToSize(signalType, signalLength);
\r
94 // Pointer to a byte of the source and dest respectively.
\r
95 uint8 *signalDataBytes = (uint8 *)signalData;
\r
96 uint8 signalDataBytesArray[8];
\r
97 const uint8 *pduBufferBytes = (const uint8 *)pduBuffer + (bitPosition/8);
\r
98 Com_BitPositionType startBitOffset = 0;
\r
100 if (signalEndianess == COM_OPAQUE || signalType == UINT8_N) {
\r
101 // Aligned opaque data -> straight copy
\r
102 memcpy(signalDataBytes, pduBufferBytes, destSize);
\r
105 // Unaligned data and/or endianness conversion
\r
107 if (signalEndianess == COM_LITTLE_ENDIAN) {
\r
108 // Swap source bytes before reading
\r
109 // TODO: Must adapt to larger PDUs!
\r
110 uint8 pduBufferBytes_swap[8];
\r
111 for (uint8 i = 0; i < 8; ++i) {
\r
112 pduBufferBytes_swap[i] = pduBufferBytes[7 - i];
\r
114 startBitOffset = intelBitNrToPduOffset(bitPosition%8, bitSize, 64);
\r
115 //lint -save -esym(960,12.5) PC-Lint Exception: OK. PC-Lint Wrong interpretation of MISRA rule 12.5.
\r
116 Com_ReadDataSegment(
\r
117 signalDataBytesArray, pduBufferBytes_swap, destSize,
\r
118 startBitOffset, bitSize,
\r
119 SignalTypeSignedness(signalType));
\r
122 startBitOffset = motorolaBitNrToPduOffset(bitPosition%8);
\r
123 Com_ReadDataSegment(
\r
124 signalDataBytesArray, pduBufferBytes, destSize,
\r
125 startBitOffset, bitSize,
\r
126 SignalTypeSignedness(signalType));
\r
129 if (Com_SystemEndianness == COM_BIG_ENDIAN) {
\r
132 for (i = 0; i < destSize; i++) {
\r
133 signalDataBytes[i] = signalDataBytesArray[i];
\r
136 } else if (Com_SystemEndianness == COM_LITTLE_ENDIAN) {
\r
137 // Data copy algorithm creates big-endian output data so we swap
\r
139 for (i = 0; i < destSize; i++) {
\r
140 signalDataBytes[(destSize - 1) - i] = signalDataBytesArray[i];
\r
143 //lint --e(506) PC-Lint exception Misra 13.7, 14.1, Allow boolean to always be false.
\r
150 void Com_WriteSignalDataToPdu(
\r
151 const Com_SignalIdType signalId,
\r
152 const void *signalData) {
\r
155 const ComSignal_type *Signal = GET_Signal(signalId);
\r
156 const ComIPdu_type *IPdu = GET_IPdu(Signal->ComIPduHandleId);
\r
159 Com_WriteSignalDataToPduBuffer(
\r
163 (void *)IPdu->ComIPduDataPtr,
\r
164 IPdu->ComIPduSize);
\r
167 void Com_WriteGroupSignalDataToPdu(
\r
168 const Com_SignalIdType parentSignalId,
\r
169 const Com_SignalIdType groupSignalId,
\r
170 const void *signalData) {
\r
173 const ComSignal_type *Signal = GET_Signal(parentSignalId);
\r
174 const ComIPdu_type *IPdu = GET_IPdu(Signal->ComIPduHandleId);
\r
177 Com_WriteSignalDataToPduBuffer(
\r
181 (void *)IPdu->ComIPduDataPtr,
\r
182 IPdu->ComIPduSize);
\r
186 void Com_WriteSignalDataToPduBuffer(
\r
187 const uint16 signalId,
\r
188 const boolean isGroupSignal,
\r
189 const void *signalData,
\r
191 const uint8 pduSize) {
\r
192 // TODO: Implement writing little-endian signals
\r
194 Com_SignalType signalType;
\r
195 uint8 signalLength;
\r
196 Com_BitPositionType bitPosition;
\r
198 ComSignalEndianess_type endian;
\r
200 if (!isGroupSignal) {
\r
201 const ComSignal_type * Signal = GET_Signal(signalId);
\r
202 signalType = Signal->ComSignalType;
\r
203 signalLength = Signal->ComBitSize / 8;
\r
204 bitPosition = Signal->ComBitPosition;
\r
205 bitSize = Signal->ComBitSize;
\r
206 endian = Signal->ComSignalEndianess;
\r
208 const ComGroupSignal_type *GroupSignal = GET_GroupSignal(signalId);
\r
209 signalType = GroupSignal->ComSignalType;
\r
210 signalLength = GroupSignal->ComBitSize / 8;
\r
211 bitPosition = GroupSignal->ComBitPosition;
\r
212 bitSize = GroupSignal->ComBitSize;
\r
213 endian = GroupSignal->ComSignalEndianess;
\r
216 uint8 signalBufferSize = SignalTypeToSize(signalType, signalLength);
\r
217 uint8 pduSignalMask[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
\r
219 uint8 signalDataBytesArray[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
\r
220 const uint8 *signalDataBytes = (const uint8 *)signalData;
\r
221 if (endian == COM_OPAQUE || signalType == UINT8_N) {
\r
222 //assert(bitPosition % 8 == 0);
\r
223 //assert(bitSize % 8 == 0);
\r
224 uint8 *pduBufferBytes = (uint8 *)pduBuffer;
\r
225 uint8 startFromPduByte = bitPosition / 8;
\r
226 memcpy(pduBufferBytes + startFromPduByte, signalDataBytes, signalLength);
\r
228 if (Com_SystemEndianness == COM_BIG_ENDIAN) {
\r
231 for (i = 0; i < signalBufferSize; i++) {
\r
232 signalDataBytesArray[i] = signalDataBytes[i];
\r
235 } else if (Com_SystemEndianness == COM_LITTLE_ENDIAN) {
\r
236 // Data copy algorithm assumes big-endian input data so we swap
\r
238 for (i = 0; i < signalBufferSize; i++) {
\r
239 signalDataBytesArray[(signalBufferSize - 1) - i] = signalDataBytes[i];
\r
242 //lint --e(506) PC-Lint exception Misra 13.7, 14.1, Allow boolean to always be false.
\r
246 if (endian == COM_BIG_ENDIAN) {
\r
247 Com_BitPositionType startBitOffset = motorolaBitNrToPduOffset(bitPosition%8);
\r
248 uint8 pduBufferBytesStraight[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
\r
250 Com_WriteDataSegment(pduBufferBytesStraight, pduSignalMask,
\r
251 signalDataBytesArray, signalBufferSize, startBitOffset, bitSize);
\r
253 // Straight copy into real pdu buffer (with mutex)
\r
254 uint8 *pduBufferBytes = ((uint8 *)pduBuffer)+(bitPosition/8);
\r
257 Irq_Save(irq_state);
\r
258 for (i = 0; i < 8; i++) {
\r
259 pduBufferBytes[ i ] &= ~( pduSignalMask[ i ] );
\r
260 pduBufferBytes[ i ] |= pduBufferBytesStraight[ i ];
\r
262 Irq_Restore(irq_state);
\r
265 uint8 startBitOffset = intelBitNrToPduOffset(bitPosition%8, bitSize, 64);
\r
266 uint8 pduBufferBytesSwapped[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
\r
268 Com_WriteDataSegment(pduBufferBytesSwapped, pduSignalMask,
\r
269 signalDataBytesArray, signalBufferSize, startBitOffset, bitSize);
\r
271 // Swapped copy into real pdu buffer (with mutex)
\r
272 uint8 *pduBufferBytes = ((uint8 *)pduBuffer)+(bitPosition/8);
\r
275 Irq_Save(irq_state);
\r
276 // actually it is only necessary to iterate through the bytes that are written.
\r
277 for (i = 0; i < 8; i++) {
\r
278 pduBufferBytes[ i ] &= ~( pduSignalMask[ (8 - 1) - i ] );
\r
279 pduBufferBytes[ i ] |= pduBufferBytesSwapped[ (8 - 1) - i ];
\r
281 Irq_Restore(irq_state);
\r
288 * Read an arbitrary signal segment from buffer.
\r
289 * dest: pointer to start of destination buffer
\r
290 * source: pointer to start of source buffer
\r
291 * destByteLength: size of destination buffer in bytes
\r
292 * segmentStartBitOffset: bit offset to signal segment (from first bit in *source data)
\r
293 * segmentBitLength: length in bits of the signal segment to be read
\r
296 * Source data: (ABC... = signal segment)
\r
297 * | -----ABC | DEFGHIJK | LMNOPQ-- |
\r
300 * dest: pointer to 32 bit space (needs to be at least 3 bytes to keep the 17 signal bits)
\r
301 * destByteLength: 4
\r
303 * segmentStartBitOffset: 5
\r
304 * segmentBitLength: 17
\r
308 * | -------- | -------A | BCDEFGHI | JKLMNOPQ |
\r
311 void Com_ReadDataSegment(uint8 *dest, const uint8 *source, uint8 destByteLength,
\r
312 Com_BitPositionType segmentStartBitOffset, uint8 segmentBitLength, boolean signedOutput) {
\r
314 Com_BitPositionType sourceEndBitOffset = segmentStartBitOffset + segmentBitLength - 1;
\r
315 Com_BitPositionType sourceStartByte = segmentStartBitOffset / 8;
\r
316 uint8 sourceEndByte = (sourceEndBitOffset) / 8;
\r
317 uint8 sourceByteLength = sourceEndByte - sourceStartByte;
\r
319 uint8 segmentStartBitOffsetInsideByte = segmentStartBitOffset % 8;
\r
320 uint16 sourceStartByteMask;
\r
322 uint8 sourceAlignmentShift = 7 - (sourceEndBitOffset % 8);
\r
323 uint8 segmentByteLength = 1 + (segmentBitLength - 1) / 8;
\r
324 uint8 sourceByteNr = 0;
\r
325 uint8 destByteNr = 0;
\r
327 uint16 shiftReg = 0;
\r
331 if ( signedOutput && (*(source + sourceStartByte) & (0x80u >> segmentStartBitOffsetInsideByte)) ) {
\r
333 sourceStartByteMask = (0xFF00u >> segmentStartBitOffsetInsideByte);
\r
334 memset(dest, 0xFF, destByteLength);
\r
337 sourceStartByteMask = (0x00FFu >> segmentStartBitOffsetInsideByte);
\r
338 memset(dest, 0x00u, destByteLength);
\r
341 // setup to point to end (LSB) of buffers
\r
342 source += sourceEndByte;
\r
343 dest += destByteLength - 1;
\r
346 // compiles and writes one destination byte on each iteration
\r
348 shiftReg = *(source - sourceByteNr) | 0xFF00u; // read source byte (already matching "byte space")
\r
349 if (sourceByteNr == sourceByteLength) { // if we are on the last source byte..
\r
350 shiftReg |= sourceStartByteMask; // ..we need to mask out stuff we don't want
\r
352 shiftReg >>= sourceAlignmentShift; // shift down to align
\r
353 *(dest - destByteNr) &= shiftReg | 0xFF00u; // write into destination byte
\r
355 sourceByteNr++; // move to next source byte
\r
356 if ( (sourceAlignmentShift != 0) // do we have more bits for current dest. byte in this source byte?
\r
357 && (sourceByteNr <= sourceByteLength) ) {
\r
358 shiftReg = *(source - sourceByteNr) | 0xFF00u; // read next source byte
\r
359 if (sourceByteNr == sourceByteLength) { // if we are on the last source byte..
\r
360 shiftReg |= sourceStartByteMask; // ..we need to mask out stuff we don't want
\r
362 shiftReg = (uint16)~(shiftReg); // shifting inverted to shift in 1:s
\r
363 shiftReg <<= 8; // shift up (to match destination "byte space")
\r
364 shiftReg = (uint16)~shiftReg;
\r
365 shiftReg >>= sourceAlignmentShift; // shift down to align
\r
366 *(dest - destByteNr) &= shiftReg | 0xFF00u; // write into destination byte
\r
369 } while (destByteNr < segmentByteLength);
\r
370 } else { // positive
\r
372 shiftReg = *(source - sourceByteNr) & 0x00FFu; // read source byte (already matching "byte space")
\r
373 if (sourceByteNr == sourceByteLength) { // if we are on the last source byte..
\r
374 shiftReg &= sourceStartByteMask; // ..we need to mask out stuff we don't want
\r
376 shiftReg >>= sourceAlignmentShift; // shift down to align
\r
377 *(dest - destByteNr) |= shiftReg & 0x00FFu; // write into destination byte
\r
379 sourceByteNr++; // move to next source byte
\r
380 if (sourceAlignmentShift != 0 // do we have more bits for current dest. byte in this source byte?
\r
381 && sourceByteNr <= sourceByteLength) {
\r
382 shiftReg = *(source - sourceByteNr) & 0x00FFu; // read next source byte
\r
383 if (sourceByteNr == sourceByteLength) { // if we are on the last source byte..
\r
384 shiftReg &= sourceStartByteMask; // ..we need to mask out stuff we don't want
\r
386 shiftReg <<= 8; // shift up (to match destination "byte space")
\r
387 shiftReg >>= sourceAlignmentShift; // shift down to align
\r
388 *(dest - destByteNr) |= shiftReg & 0x00FFu; // write into destination byte
\r
391 } while (destByteNr < segmentByteLength);
\r
396 * Copies the <segmentBitLength> least significant bits from <signal> into <pdu>.
\r
397 * The bit segment is placed in <pdu> so that the most significant bit ends up
\r
398 * at <segmentStartBitOffset> from the msb of <pdu>.
\r
399 * <pduSignalMask> is cleared and written to contain a mask with 1´s where the
\r
400 * signal is located in the <pdu>.
\r
402 void Com_WriteDataSegment(uint8 *pdu, uint8 *pduSignalMask, const uint8 *signalDataPtr, uint8 destByteLength,
\r
403 Com_BitPositionType segmentStartBitOffset, uint8 segmentBitLength) {
\r
404 Com_BitPositionType pduEndBitOffset = segmentStartBitOffset + segmentBitLength - 1;
\r
405 uint8 pduStartByte = segmentStartBitOffset / 8;
\r
406 uint8 pduEndByte = (pduEndBitOffset) / 8;
\r
407 uint8 pduByteLength = pduEndByte - pduStartByte;
\r
409 uint8 segmentStartBitOffsetInsideByte = segmentStartBitOffset % 8;
\r
410 uint8 pduStartByteMask = (0xFFu >> segmentStartBitOffsetInsideByte);
\r
412 uint8 pduAlignmentShift = 7 - (pduEndBitOffset % 8);
\r
413 uint8 segmentByteLength = 1 + (segmentBitLength - 1) / 8;
\r
414 uint8 pduByteNr = 0;
\r
415 uint8 signalByteNr = 0;
\r
417 uint16 shiftReg = 0;
\r
418 uint16 clearReg = 0;
\r
420 // clear pduSignalMask all the way from 0
\r
421 memset(pduSignalMask, 0x00, pduEndByte);
\r
423 // setup to point to end (LSB) of buffers
\r
425 pduSignalMask += pduEndByte;
\r
427 signalDataPtr += destByteLength - 1;
\r
429 // splits and writes one source byte on each iteration
\r
431 shiftReg = *(signalDataPtr - signalByteNr) & 0x00FFu;
\r
433 //lint -save -e701 -e734 //PC-Lint Wrong interpretation of MISRA rule 10.5.
\r
434 shiftReg <<= pduAlignmentShift;
\r
435 clearReg <<= pduAlignmentShift;
\r
437 if (pduByteNr == pduByteLength) {
\r
438 shiftReg &= pduStartByteMask;
\r
439 clearReg &= pduStartByteMask;
\r
441 *(pdu - pduByteNr) &= (uint16)~(clearReg & 0x00FFu);
\r
442 *(pduSignalMask - pduByteNr) |= (uint16) (clearReg & 0x00FFu);
\r
443 *(pdu - pduByteNr) |= shiftReg & 0x00FFu;
\r
446 if ( (pduAlignmentShift != 0)
\r
447 && (pduByteNr <= pduByteLength) ) {
\r
448 shiftReg = *(signalDataPtr - signalByteNr) & 0x00FFu;
\r
450 //lint -save -e701 -e734 //PC-Lint Wrong interpretation of MISRA rule 10.5.
\r
451 shiftReg <<= pduAlignmentShift;
\r
452 clearReg <<= pduAlignmentShift;
\r
456 if (pduByteNr == pduByteLength) {
\r
457 shiftReg &= pduStartByteMask;
\r
458 clearReg &= pduStartByteMask;
\r
460 *(pdu - pduByteNr) &= (uint16)~(clearReg & 0x00FFu);
\r
461 *(pduSignalMask - pduByteNr) |= (uint16) (clearReg & 0x00FFu);
\r
462 *(pdu - pduByteNr) |= shiftReg & 0x00FFu;
\r
465 } while (signalByteNr < segmentByteLength);
\r
469 * Converts from motorola CAN bit nr to PDU bit offset
\r
471 * motorolaBitNr: 7 6 5 4 3 2 1 0 15 14 13 12 ...
\r
472 * motorolaBitNrToPduOffset: 0 1 2 3 4 5 6 7 8 9 10 11 ...
\r
474 Com_BitPositionType motorolaBitNrToPduOffset (Com_BitPositionType motorolaBitNr) {
\r
475 uint8 byte = motorolaBitNr / 8;
\r
476 Com_BitPositionType offsetToByteStart = (Com_BitPositionType) (byte * 8u);
\r
477 Com_BitPositionType offsetInsideByte = motorolaBitNr % 8;
\r
478 return (Com_BitPositionType) (offsetToByteStart + (7u - offsetInsideByte));
\r
482 * Converts from intel CAN bit nr to PDU bit offset
\r
485 * intelBitNr (after PDU byte-swap): 39 38 37 36 35 34 33 32 31 ... 3 2 1 0
\r
486 * intelBitNrToPduOffset: 0 1 2 3 4 5 6 7 8 ... 36 37 38 39
\r
488 Com_BitPositionType intelBitNrToPduOffset (Com_BitPositionType intelBitNr, Com_BitPositionType segmentBitLength, Com_BitPositionType pduBitLength) {
\r
489 return pduBitLength - (intelBitNr + segmentBitLength);
\r
492 void Com_RxProcessSignals(const ComIPdu_type *IPdu,Com_Arc_IPdu_type *Arc_IPdu) {
\r
493 const ComSignal_type *comSignal;
\r
494 for (uint8 i = 0; IPdu->ComIPduSignalRef[i] != NULL; i++) {
\r
495 comSignal = IPdu->ComIPduSignalRef[i];
\r
496 Com_Arc_Signal_type * Arc_Signal = GET_ArcSignal(comSignal->ComHandleId);
\r
498 // If this signal uses an update bit, then it is only considered if this bit is set.
\r
499 if ( (!comSignal->ComSignalArcUseUpdateBit) ||
\r
500 ( (comSignal->ComSignalArcUseUpdateBit) && (TESTBIT(IPdu->ComIPduDataPtr, comSignal->ComUpdateBitPosition)) ) ) {
\r
502 if (comSignal->ComTimeoutFactor > 0) { // If reception deadline monitoring is used.
\r
503 // Reset the deadline monitoring timer.
\r
504 Arc_Signal->Com_Arc_DeadlineCounter = comSignal->ComTimeoutFactor;
\r
507 // Check the signal processing mode.
\r
508 if (IPdu->ComIPduSignalProcessing == IMMEDIATE) {
\r
509 // If signal processing mode is IMMEDIATE, notify the signal callback.
\r
510 if (IPdu->ComIPduSignalRef[i]->ComNotification != NULL) {
\r
511 IPdu->ComIPduSignalRef[i]->ComNotification();
\r
515 // Signal processing mode is DEFERRED, mark the signal as updated.
\r
516 Arc_Signal->ComSignalUpdated = 1;
\r
520 DEBUG(DEBUG_LOW, "Com_RxIndication: Ignored signal %d of I-PD %d since its update bit was not set\n", comSignal->ComHandleId, ComRxPduId);
\r
524 void UnlockTpBuffer(PduIdType PduId) {
\r
525 Com_BufferPduState[PduId].locked = false;
\r
526 Com_BufferPduState[PduId].currentPosition = 0;
\r
529 boolean isPduBufferLocked(PduIdType id) {
\r
532 boolean bufferLocked = Com_BufferPduState[id].locked;
\r
533 Irq_Restore(state);
\r
534 if (bufferLocked) {
\r
540 PduIdType getPduId(const ComIPdu_type* IPdu) {
\r
541 return (PduIdType)(IPdu - (ComConfig->ComIPdu));
\r