PIC24 Support Libraries
dataXfer.c
Go to the documentation of this file.
1 #include "dataXfer.h"
2 #include <string.h>
3 #include <stdio.h>
4 
5 /** \file
6  * \brief Implementation of the \ref index "uC data transfer protocol".
7  */
8 
9 // MS compiler workaround for snprintf.
10 #ifdef _MSC_VER
11 # define SNPRINTF sprintf_s
12 #else
13 # define SNPRINTF snprintf
14 #endif
15 
16 void
20 }
21 
22 
23 /// \name Send functions
24 //@{
25 
26 void
27 outCharXfer(char c) {
28  // If we're sending a character that needs escaping, then escape it.
29  OUT_CHAR(c);
30  if (c == CMD_TOKEN)
31  OUT_CHAR(ESCAPED_CMD);
32 }
33 
34 #if defined(MICROCONTROLLER) || defined(__DOXYGEN__) || defined(UNIT_TESTS)
35 void
36 specifyVar(uint u_varIndex, volatile void* pv_data, uint u_size,
37  BOOL b_isWriteable, char* psz_format, char* psz_name,
38  char* psz_desc) {
39  uint u_len;
40 
41  // Make sure this variable exists
42  ASSERTM("specifyVar:indexTooHigh", u_varIndex < NUM_XFER_VARS);
43  // Make sure the data isn't NULL
44  ASSERTM("specifyVar:nullData", pv_data != NULL);
45  // Make sure the size is valid
46  ASSERTM("specifyVar:invalidSize", (u_size > 0) && (u_size <= (UINT8_MAX + 1)));
47 
48  // Update data structure
49  xferVar[u_varIndex].pu8_data = (uint8_t*) pv_data;
50  xferVar[u_varIndex].u8_size = u_size - 1;
51  assignBit(u_varIndex, b_isWriteable);
52 
53  // Send a command
54  OUT_CHAR(CMD_TOKEN);
55 
56  // Send a specification: The spec code, index, then length
58  outCharXfer(u_varIndex);
59  // Include the space taken by the three NULL characters, minus one since a
60  // length of 1 is sent as 0, plus one for the variable size byte.
61  u_len = strlen(psz_format) + strlen(psz_name) + strlen(psz_desc) + 3 - 1 + 1;
62  // Allow a maximum data length of 256. Cap at 255, since all lengths are
63  // (actual length - 1).
64  outCharXfer(u_len <= UINT8_MAX ? u_len : UINT8_MAX);
65 
66  // Send the size of this variable, minus 1 since a size of 1 is sent as a 0.
67  outCharXfer(u_size - 1);
68 
69  // Send the strings; do not send more than 255 chars (the size just sent makes
70  // the 256th character, the maximum length).
71  u_len = 0;
72  do {
73  if (++u_len > UINT8_MAX) return;
74  outCharXfer(*psz_format);
75  } while (*psz_format++);
76  do {
77  if (++u_len > UINT8_MAX) return;
78  outCharXfer(*psz_name);
79  } while (*psz_name++);
80  do {
81  if (++u_len > UINT8_MAX) return;
82  outCharXfer(*psz_desc);
83  } while (*psz_desc++);
84 }
85 #endif
86 
87 void
88 sendVar(uint u_varIndex) {
89  XFER_VAR* pXferVar;
90  uint8_t u8_size;
91  uint8_t* pu8_data;
92  // Make sure this variable exists
93  ASSERTM("sendVar:indexTooHigh", u_varIndex < NUM_XFER_VARS);
94  // Note: The MS C compiler flags the statement
95  // XFER_VAR* pXferVar = xferVar + u_varIndex;
96  // as an error. It's OK in MS C++. Apparently, the C compiler doesn't
97  // support the newer C99 syntax. Therefore, u8_size and pu8_data are
98  // also declared above.
99  pXferVar = xferVar + u_varIndex;
100  ASSERTM("sendVar:indexNotSpecified", pXferVar->pu8_data != NULL);
101  // Make sure it's read/write (PC only)
102 #ifndef MICROCONTROLLER
103  ASSERTM("sendVar:notWriteable", isVarWriteable(u_varIndex));
104 #endif
105 
106  // Send a command
107  OUT_CHAR(CMD_TOKEN);
108 
109  // Send short/long var info
110  u8_size = pXferVar->u8_size;
111  if ((u8_size + 1) > SHORT_VAR_MAX_LEN) {
112  // Send a long var: The long var code, index, then length
114  outCharXfer(u_varIndex);
115  outCharXfer(u8_size);
116  } else {
117  // Send a short var
118  outCharXfer((u_varIndex << VAR_SIZE_BITS) | u8_size);
119  }
120 
121  // Send data
122  pu8_data = pXferVar->pu8_data;
123  do {
124  outCharXfer(*pu8_data++);
125  } while (u8_size--);
126 }
127 
128 //@}
129 
130 #ifndef MICROCONTROLLER
131 int
132 formatVar(uint u_varIndex, char* psz_buf, size_t s_len) {
133  XFER_VAR* pXferVar;
134  int i_ret;
135  uint u_size;
136  uintmax_t um_buf;
137 
138  // Make sure this variable exists
139  ASSERTM("formatVar:indexTooHigh", u_varIndex < NUM_XFER_VARS);
140  // Note: The MS C compiler flags the statement
141  // XFER_VAR* pXferVar = xferVar + u_varIndex;
142  // as an error. It's OK in MS C++. Apparently, the C compiler doesn't
143  // support the newer C99 syntax. Therefore, u8_size and pu8_data are
144  // also declared above.
145  pXferVar = xferVar + u_varIndex;
146  ASSERTM("formatVar:indexNotSpecified", pXferVar->pu8_data != NULL);
147 
148  // Copy the data over to the largest available var for formatting.
149  // This means strings won't work. How to fix this?
150  u_size = pXferVar->u8_size + 1;
151  ASSERT(u_size <= sizeof(um_buf));
152  memcpy(&um_buf, pXferVar->pu8_data, u_size);
153 
154  // Copy the data over to the largest available var for formatting. Using a
155  // #defined sprintf to work around MSVC's naming of that function.
156  i_ret = SNPRINTF(psz_buf, s_len, pXferVar->psz_format, um_buf);
157  return i_ret;
158 }
159 #endif
160 
161 #ifdef MICROCONTROLLER
162 
163 #include "pic24_clockfreq.h"
164 #include "pic24_util.h"
165 #include "pic24_serial.h"
166 
167 uint
168 receiveVar(char* p_c) {
169  // Receive the data by stepping the machine until it outputs
170  // something
171  do {
172  // While there's no data, run the timeout counter
173  RECEIVE_ERROR re;
174  uint32_t u32_count = 0;
175  while (!isCharReady()) {
176  if (u32_count < RECEIVE_TIMEOUT)
177  u32_count++;
178  doHeartbeat();
179  }
180 
181  // Step the machine
182  *p_c = inChar();
183  if (u32_count >= RECEIVE_TIMEOUT)
184  notifyOfTimeout();
185  re = stepReceiveMachine(*p_c);
186  if (re != ERR_NONE) {
187  outString("Data receive error: ");
189  outChar('\n');
190  }
191  } while (!isReceiveMachineChar() && !isReceiveMachineData());
192 
193  // Note that p_c already contains the received character, since it's
194  // always the last thing received from inChar().
195  return getReceiveMachineIndex();
196 }
197 
198 char
199 inCharXfer() {
200  char c;
201  while (receiveVar(&c) != CHAR_RECEIVED_INDEX);
202  return c;
203 }
204 
205 #else
206 BOOL receiveVar(char c_in, char* pc_out, uint* pu_index,
207  uint64_t u64_timeMs, const char** psz_error) {
208 
209  static uint64_t u64_timeLastMs = 0;
210  uint64_t u64_timeDeltaMs;
211  RECEIVE_ERROR re;
212 
213  // Check for 100 ms timeout.
214  u64_timeDeltaMs = u64_timeMs - u64_timeLastMs;
215  u64_timeLastMs = u64_timeMs;
216  if (u64_timeDeltaMs > 100)
217  notifyOfTimeout();
218 
219  // Step the machine
220  re = stepReceiveMachine(c_in);
221  if (re != ERR_NONE) {
222  *psz_error = getReceiveErrorString();
223  return FALSE;
224  } else {
225  *psz_error = NULL;
226  }
227  if (isReceiveMachineChar()) {
228  *pc_out = getReceiveMachineOutChar();
229  *pu_index = CHAR_RECEIVED_INDEX;
230  return TRUE;
231  }
232  if (isReceiveMachineData()) {
233  *pu_index = getReceiveMachineIndex();
234  return TRUE;
235  }
236  return FALSE;
237 }
238 #endif
void doHeartbeat(void)
Definition: pic24_util.c:104
unsigned int uint
An abbreviation for an unsigned integer.
Definition: dataXferImpl.h:190
void resetReceiveMachine()
Definition: dataXferImpl.c:160
#define NUM_XFER_VARS
Definition: dataXferImpl.h:335
int formatVar(uint u_varIndex, char *psz_buf, size_t s_len)
Definition: dataXfer.c:132
#define CMD_SEND_RECEIVE_VAR
Definition: dataXferImpl.h:221
void outCharXfer(char c)
Definition: dataXfer.c:27
#define VAR_SIZE_BITS
Definition: dataXferImpl.h:225
uint8_t isCharReady(void)
Definition: pic24_serial.c:316
BOOL
Definition: all_generic.h:402
const char * getReceiveErrorString()
Returns an error string matching the last error code.
Definition: dataXferImpl.c:612
Routines which implement the uC comm protocol.
uint8_t inChar(void)
Definition: pic24_serial.c:277
#define SHORT_VAR_MAX_LEN
Definition: dataXferImpl.h:232
Configures the system clock.
uint getReceiveMachineIndex()
Definition: dataXferImpl.c:141
XFER_VAR xferVar[NUM_XFER_VARS]
A table to hold the state of transfer variables.
Definition: dataXferImpl.c:100
#define RECEIVE_TIMEOUT
Definition: dataXfer.h:45
uint receiveVar(char *c)
void outString(const char *psz_s)
Definition: pic24_serial.c:90
void clearReceiveStruct()
Definition: dataXferImpl.c:188
#define CMD_TOKEN
Definition: dataXferImpl.h:205
BOOL isReceiveMachineData()
Definition: dataXferImpl.c:206
char * psz_format
printf format string to use in displaying the variable. PC only.
Definition: dataXferImpl.h:321
void specifyVar(uint u_varIndex, volatile void *pv_data, uint u_size, BOOL b_isWriteable, char *psz_format, char *psz_name, char *psz_desc)
Definition: dataXfer.c:36
void outChar(uint8_t u8_c)
A system-dependent macro to output one character.
Definition: pic24_serial.c:58
BOOL isReceiveMachineChar()
Definition: dataXferImpl.c:200
void assignBit(uint u_index, BOOL b_bitVal)
Definition: dataXferImpl.c:267
RECEIVE_ERROR
Definition: dataXferImpl.h:381
char inCharXfer()
uint8_t * pu8_data
Definition: dataXferImpl.h:316
RECEIVE_ERROR stepReceiveMachine(char c_inChar)
Definition: dataXferImpl.c:374
void initDataXfer()
Definition: dataXfer.c:17
#define ASSERT(test)
#define CHAR_RECEIVED_INDEX
Definition: dataXferImpl.h:358
RECEIVE_ERROR notifyOfTimeout()
Definition: dataXferImpl.c:361
void sendVar(uint u_varIndex)
Definition: dataXfer.c:88
#define ESCAPED_CMD
Definition: dataXferImpl.h:209
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194
uint8_t u8_size
Size of data in bytes - 1: 0 = 1 byte, etc.
Definition: dataXferImpl.h:318
#define CMD_LONG_VAR
Definition: dataXferImpl.h:213
char getReceiveMachineOutChar()
Definition: dataXferImpl.c:137
#define CMD_SEND_ONLY
Definition: dataXferImpl.h:217
BOOL isVarWriteable(uint u_index)
Definition: dataXferImpl.c:279
#define ASSERTM(msg, expr)
An assert with message macro; the msg isn&#39;t used in C.
Definition: dataXferImpl.h:182