AM_DIAG_MSG = 0xB1,
};
- components DiagMsgM, MainC, SerialActiveMessageC;
+ components DiagMsgP, MainC, SerialActiveMessageC;
- DiagMsg = DiagMsgM.DiagMsg;
+ DiagMsg = DiagMsgP.DiagMsg;
- MainC.SoftwareInit -> DiagMsgM.Init;
- DiagMsgM.AMSend -> SerialActiveMessageC.AMSend[AM_DIAG_MSG];
- DiagMsgM.Packet -> SerialActiveMessageC;
+ MainC.SoftwareInit -> DiagMsgP.Init;
+ DiagMsgP.AMSend -> SerialActiveMessageC.AMSend[AM_DIAG_MSG];
+ DiagMsgP.Packet -> SerialActiveMessageC;
#endif
}
+++ /dev/null
-/*
- * Copyright (c) 2002-2007, Vanderbilt University
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice, the following
- * two paragraphs and the author appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
- * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Author: Miklos Maroti
- */
-
-#include <message.h>
-
-module DiagMsgM
-{
- provides
- {
- interface DiagMsg;
- interface Init;
- }
-
- uses
- {
- interface AMSend;
- interface Packet;
- }
-}
-
-#ifndef DIAGMSG_BASE_STATION
-#define DIAGMSG_BASE_STATION AM_BROADCAST_ADDR
-#endif
-
-#ifndef DIAGMSG_RETRY_COUNT
-#define DIAGMSG_RETRY_COUNT 2
-#endif
-
-#ifndef DIAGMSG_RECORDED_MSGS
-#define DIAGMSG_RECORDED_MSGS 10
-#endif
-
-implementation
-{
- enum
- {
- STATE_READY = 1,
- STATE_RECORDING_FIRST = 2, // recording the first 4-bit descriptor
- STATE_RECORDING_SECOND = 3, // recording the second 4-bit descriptor
- STATE_MSG_FULL = 4,
- STATE_BUFFER_FULL = 5,
- };
-
- norace volatile uint8_t state; // the state of the recording
-
- message_t msgs[DIAGMSG_RECORDED_MSGS]; // circular buffer of messages
-
- norace message_t *recording; // the message that is beeing or going to be recorded
- message_t *sending; // the message that is beeing sent, or the null pointer
-
- norace uint8_t nextData; // points to the next unsued byte
- norace uint8_t prevType; // points to the type descriptor
- norace uint8_t retries; // number of remaining retries
-
- command error_t Init.init()
- {
- state = STATE_READY;
- recording = msgs;
- sending = 0;
-
- return SUCCESS;
- }
-
- // two type fields are stored in on byte
- enum
- {
- TYPE_END = 0,
- TYPE_INT8 = 1,
- TYPE_UINT8 = 2,
- TYPE_HEX8 = 3,
- TYPE_INT16 = 4,
- TYPE_UINT16 = 5,
- TYPE_HEX16 = 6,
- TYPE_INT32 = 7,
- TYPE_UINT32 = 8,
- TYPE_HEX32 = 9,
- TYPE_FLOAT = 10,
- TYPE_CHAR = 11,
- TYPE_INT64 = 12,
- TYPE_UINT64 = 13,
- TYPE_ARRAY = 15,
- };
-
-/*
- The format of the payload is as follows:
-
- Each value has an associated data type descriptor. The descriptor takes 4-bits,
- and two descriptors are packed into one byte. The double-descriptor is followed
- by the data bytes needed to store the corresponding value. Two sample layouts are:
-
- [D2, D1] [V1] ... [V1] [V2] ... [V2]
- [D2, D1] [V1] ... [V1] [V2] ... [V2] [0, D3] [V3] ... [V3]
-
- where D1, D2, D3 denotes the data type descriptors, and V1, V2 and V3
- denotes the bytes where the corresponding values are stored. If there is an odd
- number of data descriptors, then a zero data descriptor <code>TYPE_END</code>
- is inserted.
-
- Each data type (except arrays) uses a fixed number of bytes to store the value.
- For arrays, the first byte of the array holds the data type of the array (higer
- 4 bits) and the length of the array (lower 4 bits). The actual data follows
- this first byte.
-*/
-
- async command bool DiagMsg.record()
- {
- atomic
- {
- // currently recording or no more space
- if( state != STATE_READY )
- return FALSE;
-
- state = STATE_RECORDING_FIRST;
- nextData = 0;
- }
-
- return TRUE;
- }
-
- /**
- * Allocates space in the message for <code>size</code> bytes
- * and sets the type information to <code>type</code>.
- * Returns the index in <code>msg.data</code> where the data
- * should be stored or <code>-1</code> if no more space is avaliable.
- */
- int8_t allocate(uint8_t size, uint8_t type)
- {
- int8_t ret = -1;
-
- if( state == STATE_RECORDING_FIRST )
- {
- if( nextData + 1 + size <= TOSH_DATA_LENGTH )
- {
- state = STATE_RECORDING_SECOND;
-
- prevType = nextData++;
- ((uint8_t*) &(recording->data))[prevType] = type;
- ret = nextData;
- nextData += size;
- }
- else
- state = STATE_MSG_FULL;
- }
- else if( state == STATE_RECORDING_SECOND )
- {
- if( nextData + size <= TOSH_DATA_LENGTH )
- {
- state = STATE_RECORDING_FIRST;
-
- ((uint8_t*) &(recording->data))[prevType] += (type << 4);
- ret = nextData;
- nextData += size;
- }
- else
- state = STATE_MSG_FULL;
- }
-
- return ret;
- }
-
-#define IMPLEMENT(NAME, TYPE, TYPE2) \
- async command void DiagMsg.NAME(TYPE value) \
- { \
- int8_t start = allocate(sizeof(TYPE), TYPE2); \
- if( start >= 0 ) \
- *(TYPE*)((uint8_t*) &(recording->data) + start) = value; \
- } \
- async command void DiagMsg.NAME##s(const TYPE *value, uint8_t len) \
- { \
- int8_t start; \
- if( len > 15 ) len = 15; \
- start = allocate(sizeof(TYPE)*len + 1, TYPE_ARRAY); \
- if( start >= 0 ) \
- { \
- ((uint8_t*) &(recording->data))[start++] = (TYPE2 << 4) + len; \
- while( len-- != 0 ) \
- ((TYPE*)((uint8_t*) &(recording->data) + start))[len] = value[len]; \
- } \
- }
-
- IMPLEMENT(int8, int8_t, TYPE_INT8)
- IMPLEMENT(uint8, uint8_t, TYPE_UINT8)
- IMPLEMENT(hex8, uint8_t, TYPE_HEX8)
- IMPLEMENT(int16, int16_t, TYPE_INT16)
- IMPLEMENT(uint16, uint16_t, TYPE_UINT16)
- IMPLEMENT(hex16, uint16_t, TYPE_HEX16)
- IMPLEMENT(int32, int32_t, TYPE_INT32)
- IMPLEMENT(uint32, uint32_t, TYPE_UINT32)
- IMPLEMENT(hex32, uint32_t, TYPE_HEX32)
- IMPLEMENT(int64, int64_t, TYPE_INT64)
- IMPLEMENT(uint64, uint64_t, TYPE_UINT64)
- IMPLEMENT(real, float, TYPE_FLOAT)
- IMPLEMENT(chr, char, TYPE_CHAR)
-
- async command void DiagMsg.str(const char* str)
- {
- int8_t len = 0;
- while( str[len] != 0 && len < 15 )
- ++len;
-
- call DiagMsg.chrs(str, len);
- }
-
- // TODO: this is a hack because setPayloadLength should be async
- inline void setPayloadLength(message_t* msg, uint8_t length)
- {
- (*(uint8_t*) &(msg->header)) = length;
- }
-
- inline uint8_t getPayloadLength(message_t* msg)
- {
- return *(uint8_t*) &(msg->header);
- }
-
- task void send()
- {
- message_t* msg;
-
- atomic msg = sending;
-
- if( call AMSend.send(DIAGMSG_BASE_STATION, msg, getPayloadLength(msg)) != SUCCESS )
- post send();
- }
-
- // calculates the next message_t pointer in the <code>msgs</code> circular buffer
- static inline message_t* nextPointer(message_t* ptr)
- {
- if( ++ptr >= msgs + DIAGMSG_RECORDED_MSGS )
- return msgs;
- else
- return ptr;
- }
-
- async command void DiagMsg.send()
- {
- // no message recorded
- if( state == STATE_READY )
- return;
-
- // store the length
- setPayloadLength(recording, nextData);
-
- atomic
- {
- if( sending == 0 )
- {
- sending = recording;
- retries = DIAGMSG_RETRY_COUNT;
- post send();
- }
-
- recording = nextPointer(recording);
-
- if( recording == sending )
- state = STATE_BUFFER_FULL;
- else
- state = STATE_READY;
- }
- }
-
- event void AMSend.sendDone(message_t* p, error_t error)
- {
- atomic
- {
- // retry if not successful
- if( error != SUCCESS && --retries > 0 )
- post send();
- else
- {
- p = nextPointer(sending);
- if( p != recording )
- {
- sending = p;
- retries = DIAGMSG_RETRY_COUNT;
- post send();
- }
- else
- {
- sending = 0;
-
- if( state == STATE_BUFFER_FULL )
- {
- state = STATE_READY;
- if( call DiagMsg.record() )
- {
- call DiagMsg.str("DiagMsgOverflow");
- call DiagMsg.send();
- }
- }
- }
- }
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2002-2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <message.h>
+
+module DiagMsgP
+{
+ provides
+ {
+ interface DiagMsg;
+ interface Init;
+ }
+
+ uses
+ {
+ interface AMSend;
+ interface Packet;
+ }
+}
+
+#ifndef DIAGMSG_BASE_STATION
+#define DIAGMSG_BASE_STATION AM_BROADCAST_ADDR
+#endif
+
+#ifndef DIAGMSG_RETRY_COUNT
+#define DIAGMSG_RETRY_COUNT 2
+#endif
+
+#ifndef DIAGMSG_RECORDED_MSGS
+#define DIAGMSG_RECORDED_MSGS 10
+#endif
+
+implementation
+{
+ enum
+ {
+ STATE_READY = 1,
+ STATE_RECORDING_FIRST = 2, // recording the first 4-bit descriptor
+ STATE_RECORDING_SECOND = 3, // recording the second 4-bit descriptor
+ STATE_MSG_FULL = 4,
+ STATE_BUFFER_FULL = 5,
+ };
+
+ norace volatile uint8_t state; // the state of the recording
+
+ message_t msgs[DIAGMSG_RECORDED_MSGS]; // circular buffer of messages
+
+ norace message_t *recording; // the message that is beeing or going to be recorded
+ message_t *sending; // the message that is beeing sent, or the null pointer
+
+ norace uint8_t nextData; // points to the next unsued byte
+ norace uint8_t prevType; // points to the type descriptor
+ norace uint8_t retries; // number of remaining retries
+
+ command error_t Init.init()
+ {
+ state = STATE_READY;
+ recording = msgs;
+ sending = 0;
+
+ return SUCCESS;
+ }
+
+ // two type fields are stored in on byte
+ enum
+ {
+ TYPE_END = 0,
+ TYPE_INT8 = 1,
+ TYPE_UINT8 = 2,
+ TYPE_HEX8 = 3,
+ TYPE_INT16 = 4,
+ TYPE_UINT16 = 5,
+ TYPE_HEX16 = 6,
+ TYPE_INT32 = 7,
+ TYPE_UINT32 = 8,
+ TYPE_HEX32 = 9,
+ TYPE_FLOAT = 10,
+ TYPE_CHAR = 11,
+ TYPE_INT64 = 12,
+ TYPE_UINT64 = 13,
+ TYPE_ARRAY = 15,
+ };
+
+/*
+ The format of the payload is as follows:
+
+ Each value has an associated data type descriptor. The descriptor takes 4-bits,
+ and two descriptors are packed into one byte. The double-descriptor is followed
+ by the data bytes needed to store the corresponding value. Two sample layouts are:
+
+ [D2, D1] [V1] ... [V1] [V2] ... [V2]
+ [D2, D1] [V1] ... [V1] [V2] ... [V2] [0, D3] [V3] ... [V3]
+
+ where D1, D2, D3 denotes the data type descriptors, and V1, V2 and V3
+ denotes the bytes where the corresponding values are stored. If there is an odd
+ number of data descriptors, then a zero data descriptor <code>TYPE_END</code>
+ is inserted.
+
+ Each data type (except arrays) uses a fixed number of bytes to store the value.
+ For arrays, the first byte of the array holds the data type of the array (higer
+ 4 bits) and the length of the array (lower 4 bits). The actual data follows
+ this first byte.
+*/
+
+ async command bool DiagMsg.record()
+ {
+ atomic
+ {
+ // currently recording or no more space
+ if( state != STATE_READY )
+ return FALSE;
+
+ state = STATE_RECORDING_FIRST;
+ nextData = 0;
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * Allocates space in the message for <code>size</code> bytes
+ * and sets the type information to <code>type</code>.
+ * Returns the index in <code>msg.data</code> where the data
+ * should be stored or <code>-1</code> if no more space is avaliable.
+ */
+ int8_t allocate(uint8_t size, uint8_t type)
+ {
+ int8_t ret = -1;
+
+ if( state == STATE_RECORDING_FIRST )
+ {
+ if( nextData + 1 + size <= TOSH_DATA_LENGTH )
+ {
+ state = STATE_RECORDING_SECOND;
+
+ prevType = nextData++;
+ ((uint8_t*) &(recording->data))[prevType] = type;
+ ret = nextData;
+ nextData += size;
+ }
+ else
+ state = STATE_MSG_FULL;
+ }
+ else if( state == STATE_RECORDING_SECOND )
+ {
+ if( nextData + size <= TOSH_DATA_LENGTH )
+ {
+ state = STATE_RECORDING_FIRST;
+
+ ((uint8_t*) &(recording->data))[prevType] += (type << 4);
+ ret = nextData;
+ nextData += size;
+ }
+ else
+ state = STATE_MSG_FULL;
+ }
+
+ return ret;
+ }
+
+#define IMPLEMENT(NAME, TYPE, TYPE2) \
+ async command void DiagMsg.NAME(TYPE value) \
+ { \
+ int8_t start = allocate(sizeof(TYPE), TYPE2); \
+ if( start >= 0 ) \
+ *(TYPE*)((uint8_t*) &(recording->data) + start) = value; \
+ } \
+ async command void DiagMsg.NAME##s(const TYPE *value, uint8_t len) \
+ { \
+ int8_t start; \
+ if( len > 15 ) len = 15; \
+ start = allocate(sizeof(TYPE)*len + 1, TYPE_ARRAY); \
+ if( start >= 0 ) \
+ { \
+ ((uint8_t*) &(recording->data))[start++] = (TYPE2 << 4) + len; \
+ while( len-- != 0 ) \
+ ((TYPE*)((uint8_t*) &(recording->data) + start))[len] = value[len]; \
+ } \
+ }
+
+ IMPLEMENT(int8, int8_t, TYPE_INT8)
+ IMPLEMENT(uint8, uint8_t, TYPE_UINT8)
+ IMPLEMENT(hex8, uint8_t, TYPE_HEX8)
+ IMPLEMENT(int16, int16_t, TYPE_INT16)
+ IMPLEMENT(uint16, uint16_t, TYPE_UINT16)
+ IMPLEMENT(hex16, uint16_t, TYPE_HEX16)
+ IMPLEMENT(int32, int32_t, TYPE_INT32)
+ IMPLEMENT(uint32, uint32_t, TYPE_UINT32)
+ IMPLEMENT(hex32, uint32_t, TYPE_HEX32)
+ IMPLEMENT(int64, int64_t, TYPE_INT64)
+ IMPLEMENT(uint64, uint64_t, TYPE_UINT64)
+ IMPLEMENT(real, float, TYPE_FLOAT)
+ IMPLEMENT(chr, char, TYPE_CHAR)
+
+ async command void DiagMsg.str(const char* str)
+ {
+ int8_t len = 0;
+ while( str[len] != 0 && len < 15 )
+ ++len;
+
+ call DiagMsg.chrs(str, len);
+ }
+
+ // TODO: this is a hack because setPayloadLength should be async
+ inline void setPayloadLength(message_t* msg, uint8_t length)
+ {
+ (*(uint8_t*) &(msg->header)) = length;
+ }
+
+ inline uint8_t getPayloadLength(message_t* msg)
+ {
+ return *(uint8_t*) &(msg->header);
+ }
+
+ task void send()
+ {
+ message_t* msg;
+
+ atomic msg = sending;
+
+ if( call AMSend.send(DIAGMSG_BASE_STATION, msg, getPayloadLength(msg)) != SUCCESS )
+ post send();
+ }
+
+ // calculates the next message_t pointer in the <code>msgs</code> circular buffer
+ static inline message_t* nextPointer(message_t* ptr)
+ {
+ if( ++ptr >= msgs + DIAGMSG_RECORDED_MSGS )
+ return msgs;
+ else
+ return ptr;
+ }
+
+ async command void DiagMsg.send()
+ {
+ // no message recorded
+ if( state == STATE_READY )
+ return;
+
+ // store the length
+ setPayloadLength(recording, nextData);
+
+ atomic
+ {
+ if( sending == 0 )
+ {
+ sending = recording;
+ retries = DIAGMSG_RETRY_COUNT;
+ post send();
+ }
+
+ recording = nextPointer(recording);
+
+ if( recording == sending )
+ state = STATE_BUFFER_FULL;
+ else
+ state = STATE_READY;
+ }
+ }
+
+ event void AMSend.sendDone(message_t* p, error_t error)
+ {
+ atomic
+ {
+ // retry if not successful
+ if( error != SUCCESS && --retries > 0 )
+ post send();
+ else
+ {
+ p = nextPointer(sending);
+ if( p != recording )
+ {
+ sending = p;
+ retries = DIAGMSG_RETRY_COUNT;
+ post send();
+ }
+ else
+ {
+ sending = 0;
+
+ if( state == STATE_BUFFER_FULL )
+ {
+ state = STATE_READY;
+ if( call DiagMsg.record() )
+ {
+ call DiagMsg.str("DiagMsgOverflow");
+ call DiagMsg.send();
+ }
+ }
+ }
+ }
+ }
+ }
+}