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