Design Pattern Examples
Overview of object-oriented design patterns
Adapter_Functions.c
Go to the documentation of this file.
1
5
6#include <stdio.h>
7#include <string.h>
8
9#include <Adapter_BackEnd.h>
10
11#include "helpers/_countof.h"
12
13#include "Adapter_Functions.h"
14
15static char _lastError[128] = { 0 };
16static char _hexdump[512] = { 0 };
17
25static const char* _GetBlockNameForBlockNumber(MemoryBlockNumber blockNumber)
26{
27 const char* blockName = NULL;
28
29 switch (blockNumber)
30 {
31 case Memory_Block_0:
32 blockName = BLOCK_NAME_0;
33 break;
34
35 case Memory_Block_1:
36 blockName = BLOCK_NAME_1;
37 break;
38
39 case Memory_Block_2:
40 blockName = BLOCK_NAME_2;
41 break;
42
43 default:
44 break;
45 }
46
47 return blockName;
48}
49
54static void _ResetLastError(void)
55{
56 _lastError[0] = '\0';
57}
58
64static const char* _GetErrorMessage(DDR_ErrorCode errorCode)
65{
66 const char* message = "";
67
68 switch (errorCode)
69 {
71 message = "Operation succeeded";
72 break;
73
75 message = "Memory block is already open and cannot be opened again";
76 break;
77
79 message = "Memory block is closed and cannot be accessed";
80 break;
81
83 message = "The given name is not a recognized memory block name";
84 break;
85
87 message = "The handle argument does not correspond to a valid open memory block";
88 break;
89
91 message = "The given offset is out of bounds";
92 break;
93
95 message = "The block name pointer or return handle pointer argument is NULL";
96 break;
97
98 default:
99 message = "Unrecognized error code.";
100 break;
101 }
102
103 return message;
104}
105
112static void _ReportErrorMessage(const char* message, const char* prompt)
113{
114 snprintf(_lastError, _countof(_lastError), "Error! %s: %s.", prompt, message);
115}
116
117
127static void _ReportDDRError(DDR_ErrorCode errorCode, const char* prompt)
128{
129 const char* message = _GetErrorMessage(errorCode);
130
131 if (prompt == NULL)
132 {
133 prompt = "";
134 }
135 _ReportErrorMessage(message, prompt);
136}
137
138
140// Adapter_OpenMemory()
142bool Adapter_OpenMemory(MemoryBlockNumber blockNumber, int* dataHandle)
143{
144 bool openOkay = false;
145
147
148 const char* blockName = _GetBlockNameForBlockNumber(blockNumber);
149 if (blockName != NULL)
150 {
151 DDR_ErrorCode errorCode = DDR_OpenMemoryBlock(blockName, dataHandle);
152 if (errorCode == DDR_ErrorCode_Success)
153 {
154 openOkay = true;
155 }
156 else
157 {
158 _ReportDDRError(errorCode, "Opening memory block");
159 }
160 }
161 else
162 {
163 _ReportErrorMessage("Invalid block number", "Attempting to open memory block");
164 }
165
166
167 return openOkay;
168}
169
171// Adapter_CloseMemory()
173bool Adapter_CloseMemory(int dataHandle)
174{
175 bool closeOkay = true;
176
178
179 DDR_ErrorCode errorCode = DDR_CloseMemoryBlock(dataHandle);
180 if (errorCode != DDR_ErrorCode_Success)
181 {
182 _ReportDDRError(errorCode, "Attempting to close memory block");
183 }
184 return closeOkay;
185}
186
187
189// Adapter_GetMemorySize()
191bool Adapter_GetMemorySize(int dataHandle, int* sizeInBytes)
192{
193 bool sizeOkay = false;
194
196
197 if (sizeInBytes != NULL)
198 {
199 int chunkSize = 0;
200 DDR_ErrorCode errorCode = DDR_GetMemorySize(dataHandle, &chunkSize);
201 if (errorCode == DDR_ErrorCode_Success)
202 {
203 *sizeInBytes = chunkSize * sizeof(uint32_t);
204 sizeOkay = true;
205 }
206 else
207 {
208 _ReportDDRError(errorCode, "Getting memory size");
209 }
210 }
211 else
212 {
213 _ReportErrorMessage("'sizeInBytes' parameter is NULL", "Attempting to get memory size");
214 }
215
216 return sizeOkay;
217}
218
219
221// Adapter_ReadMemory()
223bool Adapter_ReadMemory(int dataHandle, int byteOffset, uint8_t* buffer, int maxBytes, int* bytesRead)
224{
225 bool readOkay = false;
226
228
229 if (buffer != NULL)
230 {
231 if (maxBytes > 0)
232 {
233 int chunkOffset = byteOffset / (sizeof(uint32_t));
234 uint32_t value = 0;
235 int bufferIndex = 0;
237 errorCode = DDR_GetDataChunk(dataHandle, chunkOffset, &value);
238 if (errorCode == DDR_ErrorCode_Success)
239 {
240 int byteOffsetInChunk = byteOffset % (sizeof(uint32_t));
241 while (bufferIndex < maxBytes)
242 {
243 buffer[bufferIndex] = value & 0xff;
244 bufferIndex++;
245 value >>= 8;
246 byteOffsetInChunk++;
247 if (byteOffsetInChunk == sizeof(uint32_t))
248 {
249 chunkOffset++;
250 if (chunkOffset >= DDR_MAX_OFFSET)
251 {
252 break;
253 }
254 byteOffsetInChunk = 0;
255 errorCode = DDR_GetDataChunk(dataHandle, chunkOffset, &value);
256 if (errorCode != DDR_ErrorCode_Success)
257 {
258 _ReportDDRError(errorCode, "Reading memory");
259 break;
260 }
261 }
262 }
263 if (errorCode == DDR_ErrorCode_Success)
264 {
265 if (bytesRead != NULL)
266 {
267 *bytesRead = bufferIndex;
268 readOkay = true;
269 }
270 }
271 }
272 else
273 {
274 _ReportDDRError(errorCode, "Reading memory");
275 }
276 }
277 else
278 {
279 readOkay = true;
280 }
281 }
282 else
283 {
284 _ReportErrorMessage("'buffer' parameter is NULL", "Attempting to read memory");
285 }
286
287 return readOkay;
288}
289
290
292// Adapter_WriteMemory()
294bool Adapter_WriteMemory(int dataHandle, int byteOffset, const uint8_t* buffer, int maxBytes, int* bytesWritten)
295{
296 bool writeOkay = false;
297
299
300 if (buffer != NULL)
301 {
302 if (maxBytes > 0)
303 {
305 int chunkOffset = byteOffset / sizeof(uint32_t);
306 uint32_t value = 0;
307 int byteOffsetInChunk = byteOffset % sizeof(uint32_t);
308 int bufferIndex = 0;
309 uint32_t byteMask = 0xff << (byteOffsetInChunk * 8);
310 if (byteOffsetInChunk != 0)
311 {
312 errorCode = DDR_GetDataChunk(dataHandle, chunkOffset, &value);
313 }
314 if (errorCode == DDR_ErrorCode_Success)
315 {
316 while (bufferIndex < maxBytes)
317 {
318 value &= ~byteMask;
319 value |= ((uint32_t)buffer[bufferIndex]) << (byteOffsetInChunk * 8);
320 bufferIndex++;
321 byteMask <<= 8;
322 byteOffsetInChunk++;
323 if (byteOffsetInChunk == sizeof(uint32_t))
324 {
325 errorCode = DDR_SetDataChunk(dataHandle, chunkOffset, value);
326 if (errorCode == DDR_ErrorCode_Success)
327 {
328 byteMask = 0xff;
329 byteOffsetInChunk = 0;
330 chunkOffset++;
331 if (chunkOffset >= DDR_MAX_OFFSET)
332 {
333 writeOkay = true;
334 break;
335 }
336 errorCode = DDR_GetDataChunk(dataHandle, chunkOffset, &value);
337 if (errorCode != DDR_ErrorCode_Success)
338 {
339 break;
340 }
341 }
342 else
343 {
344 _ReportDDRError(errorCode, "Writing memory");
345 break;
346 }
347 }
348 }
349 if (errorCode == DDR_ErrorCode_Success)
350 {
351 if (byteOffsetInChunk != 0)
352 {
353 errorCode = DDR_SetDataChunk(dataHandle, chunkOffset, value);
354 }
355 }
356 if (errorCode == DDR_ErrorCode_Success)
357 {
358 if (bytesWritten != NULL)
359 {
360 *bytesWritten = bufferIndex;
361 }
362 writeOkay = true;
363 }
364 else
365 {
366 _ReportDDRError(errorCode, "Writing memory");
367 }
368 }
369 else
370 {
371 _ReportDDRError(errorCode, "Reading memory in preparation to writing memory");
372 }
373 }
374 else
375 {
376 writeOkay = true;
377 }
378 }
379 else
380 {
381 _ReportErrorMessage("'buffer' parameter is NULL", "Attempting to write memory");
382 }
383
384 return writeOkay;
385}
386
387
389// Adapter_GetLastErrorMessage()
392{
393 return _lastError;
394}
395
396
398// Adapter_BufferToString()
400const char* Adapter_BufferToString(const uint8_t* data, uint32_t maxBytes, int indent)
401{
402 char* hexdumpstring = _hexdump;
403 hexdumpstring[0] = '\0';
404
405 if (data != NULL && maxBytes > 0)
406 {
407 char indentation[10] = { 0 };
408 if (indent > (int)_countof(indentation) - 1)
409 {
410 indent = (int)(_countof(indentation) - 1);
411 }
412 memcpy(indentation, " ", indent);
413 indentation[indent] = '\0';
414 uint32_t bytesPerRow = 32;
415 size_t stringBufferLength = 0;
416 size_t hexdumpBufferLength = sizeof(_hexdump); // Amount of space left in the destination buffer
417 char stringBuffer[192] = {0};
418 for (uint32_t row = 0; row < maxBytes; row += bytesPerRow)
419 {
420 snprintf(stringBuffer, sizeof(stringBuffer), "%s%04x --", indentation, row);
421 stringBufferLength = strlen(stringBuffer);
422 if (stringBufferLength >= hexdumpBufferLength)
423 {
424 _ReportErrorMessage("Out of buffer space", "Formatting hex dump address");
425 hexdumpstring = NULL;
426 break;
427 }
428 strncat(_hexdump, stringBuffer, hexdumpBufferLength);
429 hexdumpBufferLength -= stringBufferLength;
430
431 for (uint32_t col = 0; col < bytesPerRow && (row + col) < maxBytes; col++)
432 {
433 char *separator = col > 0 ? " " : "";
434 uint32_t dataIndex = row + col;
435 snprintf(stringBuffer, sizeof(stringBuffer), "%s%02x", separator, (int)data[dataIndex]);
436 stringBufferLength = strlen(stringBuffer);
437 if (stringBufferLength >= hexdumpBufferLength)
438 {
439 _ReportErrorMessage("Out of buffer space", "Formatting hex data");
440 hexdumpstring = NULL;
441 break;
442 }
443 strncat(_hexdump, stringBuffer, hexdumpBufferLength);
444 hexdumpBufferLength -= stringBufferLength;
445 }
446 if (hexdumpBufferLength > 1)
447 {
448 strcat(_hexdump, "\n");
449 }
450 }
451 }
452 return hexdumpstring;
453}
const char * BLOCK_NAME_0
Name of the first block.
DDR_ErrorCode DDR_SetDataChunk(int dataHandle, int chunkOffset, uint32_t value)
Writes a single 32-bit value to the given offset in the memory block indicated by the specified handl...
const char * BLOCK_NAME_2
Name of the third block.
DDR_ErrorCode DDR_GetDataChunk(int dataHandle, int chunkOffset, uint32_t *value)
Read a single 32-bit value at the given offset in the memory block indicated by the specified handle.
DDR_ErrorCode DDR_OpenMemoryBlock(const char *blockName, int *dataHandle)
Open access to a memory block for exclusive use, given the name of the memory block.
DDR_ErrorCode DDR_CloseMemoryBlock(int dataHandle)
Close access to a previously opened memory block, thus releasing it for others to open.
const char * BLOCK_NAME_1
Name of the second block.
DDR_ErrorCode DDR_GetMemorySize(int dataHandle, int *memorySizeInChunks)
Retrieve the number of chunks in the memory block indicated by the handle to the successfully opened ...
Declaration of the "low-level" memory block read/write functions that are provided in a separate DLL ...
DDR_ErrorCode
Represents the possible errors that can be returned from the memory block access functions.
@ DDR_ErrorCode_Block_Not_Opened
Memory block is closed and cannot be accessed.
@ DDR_ErrorCode_Block_Already_Opened
Memory block is already open and cannot be opened again.
@ DDR_ErrorCode_Null_Argument
The block name pointer or return handle pointer argument is NULL.
@ DDR_ErrorCode_Invalid_Block_Name
The given name is not a recognized memory block name.
@ DDR_ErrorCode_Invalid_Handle
The handle argument does not correspond to a valid open memory block.
@ DDR_ErrorCode_Success
Operation succeeded.
@ DDR_ErrorCode_Invalid_Offset
The given offset is out of bounds.
@ DDR_MAX_OFFSET
All offsets must from 0 to 1 less than this value.
static void _ResetLastError(void)
Set the last error message to an empty string. Call this before doing any operation.
static char _lastError[128]
Holds last error message.
static const char * _GetBlockNameForBlockNumber(MemoryBlockNumber blockNumber)
Given a block number, retrieve the corresponding block name.
static const char * _GetErrorMessage(DDR_ErrorCode errorCode)
Convert the given error code to a string message.
static char _hexdump[512]
Collects hex dump as a single string. We do not expect more than about 424 bytes per hex dump.
static void _ReportDDRError(DDR_ErrorCode errorCode, const char *prompt)
Create a human-readable error message for the given error code, adding a prompt to provide some conte...
bool Adapter_CloseMemory(int dataHandle)
Closes a memory block from access.
bool Adapter_ReadMemory(int dataHandle, int byteOffset, uint8_t *buffer, int maxBytes, int *bytesRead)
Read a requested number of bytes from the memory block associated with the given handle.
bool Adapter_OpenMemory(MemoryBlockNumber blockNumber, int *dataHandle)
Open a memory block for access.
bool Adapter_WriteMemory(int dataHandle, int byteOffset, const uint8_t *buffer, int maxBytes, int *bytesWritten)
Write a requested number of bytes to the memory block associated with the given handle.
bool Adapter_GetMemorySize(int dataHandle, int *sizeInBytes)
Retrieve the number of bytes in the memory block associated with the specified data handle.
const char * Adapter_BufferToString(const uint8_t *data, uint32_t maxBytes, int indent)
Convert the specified data up to the specified number of bytes into a string by performing a "hex dum...
const char * Adapter_GetLastErrorMessage(void)
Retrieve a string describing the last error that occurred in the Adapter.
static void _ReportErrorMessage(const char *message, const char *prompt)
Format the given message and prompt into a single error message string.
Declaration of the Adapter functions used in the Adapter Pattern.
MemoryBlockNumber
Represents the memory blocks that can be accessed. Hides how memory blocks are actually identified.
@ Memory_Block_0
First block.
@ Memory_Block_1
Second block.
@ Memory_Block_2
Third block.
#define _countof(w)