DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
WIB_Flash.cpp
Go to the documentation of this file.
2#include "wibmod/WIB1/WIB.hh"
4#include <algorithm>
5#include <assert.h>
6#include <fstream>
7#define FLASH_TIMEOUT 400
8
9#define MIN_LINE_LENGTH 10
10#define MAX_LINE_LENGTH 266
11
12static void
13ParseIHexLine(std::string line, std::vector<uint8_t>& data, uint32_t& upperAddr)
14{
15 if (line.empty()) {
16 BUException::WIB_FLASH_IHEX_ERROR e;
17 e.Append("line is empty");
18 throw e;
19 } else if (line[0] != ':') {
20 BUException::WIB_FLASH_IHEX_ERROR e;
21 e.Append("BAD Line in file - does not start with ':'");
22 throw e;
23 } else {
24 line.erase(0, 1);
25 }
26 if (line.size() < MIN_LINE_LENGTH) {
27 BUException::WIB_FLASH_IHEX_ERROR e;
28 e.Append("BAD Line in file - incomplete intel hex format\n");
29 throw e;
30 } else if (line.size() > MAX_LINE_LENGTH) {
31 BUException::WIB_FLASH_IHEX_ERROR e;
32 e.Append("BAD Line in file - intel hex format not supported, contains too many characters\n");
33 throw e;
34 } else if (line.size() & 1) {
35 BUException::WIB_FLASH_IHEX_ERROR e;
36 e.Append("BAD Line in file - uneven number of characters\n");
37 throw e;
38 } else {
39 char const* entry = line.c_str();
40 uint32_t line_sum = 0, byte_count = 0, address = 0, record_type = 0;
41
42 uint32_t byte = 0;
43 for (uint32_t iSum = 0; iSum < line.size(); iSum += 2) {
44 sscanf(entry + iSum, "%2x", &byte);
45 line_sum += byte;
46 }
47 // the content of the line is cancelled out through addition to its
48 // two's complement which is the checksum if all data is intact
49
50 if (0xFF & line_sum) {
51 line_sum = 0xFF & line_sum;
52 BUException::WIB_FLASH_IHEX_ERROR e;
53 e.Append("BAD Line in file - content inconsistent with checksum.\n");
54 throw e;
55 } else {
56 line_sum = 0;
57 }
58
59 sscanf(entry, "%2x %4x %2x ", &byte_count, &address, &record_type);
60 if (4 == record_type) {
61 upperAddr = 0;
62 sscanf(entry + 8, "%4x", &upperAddr);
63 upperAddr = upperAddr << 16;
64 } else if (0 == record_type) {
65 address = upperAddr + address;
66 if (data.size() < (address + byte_count)) {
67 data.resize(address + byte_count, 0xFF);
68 }
69 for (uint32_t iAddr = 0; iAddr < byte_count; iAddr++) {
70 uint32_t tempData = 0;
71 sscanf(entry + (iAddr * 2) + 8, "%02x", &tempData);
72 data[address + iAddr] = (uint8_t)tempData;
73 }
74 }
75 }
76}
77
78void
79LoadIHexFile(std::vector<uint8_t>& data, const char* file)
80{
81 std::string line;
82 std::ifstream datafile(file);
83 uint32_t upperAddr = 0;
84 if (datafile.is_open()) {
85 while (getline(datafile, line)) {
86 ParseIHexLine(line, data, upperAddr);
87 }
88 } else {
89 BUException::WIB_FLASH_IHEX_ERROR e;
90 e.Append("Unable to open file ");
91 e.Append(file);
92 throw e;
93 }
94}
95
96static std::vector<uint32_t>
97firmwareFromIntelHexFile(std::string const& iHexFileName)
98{
99 // Ihex parser loads intel hex into a vector of bytes.
100 std::vector<uint8_t> rawData;
101 LoadIHexFile(rawData, iHexFileName.c_str());
102
103 // We now need to convert it to a uint32_t
104 // This has the issue of what to do if we are off by 32bit boundary.
105 // For now we'll just die so we don't have to deal with the issue.
106 // Make sure this is called before we erase the flash :-p
107 if ((rawData.size() & 0x3) != 0x0) {
108 BUException::WIB_FLASH_IHEX_ERROR e;
109 e.Append("Flash data is not a multiple of 32bit words");
110 throw e;
111 } else if (0 == rawData.size()) {
112 BUException::WIB_FLASH_IHEX_ERROR e;
113 e.Append("Flash data is empty");
114 throw e;
115 }
116
117 // Create a std::vector<uint32_t> and fill it with rawData;
118 std::vector<uint32_t> ret;
119 for (size_t iRawData = 0; iRawData < rawData.size(); iRawData += 4) {
120 // Build the 32bit word
121 uint32_t tempData = (rawData[iRawData + 0] << 0 | rawData[iRawData + 1] << 8 | rawData[iRawData + 2] << 16 |
122 rawData[iRawData + 3] << 24);
123 ret.push_back(tempData);
124 }
125 return ret;
126}
127
128void
129WIB::ReadFlash(std::string const& fileName, uint8_t update_percentage)
130{
131 bool print_updates = false;
132 if (update_percentage < 100) {
133 print_updates = true;
134 }
135 size_t update_delta = (update_percentage * float(16 * 1024 * 1024 / 4)) / 100;
136 size_t next_update = update_delta;
137
138 FILE* outFile = fopen(fileName.c_str(), "w");
139 if (outFile == NULL) {
140 BUException::WIB_BAD_ARGS e;
141 e.Append("Failed to create: ");
142 e.Append(fileName);
143 throw e;
144 }
145
146 if (print_updates) {
147 fprintf(stderr, " Reading flash\n");
148 fprintf(stderr, " [");
149 for (size_t i = 0; i < 100.0 / update_percentage; i++) {
150 fprintf(stderr, "=");
151 }
152 fprintf(stderr, "]\n [");
153 }
154 // program flash in groups of 64 32bit words (256 bytes)
155 uint32_t address = 0;
156
157 uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address;
158 size_t blockSize = 64;
159 // set block size
160 WriteWithRetry("FLASH.BYTE_COUNT", 255);
161
162 for (size_t iWord = 0; iWord < 16 * 1024 * 1024 / 4;) {
164
165 // Set adddress
166 WriteWithRetry("FLASH.ADDRESS", address);
167 // Start read
168 WriteWithRetry("FLASH.RUN_COMMAND", 0x5);
169
171
172 // Readout the data
173 for (size_t iWordRead = 0; iWordRead < blockSize; iWordRead++) {
174 fprintf(outFile, "0x%06X 0x%08X\n", uint32_t(iWord), ReadWithRetry(blockRegMapAddress + iWordRead));
175 iWord++;
176 }
177
178 // iWord+= blockSize;
179 address += blockSize * 4;
180
181 if (print_updates && (iWord > next_update)) {
182 // printf(" % 3f%% done\n",float(iWord)/float(flashData.size()));
183 fprintf(stderr, "=");
184 next_update += update_delta;
185 }
186 }
187 if (print_updates) {
188 printf("]\n");
189 printf(" done\n");
190 }
191 fclose(outFile);
192}
193
194void
195WIB::EraseFlash(bool print_updates)
196{
197 if (print_updates) {
198 fprintf(stderr, " Erase flash\n");
199 }
200 WriteWithRetry("FLASH.RUN_COMMAND", 0x7);
201 size_t iTimeout = FLASH_TIMEOUT;
202 while (ReadWithRetry("FLASH.BUSY") && (iTimeout != 0)) {
203 iTimeout--;
204 usleep(100000);
205 }
206 if (iTimeout == 0) {
207 BUException::WIB_FLASH_TIMEOUT e;
208 // throw an exception
209 e.Append("Program (erase): FLASH.BUSY");
210 throw e;
211 // throw an exception
212 }
213}
214
215void
216WIB::ProgramFlash(std::string const& fileName, uint8_t update_percentage)
217{
218 WriteWithRetry("SYSTEM.SLOW_CONTROL_DND", 1);
219
220 bool print_updates = false;
221 if (update_percentage < 100) {
222 print_updates = true;
223 }
224
225 // Load data and validate
226 if (print_updates) {
227 fprintf(stderr, " Reading file: %s\n", fileName.c_str());
228 }
229 // std::vector<uint32_t> flashData = firmwareFromDumpFile(fileName);
230 std::vector<uint32_t> flashData = firmwareFromIntelHexFile(fileName);
231
232 // erase flash
233 EraseFlash(print_updates);
234
235 // Load data into flash.
236 WriteFlash(flashData, update_percentage);
237
238 // Validate flash
239 CheckFlash(flashData, update_percentage);
240 WriteWithRetry("SYSTEM.SLOW_CONTROL_DND", 0);
241}
242
243void
244WIB::WriteFlash(std::vector<uint32_t> flashData, uint8_t update_percentage)
245{
246 // Setup display if needed
247 bool print_updates = false;
248 if (update_percentage < 100) {
249 print_updates = true;
250 }
251 size_t update_delta = (update_percentage * float(flashData.size())) / 100;
252 size_t next_update = update_delta;
253 if (print_updates) {
254 fprintf(stderr, " Programming flash\n");
255 fprintf(stderr, " [");
256 for (size_t i = 0; i < 100.0 / update_percentage; i++) {
257 fprintf(stderr, "=");
258 }
259 fprintf(stderr, "]\n [");
260 }
261
262 // program flash in groups of 64 32bit words (256 bytes)
263 uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address; // Address of first of 64 32bit words
264 uint32_t flashAddress = 0; // Address in flash that we are writing to.
265
266 for (size_t currentBlockStartIndex = 0; currentBlockStartIndex < flashData.size();) {
268
269 // Find size of this block to write (usually just 64 (256bytes)), but the last one might be smaller.
270 size_t blockSize = std::min(size_t(64), flashData.size() - currentBlockStartIndex);
271 // Set adddress
272 WriteWithRetry("FLASH.ADDRESS", flashAddress);
273 // set block size (in bytes and is 1 less than value; 0 means 1 byte, 255 means 256 bytes)
274 WriteWithRetry("FLASH.BYTE_COUNT", (blockSize * sizeof(uint32_t)) - 1);
275
276 // Write block of data
277 for (size_t iBlockWord = 0; iBlockWord < blockSize; iBlockWord++) {
278 // arg1: Address in WIB register map of this 32bit word
279 // arg2: Data for this 32bit word reg map address in data vector
280 WriteWithRetry(blockRegMapAddress + iBlockWord, flashData[currentBlockStartIndex + iBlockWord]);
281 }
282 // Do the block write
283 WriteWithRetry("FLASH.RUN_COMMAND", 0x1);
284 currentBlockStartIndex += blockSize;
285 flashAddress += blockSize * sizeof(uint32_t);
286
287 // Update the screen if needed
288 if (print_updates && (currentBlockStartIndex > next_update)) {
289 fprintf(stderr, "=");
290 next_update += update_delta;
291 }
292 }
293 // Update the screen if needed
294 if (print_updates) {
295 fprintf(stderr, "]\n");
296 fprintf(stderr, " done\n");
297 }
298}
299
300void
301WIB::CheckFlash(std::vector<uint32_t> flashData, uint8_t update_percentage)
302{
303 bool print_updates = false;
304 if (update_percentage < 100) {
305 print_updates = true;
306 }
307 size_t update_delta = (update_percentage * float(16 * 1024 * 1024 / 4)) / 100;
308 size_t next_update = update_delta;
309
310 if (print_updates) {
311 fprintf(stderr, " Checking flash\n");
312 fprintf(stderr, " [");
313 for (size_t i = 0; i < 100.0 / update_percentage; i++) {
314 fprintf(stderr, "=");
315 }
316 fprintf(stderr, "]\n [");
317 }
318 // program flash in groups of 64 32bit words (256 bytes)
319 uint32_t flashAddress = 0;
320 uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address;
321
322 for (size_t currentBlockStartIndex = 0; currentBlockStartIndex < 16 * 1024 * 1024 / 4;) {
324
325 // Find size of this block to write (usually just 64 (256bytes)), but the last one might be smaller.
326 size_t blockSize = std::min(size_t(64), flashData.size() - currentBlockStartIndex);
327 // Set adddress
328 WriteWithRetry("FLASH.ADDRESS", flashAddress);
329 // set block size (in bytes and is 1 less than value; 0 means 1 byte, 255 means 256 bytes)
330 WriteWithRetry("FLASH.BYTE_COUNT", (blockSize * sizeof(uint32_t)) - 1);
331 // Start read
332 WriteWithRetry("FLASH.RUN_COMMAND", 0x5);
333
335
336 // Check the data.
337 for (size_t iBlockWord = 0; iBlockWord < blockSize; iBlockWord++) {
338 // flashData: Address in WIB register map of this 32bit word
339 // ReadWithRetry: Data from the flash for this word
340 uint32_t dataRead;
341 if ((dataRead = ReadWithRetry(blockRegMapAddress + iBlockWord)) !=
342 flashData[currentBlockStartIndex + iBlockWord]) {
343 BUException::WIB_FLASH_ERROR e;
344 char errorbuffer[] = "Error on index 0xXXXXXXXX: 0xXXXXXXXX != 0xXXXXXXXX";
345 snprintf(errorbuffer,
346 strlen(errorbuffer),
347 "Error on index 0x%08X: 0x%08X != 0x%08X",
348 flashAddress,
349 dataRead,
350 flashData[currentBlockStartIndex + iBlockWord]);
351 e.Append(errorbuffer);
352 throw e;
353 }
354 }
355 currentBlockStartIndex += blockSize;
356 flashAddress += blockSize * sizeof(uint32_t);
357
358 if (print_updates && (currentBlockStartIndex > next_update)) {
359 fprintf(stderr, "=");
360 next_update += update_delta;
361 }
362 }
363 if (print_updates) {
364 printf("]\n");
365 printf(" Check passed\n");
366 }
367}
368
369void
371{
372 size_t iTimeout = FLASH_TIMEOUT;
373 while (ReadWithRetry("FLASH.BUSY") && (iTimeout != 0)) {
374 iTimeout--;
375 usleep(10000);
376 }
377 if (iTimeout == 0) {
378 BUException::WIB_FLASH_TIMEOUT e;
379 // throw an exception
380 e.Append("Read: FLASH.BUSY");
381 throw e;
382 }
383}
static void ParseIHexLine(std::string line, std::vector< uint8_t > &data, uint32_t &upperAddr)
Definition WIB_Flash.cpp:13
#define FLASH_TIMEOUT
Definition WIB_Flash.cpp:7
#define MIN_LINE_LENGTH
Definition WIB_Flash.cpp:9
void LoadIHexFile(std::vector< uint8_t > &data, const char *file)
Definition WIB_Flash.cpp:79
static std::vector< uint32_t > firmwareFromIntelHexFile(std::string const &iHexFileName)
Definition WIB_Flash.cpp:97
#define MAX_LINE_LENGTH
Definition WIB_Flash.cpp:10
uint16_t address
void WriteWithRetry(uint16_t address, uint32_t value)
Definition WIBBase.cpp:163
uint32_t ReadWithRetry(uint16_t address)
Definition WIBBase.cpp:142
Item const * GetItem(std::string const &)
Definition WIBBase.cpp:125
void EraseFlash(bool print_updates=false)
void WriteFlash(std::vector< uint32_t > data, uint8_t update_percentage=101)
void FlashCheckBusy()
void ReadFlash(std::string const &fileName, uint8_t update_percentage=101)
void ProgramFlash(std::string const &fileName, uint8_t update_percentage=101)
void CheckFlash(std::vector< uint32_t > data, uint8_t update_percentage=101)