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