AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
ntv2konaflashprogram.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
7 #include "ntv2konaflashprogram.h"
8 #include "ntv2endian.h"
9 #include "ntv2registersmb.h"
10 #include "ajabase/system/debug.h"
12 #include "ajabase/common/common.h"
13 #include <ctime>
14 #ifdef MSWindows
15  #pragma warning(disable: 4305) // Initialization warnings.
16  #pragma warning(disable: 4309)
17  #pragma warning(disable: 4800)
18  #pragma warning(disable: 4996)
19 #endif
20 
21 #define ENUM_CASE_RETURN_VAL_OR_ENUM_STR(condition, retail_name, enum_name)\
22  case(enum_name): return condition ? retail_name : #enum_name
23 
24 using namespace std;
25 
26 #define KFPDBUG(__x__) AJA_sDEBUG (AJA_DebugUnit_Firmware, AJAFUNC << ": " << __x__)
27 #define KFPWARN(__x__) AJA_sWARNING (AJA_DebugUnit_Firmware, AJAFUNC << ": " << __x__)
28 #define KFPERR(__x__) do {ostringstream oss; oss << AJAFUNC << ": " << __x__; cerr << "## ERROR: " << oss.str() << endl; AJA_sERROR (AJA_DebugUnit_Firmware, oss.str());} while(false)
29 #define KFPNOTE(__x__) do {ostringstream oss; oss << AJAFUNC << ": " << __x__; if (!_bQuiet) cout << "## NOTE: " << oss.str() << endl; AJA_sNOTICE (AJA_DebugUnit_Firmware, oss.str());} while(false)
30 
31 
32 string MacAddr::AsString(void) const
33 {
34  ostringstream oss;
35  oss << xHEX0N(uint16_t(mac[0]),2) << ":" << xHEX0N(uint16_t(mac[1]),2) << ":" << xHEX0N(uint16_t(mac[2]),2)
36  << ":" << xHEX0N(uint16_t(mac[3]),2) << ":" << xHEX0N(uint16_t(mac[4]),2) << ":" << xHEX0N(uint16_t(mac[5]),2);
37  return oss.str();
38 }
39 
41 
43 
44 string CNTV2KonaFlashProgram::FlashBlockIDToString (const FlashBlockID inID, const bool inShortDisplay)
45 {
46  switch (inID)
47  {
48  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "Main", MAIN_FLASHBLOCK);
49  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "FailSafe", FAILSAFE_FLASHBLOCK);
50  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "Auto", AUTO_FLASHBLOCK);
51  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "SOC1", SOC1_FLASHBLOCK);
52  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "SOC2", SOC2_FLASHBLOCK);
53  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "Mac", MAC_FLASHBLOCK);
54  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "MCS", MCS_INFO_BLOCK);
55  ENUM_CASE_RETURN_VAL_OR_ENUM_STR(inShortDisplay, "License", LICENSE_BLOCK);
56  }
57  return "";
58 }
59 
60 
62  : CNTV2Card (),
63  _bitFileSize (0),
64  _flashSize (0),
65  _bankSize (0),
66  _sectorSize (0),
67  _mainOffset (0),
68  _failSafeOffset (0),
69  _macOffset (0),
70  _mcsInfoOffset (0),
71  _licenseOffset (0),
72  _soc1Offset (0),
73  _soc2Offset (0),
74  _numSectorsMain (0),
75  _numSectorsSOC1 (0),
76  _numSectorsSOC2 (0),
77  _numSectorsFailSafe (0),
78  _numBytes (0),
79  _flashID (MAIN_FLASHBLOCK),
80  _deviceID (0),
81  _bQuiet (false),
82  _mcsStep (0),
83  _failSafePadding (0),
84  _spiFlash (AJA_NULL),
85  _hasExtendedCommandSupport (false)
86 {
87 }
88 
90  : CNTV2Card (boardNumber),
91  _bitFileSize (0),
92  _flashSize (0),
93  _bankSize (0),
94  _sectorSize (0),
95  _mainOffset (0),
96  _failSafeOffset (0),
97  _macOffset (0),
98  _mcsInfoOffset (0),
99  _licenseOffset (0),
100  _soc1Offset (0),
101  _soc2Offset (0),
102  _numSectorsMain (0),
103  _numSectorsSOC1 (0),
104  _numSectorsSOC2 (0),
105  _numSectorsFailSafe (0),
106  _numBytes (0),
107  _flashID (MAIN_FLASHBLOCK),
108  _deviceID (0),
109  _bQuiet (false),
110  _mcsStep (0),
111  _failSafePadding (0),
112  _spiFlash (AJA_NULL),
113  _hasExtendedCommandSupport (false)
114 {
116 }
117 
119 {
120  if (_spiFlash)
121  delete _spiFlash;
122 }
123 
125 {
126  _bQuiet = true;
127  if (_spiFlash)
128  _spiFlash->SetVerbosity(false);
129 }
130 
132 {
133  ULWord theCommand = (ULWord)inCommand;
135  theCommand |= BIT_16;
136 
137  return WriteRegister(kRegXenaxFlashControlStatus, theCommand);
138 }
139 
141 {
142  if (!features().CanDoIP())
143  return false;
144  bool resetOK(false);
145  // Hold MB in reset
146  if ((GetDeviceID() == DEVICE_ID_IOIP_2022) ||
149  resetOK = WriteRegister(SAREK_REGS + kRegSarekControl, 0x02);
150  else if (GetDeviceID() == DEVICE_ID_KONAIP_2022 ||
153  resetOK = WriteRegister(SAREK_REGS + kRegSarekControl, 0x01);
154  // Take SPI bus control
155  return resetOK && WriteRegister(SAREK_REGS + kRegSarekSpiSelect, 0x01);
156 }
157 
158 bool CNTV2KonaFlashProgram::IsInstalledFWRunning (bool & outIsRunning, ostream & outMsgs)
159 {
160  UWord runningYear(0), runningMonth(0), runningDay(0);
161  outIsRunning = false;
162 
163  // Get running FW date...
164  if (!GetRunningFirmwareDate (runningYear, runningMonth, runningDay))
165  {
167  outMsgs << "## WARNING: Failed to get running firmware date/time" << endl;
168  return false;
169  }
170 
171  // Convert running FW date to time_t...
172  std::tm tm; ::memset(&tm, 0, sizeof(tm)); // zero
173  tm.tm_year = int(runningYear) - 1900; // Year
174  tm.tm_mon = int(runningMonth) - 1; // Month
175  tm.tm_mday = int(runningDay); // Day
176  tm.tm_hour = 11; // near mid-day
177  tm.tm_isdst = 0; // Standard time (not DST)
178  std::time_t tRunning (std::mktime(&tm));
179 
180  // Read & parse Main installed FW header...
182  {outMsgs << "## WARNING: Failed to ReadHeader or ParseHeader" << endl; return false;}
183 
184  string installedBuildDate(GetDate());
185  // TEST: same as running FW date: ostringstream oss; oss << DEC(runningYear) << "/" << DEC0N(runningMonth,2) << "/" << DEC0N(runningDay+0,2); installedBuildDate = oss.str();
186  // TEST: 1 day past running FW date: ostringstream oss; oss << DEC(runningYear) << "/" << DEC0N(runningMonth,2) << "/" << DEC0N(runningDay+1,2); installedBuildDate = oss.str();
187  // TEST: 2 days past running FW date: ostringstream oss; oss << DEC(runningYear) << "/" << DEC0N(runningMonth,2) << "/" << DEC0N(runningDay+2,2); installedBuildDate = oss.str();
188  if (installedBuildDate.empty() || installedBuildDate.length() < 10 || installedBuildDate.at(4) != '/')
189  {outMsgs << "## WARNING: Bad installed firmware date '" << installedBuildDate << "'" << endl; return false;}
190 
191  // Convert installed FW date to time_t...
192  tm.tm_year = int(aja::stol(installedBuildDate.substr(0, 4))) - 1900; // Year
193  tm.tm_mon = int(aja::stol(installedBuildDate.substr(5, 2))) - 1; // Month
194  tm.tm_mday = int(aja::stol(installedBuildDate.substr(8, 2))); // Day
195  tm.tm_hour = 11; // near mid-day
196  tm.tm_isdst = 0; // Standard time (not DST)
197  std::time_t tInstalled (std::mktime(&tm));
198 
199  // Calculate seconds between the two dates...
200  ULWord secsApart (ULWord(::difftime(tInstalled, tRunning)));
201  if (secsApart == 0)
202  outIsRunning = true; // Same date
203  else if (secsApart <= 86400) // Call them equal even within a day apart
204  {outMsgs << "## WARNING: Installed firmware date is 1 day past running firmware date" << endl; outIsRunning = true;}
205  return true;
206 }
207 
209 {
210  if (!IsOpen())
211  return false;
212 
213  if (!SetDeviceProperties())
214  return false;
215 
216  //For manufacturing use the leds to code the board number
217  uint32_t ledMask = BIT(16)+BIT(17);
218  uint32_t ledShift = 16;
219  return WriteRegister(kRegGlobalControl, index, ledMask, ledShift);
220 
221 }
222 
224 {
225  bool knownChip = false;
226  bool status = false;
227 
229 
230 // case 0x00202018://STMircro
231 // case 0x00012018://CYPRESS S25FL128
232 // case 0x00C22018://Macronix
233 // T-Tap
234 // IoExpress
235 // IoXT
236 // Kona Lhe+
237 // Kona 3G
238 // Kona 3G Quad
239 // Corvid 1
240 // Corvid 22
241 // Corvid 24
242 // Corvid 3G
243 
244 // case 0x00010220://CYPRESS f25fl512
245 // Kona IP 2022
246 // Kona IP 2110
247 // IoIP 2022
248 // IoIP 2110
249 // Io4K+
250 
251 // case 0x009d6019://ISSI
252 // No Product 6/27/18
253 
254 // case 0x00C84018://GIGADEVICE GD25Q127CFIG
255 // case 0x00EF4018://WINBOND W25Q128
256 // T-Tap
257 // IoExpress
258 // IoXT
259 // Kona Lhe+
260 // Kona 3G
261 // Kona 3G Quad
262 // Corvid 1
263 // Corvid 22
264 // Corvid 24
265 // Corvid 3G
266 
267 // case 0x00010219://CYPRESS S25FL256
268 // Kona 1
269 // Kona HDMI
270 // Kona 4
271 // Kona 4 UFC
272 // Corvid 44
273 // Corvid 88
274 // Corvid HBR
275 // Corvid HEVC
276 
277  switch(_deviceID)
278  {
279  case 0x00202018://STMircro
280  case 0x00C22018://Macronix
281  _flashSize = 16 * 1024 * 1024;
282  _bankSize = 16 * 1024 * 1024;
283  _sectorSize = 256 * 1024;
284  _failSafePadding = 1;
285  knownChip = true;
286  break;
287  case 0x00010220://CYPRESS f25fl512
288  _flashSize = 64 * 1024 * 1024;
289  _bankSize = 16 * 1024 * 1024;
290  _sectorSize = 256 * 1024;
291  _failSafePadding = 1;
292  knownChip = true;
293  break;
294  case 0x009d6019://ISSI
295  _flashSize = 64 * 1024 * 1024;
296  _bankSize = 16 * 1024 * 1024;
297  _sectorSize = 64 * 1024;
298  _failSafePadding = 4;
299  knownChip = true;
300  break;
301  case 0x0020ba20://Micron MT25QL512ABB
302  _flashSize = 64 * 1024 * 1024;
303  _bankSize = 16 * 1024 * 1024;
304  _sectorSize = 64 * 1024;
305  _failSafePadding = 4;
307  knownChip = true;
308  break;
309  case 0x00C84018://GIGADEVICE GD25Q127CFIG
310  case 0x00EF4018://WINBOND W25Q128
311  case 0x00012018://CYPRESS S25FL128
312  _flashSize = 16 * 1024 * 1024;
313  _bankSize = 16 * 1024 * 1024;
314  _sectorSize = 64 * 1024;
315  _failSafePadding = 4;
316  knownChip = true;
317  break;
318  case 0x00010219://CYPRESS S25FL256
319  _flashSize = 32 * 1024 * 1024;
320  _bankSize = 16 * 1024 * 1024;
321  _sectorSize = 64 * 1024;
322  _failSafePadding = 4;
323  knownChip = true;
324  break;
325  default:
326  _flashSize = 0;
327  _bankSize = 0;
328  _sectorSize = 0;
329  knownChip = false;
330  break;
331  }
332 
333  if(!knownChip)
334  return false;
335 
337  {
338  default:
339  case 1:
340  //This includes legacy boards such as LHi, Corvid 1...
341  //SPI is devided up into 4 logical blocks of 4M each
342  //Without history explained main is at offset 0 and failsafe is at offset 12
345  _mainOffset = 0;
346  _failSafeOffset = 12 * 1024 * 1024;
347  _macOffset = _bankSize - (2 * _sectorSize);
348  status = true;
349  break;
350  case 2:
353  _mainOffset = 0;
354  _failSafeOffset = 8 * 1024 * 1024;
355  _macOffset = _bankSize - (2 * _sectorSize);
356  status = true;
357  break;
358  case 3:
359  if (_deviceID == 0x010220)
360  {
361  //This is actually SPI v4 but needed this for spoofing Kona4
366  _mainOffset = 0;
367  _soc1Offset = 0;
368  _soc2Offset = 0;
369  _failSafeOffset = 0;// but is really 16*1024*1024;
370  _macOffset = _bankSize - (2 * _sectorSize);
373  status = true;
374  }
375  else
376  {
377  //SPIV3 This gets a little weird both main and failsafe have an offset of 0
378  //and the real offset is controlled by a bank selector switch in firmware
381  _mainOffset = 0;
382  _failSafeOffset = 0;// but is really 16*1024*1024;
383  _macOffset = _bankSize - (2 * _sectorSize);
386  status = true;
387  }
388  break;
389  case 4:
390  //SPIV4 is a bigger SPIv3 2x
395  _mainOffset = 0;
396  _soc1Offset = 0;
397  _soc2Offset = 0;
398  _failSafeOffset = 0;// but is really 16*1024*1024;
399  _macOffset = _bankSize - (2 * _sectorSize);
402  status = true;
403  break;
404  case 5:
405  case 6:
408  _mainOffset = 0;
409  _failSafeOffset = 0;// but is really 32*1024*1024;
410  status = true;
411  break;
412  }
413 
414  if (_spiFlash)
415  {
416  delete _spiFlash;
418  }
419 
421  {
423  }
424 
425  return status;
426 }
427 
428 bool CNTV2KonaFlashProgram::SetBitFile (const string & inBitfileName, ostream & outMsgs, const FlashBlockID blockID)
429 {
431  _bitFileName = inBitfileName;
432 
433  if (blockID == AUTO_FLASHBLOCK)
435  else if (blockID >= MAIN_FLASHBLOCK && blockID <= FAILSAFE_FLASHBLOCK)
436  _flashID = blockID;
437  else
438  {outMsgs << "Invalid flash block ID " << DEC(blockID); return false;}
439 
440  FILE* pFile = AJA_NULL;
441  struct stat fsinfo;
442  stat(inBitfileName.c_str(), &fsinfo);
443  _bitFileSize = uint32_t(fsinfo.st_size);
444  pFile = fopen(inBitfileName.c_str(), "rb");
445  if (!pFile)
446  {outMsgs << "Cannot open bitfile '" << inBitfileName << "'"; return false;}
447 
448  // +_256 for fastFlash Programming
450  {outMsgs << "Allocate " << DEC(_bitFileSize+512) << "-byte buffer failed"; return false;}
451  _bitFileBuffer.Fill(0xFFFFFFFF);
452 
453  fseek(pFile, 0, SEEK_SET);
454  size_t bytesRead = fread(_bitFileBuffer, 1, _bitFileSize, pFile);
455  NTV2_UNUSED(bytesRead);
456  fclose(pFile);
457 
458  // Parse header to make sure this is a xilinx bitfile.
459  if (!_parser.ParseHeader(_bitFileBuffer, outMsgs))
460  return false;
461 
462  if (!SetDeviceProperties())
463  {outMsgs << "Device not recognized"; return false;}
464  return true;
465 }
466 
468 {
470  if (bitFileName.find("_fs_") != string::npos)
472 }
473 
475 {
476  bool status (SetFlashBlockIDBank(blockID));
477  NTV2Buffer bitFileHeader(MAXBITFILE_HEADERSIZE);
478  uint32_t baseAddress (GetBaseAddressForProgramming(blockID));
479  const int dwordSizeCount (int(bitFileHeader.GetByteCount()) / 4);
480  for (int count(0); status && count < dwordSizeCount; count++, baseAddress += 4)
481  status = WriteRegister(kRegXenaxFlashAddress, baseAddress)
484  && ReadRegister(kRegXenaxFlashDOUT, bitFileHeader.U32(count));
485  ostringstream msgs;
486  if (status) status = _parser.ParseHeader(bitFileHeader, msgs);
487  SetBankSelect(BANK_0); // Make sure to reset bank to lower
488  return status;
489 }
490 
492 {
493  if (_spiFlash)
494  {
495  vector<uint8_t> mcsInfoData;
496  bool oldVerboseMode = _spiFlash->GetVerbosity();
497  _spiFlash->SetVerbosity(false);
498  uint32_t offset = _spiFlash->Offset(SPI_FLASH_SECTION_MCSINFO);
499  if (_spiFlash->Read(offset, mcsInfoData, MAXMCSINFOSIZE))
500  {
501  _spiFlash->SetVerbosity(oldVerboseMode);
502  _mcsInfo.assign(mcsInfoData.begin(), mcsInfoData.end());
503  }
504  else
505  {
506  _spiFlash->SetVerbosity(oldVerboseMode);
507  return false;
508  }
509  }
510  else
511  {
512  if (_deviceID != 0x010220 || !features().CanDoIP())
513  return false;
514  uint32_t baseAddress = _mcsInfoOffset;
516 
517  NTV2Buffer mcsInfoPtr(MAXMCSINFOSIZE);
518  uint32_t dwordSizeCount (MAXMCSINFOSIZE / 4);
519  for (uint32_t count(0); count < dwordSizeCount; count++, baseAddress += 4)
520  {
521  WriteRegister(kRegXenaxFlashAddress, baseAddress);
524  ReadRegister(kRegXenaxFlashDOUT, mcsInfoPtr.U32(int(count)));
525  if (mcsInfoPtr.U32(int(count)) == 0)
526  break;
527  }
528  _mcsInfo = reinterpret_cast<const char*>(mcsInfoPtr.GetHostPointer());
529  SetBankSelect(BANK_0); // Make sure to reset bank to lower
530  }
531  // Fix up _mcsInfo...
532  size_t ffPos(_mcsInfo.find("\xFF\xFF"));
533  if (ffPos != string::npos)
534  _mcsInfo = _mcsInfo.substr(0, ffPos); // Lop off "\xFF\xFF...", if present
535  return true;
536 }
537 
538 std::string CNTV2KonaFlashProgram::Program(bool fullVerify)
539 {
540  if (!_bitFileBuffer)
541  return "Bitfile not open";
542 
543  if (!IsOpen())
544  return "Device not open";
545 
546  uint32_t baseAddress(GetBaseAddressForProgramming(_flashID));
547  switch (_flashID)
548  {
553  default: break;
554  }
555 
557 
559 
560  uint32_t* bitFilePtr = _bitFileBuffer;
561  uint32_t twoFixtysixBlockSizeCount ((_bitFileSize + 256) / 256);
562  uint32_t percentComplete(0);
564  WriteRegister(kVRegFlashSize, twoFixtysixBlockSizeCount);
565  for (uint32_t count(0); count < twoFixtysixBlockSizeCount; count++, baseAddress += 256, bitFilePtr += 64)
566  {
567  if (::NTV2DeviceGetSPIFlashVersion(_boardID) >= 5 && baseAddress == _bankSize)
568  {
569  baseAddress = 0;
571  }
572  FastProgramFlash256(baseAddress, bitFilePtr);
573  percentComplete = (count*100)/twoFixtysixBlockSizeCount;
574 
576  if (!_bQuiet)
577  cout << "Program status: " << DEC(percentComplete) << "% \r" << flush;
578  }
579  if (!_bQuiet)
580  cout << "Program status: 100% " << endl;
581 
583  if (!VerifyFlash(_flashID, fullVerify))
584  {
586  return "Program Didn't Verify";
587  }
588 
589  // Protect Device
595 
602 
604  return "";
605 }
606 
607 bool CNTV2KonaFlashProgram::ProgramFlashValue(uint32_t address, uint32_t value)
608 {
615 
616  return true;
617 }
618 
619 bool CNTV2KonaFlashProgram::FastProgramFlash256(uint32_t address, uint32_t* buffer)
620 {
623  for ( uint32_t count=0; count < 64; count++ )
624  {
625  WriteRegister(kRegXenaxFlashDIN, *buffer++);
626  }
630 
631  return true;
632 }
633 
635 {
636  uint32_t deviceID = 0;
637  if (IsOpen ())
638  {
641  ReadRegister(kRegXenaxFlashDOUT, deviceID);
642  }
643  return (deviceID & 0xFFFFFF);
644 }
645 
647 {
648  if (!IsOpen())
649  return false;
650  SetFlashBlockIDBank(blockID);
651 
657  uint32_t percentComplete = 0;
658 
659  uint32_t numSectors = GetNumberOfSectors(blockID);
660  WriteRegister(kVRegFlashSize,numSectors);
661 
662  uint32_t baseAddress = GetBaseAddressForProgramming(blockID);
663  uint32_t bankCount = 0;
664  for (uint32_t sectorCount = 0; sectorCount < numSectors; sectorCount++ )
665  {
666  if (::NTV2DeviceGetSPIFlashVersion(_boardID) >= 5 && sectorCount*_sectorSize == _bankSize)
667  {
668  switch(blockID)
669  {
670  default:
671  case MAIN_FLASHBLOCK:
673  break;
674  case FAILSAFE_FLASHBLOCK:
676  break;
677  }
678  bankCount++;
679  }
680  EraseSector(baseAddress + ((sectorCount - (_numSectorsMain* bankCount)) * _sectorSize));
681  percentComplete = (sectorCount*100)/numSectors;
682  WriteRegister(kVRegFlashStatus, sectorCount);
683  if (!_bQuiet)
684  cout << "Erase status: " << DEC(percentComplete) << "%\r" << flush;
685  }
686  WriteRegister(kVRegFlashStatus,numSectors);
687  if (!_bQuiet)
688  cout << "Erase status: 100% " << endl;
689  //if ( !CheckFlashErasedWithBlockID(flashBlockNumber))
690  //throw "Erase didn't work";
691  return SetBankSelect(BANK_0);
692 }
693 
694 bool CNTV2KonaFlashProgram::EraseSector (uint32_t sectorAddress)
695 {
696  WriteRegister(kRegXenaxFlashAddress, sectorAddress);
700  return WaitForFlashNOTBusy();
701 }
702 
704 { (void) chip; // unused
714  return WaitForFlashNOTBusy();
715 }
716 
717 bool CNTV2KonaFlashProgram::VerifyFlash (FlashBlockID flashID, bool fullVerify)
718 {
719  uint32_t errorCount = 0;
720  uint32_t baseAddress = GetBaseAddressForProgramming(flashID);
721  uint32_t* bitFilePtr = _bitFileBuffer;
722  uint32_t dwordSizeCount ((_bitFileSize + 4) / 4);
723  uint32_t percentComplete(0), lastPercentComplete(999);
724 
727  WriteRegister(kVRegFlashSize, dwordSizeCount);
728  for (uint32_t count = 0; count < dwordSizeCount; )
729  {
730  if (::NTV2DeviceGetSPIFlashVersion(_boardID) >= 5 && baseAddress == _bankSize)
731  {
732  baseAddress = 0;
734  }
735  WriteRegister(kRegXenaxFlashAddress, baseAddress);
738  uint32_t flashValue;
739  ReadRegister(kRegXenaxFlashDOUT, flashValue);
740  uint32_t bitFileValue = *bitFilePtr;
741  if (flashValue != bitFileValue)
742  {
743  cerr << "Error " << DEC(count) << " E(" << HEX0N(bitFileValue,8) << "),R(" << HEX0N(flashValue,8) << ")" << endl;
744  errorCount++;
745  if (errorCount > 1)
746  break;
747  }
748  percentComplete = (count*100)/dwordSizeCount;
750  if (!_bQuiet)
751  {
752  if (percentComplete != lastPercentComplete)
753  {
754  cout << "Program verify: " << DEC(percentComplete) << "%\r" << flush;
755  lastPercentComplete = percentComplete;
756  }
757  }
758  count += fullVerify ? 1 : 64;
759  baseAddress += fullVerify ? 4 : 256;
760  bitFilePtr += fullVerify ? 1 : 64;
761  }
762 
764 
765  if (errorCount)
766  {
767  if (!_bQuiet)
768  cout << "Program verify failed: " << DEC(percentComplete) << "%" << endl;
769  return false;
770  }
771  if (!_bQuiet)
772  cout << "Program verify: 100% " << endl;
773  return true;
774 }
775 
776 bool CNTV2KonaFlashProgram::ReadFlash (NTV2Buffer & outBuffer, const FlashBlockID inFlashID, CNTV2FlashProgress & inFlashProgress)
777 {
778  uint32_t baseAddress(GetBaseAddressForProgramming(inFlashID));
779  const uint32_t numDWords((_bitFileSize+4)/4);
780  if (outBuffer.GetByteCount() < numDWords*4)
781  {
782  if (outBuffer.GetByteCount() && !outBuffer.IsAllocatedBySDK())
783  {KFPERR("Unable to resize target buffer (not alloc'd by SDK)"); return false;}
784  if (!outBuffer.Allocate(numDWords * 4))
785  {KFPERR("Failed to allocate " << DEC(numDWords*4) << "-byte target buffer"); return false;}
786  }
787 
788  size_t lastPercent(0), percent(0);
789  inFlashProgress.UpdatePercentage(lastPercent);
790  switch (_flashID)
791  {
792  default:
793  case MAIN_FLASHBLOCK:
795  break;
796  case FAILSAFE_FLASHBLOCK:
798  break;
799  }
801  WriteRegister(kVRegFlashSize, numDWords);
802  KFPDBUG("About to read " << xHEX0N(numDWords*4,8) << "(" << DEC(numDWords*4) << ") bytes from '" << FlashBlockIDToString(inFlashID, /*compact*/true) << "' address " << xHEX0N(baseAddress,8));
803  for (uint32_t dword(0); dword < numDWords; )
804  {
805  if (::NTV2DeviceGetSPIFlashVersion(_boardID) >= 5 && baseAddress == _bankSize)
806  {
807  baseAddress = 0;
808  switch (_flashID)
809  {
810  default:
811  case MAIN_FLASHBLOCK:
813  break;
814  case FAILSAFE_FLASHBLOCK:
816  break;
817  }
818  }
819  WriteRegister(kRegXenaxFlashAddress, baseAddress);
822  uint32_t flashValue;
823  ReadRegister(kRegXenaxFlashDOUT, flashValue);
824  outBuffer.U32(int(dword)) = flashValue;
826 
827  dword += 1;
828  percent = dword * 100 / numDWords;
829  if (percent != lastPercent)
830  if (!inFlashProgress.UpdatePercentage(percent))
831  {SetBankSelect(BANK_0); KFPERR("Cancelled at " << DEC(percent) << "% addr=" << xHEX0N(baseAddress,8) << " dword=" << DEC(dword)); return false;}
832  lastPercent = percent;
833  if ((dword % 0x10000) == 0) cerr << xHEX0N(dword,8) << " of " << xHEX0N(numDWords,8) << endl;
834  baseAddress += 4;
835  }
837  inFlashProgress.UpdatePercentage(100);
838  KFPNOTE("Successfully read " << xHEX0N(numDWords*4,8) << "(" << DEC(numDWords*4) << ") bytes from '" << FlashBlockIDToString(inFlashID, /*compact*/true) << "' address " << xHEX0N(baseAddress,8));
839  return true;
840 }
841 
843 {
844  bool busy = true;
845  int i = 0;
846  uint32_t regValue;
847  while (i < 1)
848  {
849  ReadRegister(kRegBoardID, regValue);
850  i++;
851  }
852  regValue = 0;
853  do
854  {
856  if (!(regValue & BIT(8)))
857  {
858  busy = false;
859  break;
860  }
861  } while (busy);
862 
863  return !busy; // Return true if wait was successful
864 }
865 
867 {
868  bool status = true;
869  uint32_t baseAddress = GetBaseAddressForProgramming(flashID);
870  uint32_t numSectors = GetNumberOfSectors(flashID);
871  uint32_t dwordSizeCount = (numSectors*_sectorSize)/4;
872  uint32_t percentComplete = 0;
873  SetFlashBlockIDBank(flashID);
874 
875  for (uint32_t count = 0; count < dwordSizeCount; count++, baseAddress += 4)
876  {
877  WriteRegister(kRegXenaxFlashAddress, baseAddress);
880  uint32_t flashValue;
881  ReadRegister(kRegXenaxFlashDOUT, flashValue);
882  if ( flashValue != 0xFFFFFFFF )
883  {
884  count = dwordSizeCount;
885  status = false;
886  continue;
887  }
888  percentComplete = (count*100)/dwordSizeCount;
889  if(!_bQuiet)
890  cout << "Erase verify: " << DEC(percentComplete) << "%\r" << flush;
891  }
892  if(!_bQuiet && status == true)
893  cout << "Erase verify: 100% " << endl;
894 
896 
897  return status;
898 }
899 
900 
901 bool CNTV2KonaFlashProgram::CreateSRecord(bool bChangeEndian)
902 {
903  uint32_t baseAddress = 0;
904  // char sRecord[100];
905  uint32_t partitionOffset = 0;
906 
907  cout << "S0030000FC" << endl;
908 
909  for ( uint32_t count = 0; count < _flashSize; count+=32)
910  {
911  ostringstream sRec;
912  if (ROMHasBankSelect() && count % _bankSize == 0)
913  {
914  baseAddress = 0;
915  partitionOffset = count;
916  switch (partitionOffset)
917  {
918  default:
919  case 0x00000000: SetBankSelect(BANK_0); break;
920  case 0x01000000: SetBankSelect(BANK_1); break;
921  case 0x02000000: SetBankSelect(BANK_2); break;
922  case 0x03000000: SetBankSelect(BANK_3); break;
923  }
924  }
925 
926  uint32_t recordSize = 32;
927  if((_flashSize - count) < recordSize)
928  recordSize = _flashSize - count;
929 
930 
931  UByte checksum = 0;
932 
933  sRec << "S3"; // sRecord[0] = 'S'; sRecord[1] = '3';
934 
935  uint32_t cc (recordSize + 5);
936  sRec << Hex0N(cc,2); //sprintf(&sRecord[2], "%02x", cc);
937  checksum += cc;
938 
939  uint32_t addr = baseAddress+partitionOffset;
940  UWord aa = ((addr >> 24) &0xff);
941  sRec << Hex0N(aa,2); // sprintf(&sRecord[4], "%02x", aa);
942  checksum += aa;
943 
944  aa = ((addr >> 16) & 0xff);
945  sRec << Hex0N(aa,2); // sprintf (&sRecord[6],"%02x", aa);
946  checksum += aa;
947 
948  aa = ((addr >> 8) & 0xff);
949  sRec << Hex0N(aa,2); // sprintf (&sRecord[8],"%02x", aa);
950  checksum += aa;
951 
952  aa = (addr & 0xff);
953  sRec << Hex0N(aa,2); // sprintf (&sRecord[10],"%02x", aa);
954  checksum += aa;
955 
956  uint32_t i = 0;
957  int32_t index = 12;
958  while(i < recordSize)
959  {
963  uint32_t flashValue;
964  ReadRegister(kRegXenaxFlashDOUT, flashValue);
965  if(bChangeEndian)
966  flashValue = NTV2EndianSwap32(flashValue);
967 
968  UWord dd = (flashValue & 0xff);
969  sRec << Hex0N(dd,2); // sprintf(&sRecord[index], "%02x", dd);
970  checksum += dd;
971 
972  dd = ((flashValue >> 8) & 0xff);
973  sRec << Hex0N(dd,2); // sprintf(&sRecord[index+2], "%02x", dd);
974  checksum += dd;
975 
976  dd = ((flashValue >> 16) & 0xff);
977  sRec << Hex0N(dd,2); // sprintf(&sRecord[index+4], "%02x", dd);
978  checksum += dd;
979 
980  dd = ((flashValue >> 24) & 0xff);
981  sRec << Hex0N(dd,2); // sprintf(&sRecord[index+6], "%02x", dd);
982  checksum += dd;
983 
984  i += 4;
985  index += 8;
986  baseAddress += 4;
987  }
988  checksum = ~checksum;
989  sRec << Hex0N(UWord(checksum),2); // sprintf(&sRecord[index], "%02x", checksum);
990 
991  cout << sRec.str() << endl; // sRecord);
992  } // for loop
993 
995 
996  cout << "S705FFF001000A" << endl;
997 
998  return true;
999 }
1000 
1002 {
1003  uint32_t baseAddress = 0;
1004  ostringstream sRec; // char sRecord[100];
1005  uint32_t partitionOffset = 0;
1006 
1007  cout << "S0030000FC" << endl;
1008 
1009  for (uint32_t count = 0; count < _bankSize; count += 32)
1010  {
1011  if (ROMHasBankSelect())
1012  {
1013  SetBankSelect(bankID);
1014  }
1015 
1016  uint32_t recordSize = 32;
1017  if ((_flashSize - count) < recordSize)
1018  recordSize = _flashSize - count;
1019 
1020  UByte checksum = 0;
1021 
1022  sRec << "S3"; // sRecord[0] = 'S'; sRecord[1] = '3';
1023 
1024  UWord cc (UWord(recordSize) + 5);
1025  sRec << Hex0N(cc,2); // sprintf(&sRecord[2], "%02x", cc);
1026  checksum += cc;
1027 
1028  uint32_t addr = baseAddress + partitionOffset;
1029  UWord aa = ((addr >> 24) & 0xff);
1030  sRec << Hex0N(aa,2); // sprintf(&sRecord[4], "%02x", aa);
1031  checksum += aa;
1032 
1033  aa = ((addr >> 16) & 0xff);
1034  sRec << Hex0N(aa,2); // sprintf(&sRecord[6], "%02x", aa);
1035  checksum += aa;
1036 
1037  aa = ((addr >> 8) & 0xff);
1038  sRec << Hex0N(aa,2); // sprintf(&sRecord[8], "%02x", aa);
1039  checksum += aa;
1040 
1041  aa = (addr & 0xff);
1042  sRec << Hex0N(aa,2); // sprintf(&sRecord[10], "%02x", aa);
1043  checksum += aa;
1044 
1045  uint32_t i = 0;
1046  int32_t index = 12;
1047  while (i < recordSize)
1048  {
1049  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1052  uint32_t flashValue;
1053  ReadRegister(kRegXenaxFlashDOUT, flashValue);
1054  //flashValue = NTV2EndianSwap32(flashValue);
1055 
1056  UWord dd = (flashValue & 0xff);
1057  sRec << Hex0N(dd,2); // sprintf(&sRecord[index], "%02x", dd);
1058  checksum += dd;
1059 
1060  dd = ((flashValue >> 8) & 0xff);
1061  sRec << Hex0N(dd,2); // sprintf(&sRecord[index + 2], "%02x", dd);
1062  checksum += dd;
1063 
1064  dd = ((flashValue >> 16) & 0xff);
1065  sRec << Hex0N(dd,2); // sprintf(&sRecord[index + 4], "%02x", dd);
1066  checksum += dd;
1067 
1068  dd = ((flashValue >> 24) & 0xff);
1069  sRec << Hex0N(dd,2); // sprintf(&sRecord[index + 6], "%02x", dd);
1070  checksum += dd;
1071 
1072  i += 4;
1073  index += 8;
1074  baseAddress += 4;
1075  }
1076  checksum = ~checksum;
1077  sRec << Hex0N(UWord(checksum),2); // sprintf(&sRecord[index], "%02x", checksum);
1078 
1079  cout << sRec.str() << endl; // sRecord);
1080  } // for loop
1081 
1083 
1084  cout << "S705FFF001000A" << endl;
1085 
1086  return true;
1087 }
1088 
1090 {
1091  ostringstream iRec; // char iRecord[100];
1092  int32_t recordSize = 16;
1093  UWord baseAddress = 0x0000;
1094  UByte checksum = 0;
1095  UByte recordType = 0x00;
1096  UByte byteCount = 0x10;
1097 
1098  uint32_t i2cVal = 0x02000050;
1099 
1100  for(int32_t x = 0; x < 16; x++)
1101  {
1102  int32_t i= 0;
1103  int32_t index = 0;
1104  checksum = 0;
1105 
1106  iRec << ":"; // iRecord[0] = ':';
1107 
1108  iRec << Hex0N(UWord(byteCount),2); // sprintf(&iRecord[1], "%02x", byteCount);
1109  checksum += byteCount;
1110 
1111  UWord addr = baseAddress;
1112  UByte aa = ((addr >> 8) & 0xff);
1113  iRec << Hex0N(UWord(aa),2); // sprintf(&iRecord[3], "%02x", aa);
1114  checksum += aa;
1115 
1116  aa = ((addr) & 0xff);
1117  iRec << Hex0N(UWord(aa),2); // sprintf(&iRecord[5], "%02x", aa);
1118  checksum += aa;
1119 
1120  iRec << Hex0N(UWord(recordType),2); // sprintf (&iRecord[7], "%02x", recordType);
1121 
1122  index = 9;
1123 
1124  while(i<recordSize)
1125  {
1127 
1128  AJATime::Sleep(100);
1129 
1130  uint32_t flashValue;
1131  ReadRegister(kRegFS1I2C1Data, flashValue);
1132 
1133  UByte dd = ((flashValue >> 8) & 0xff);
1134  iRec << Hex0N(UWord(dd),2); // sprintf(&iRecord[index], "%02x", dd);
1135  checksum += dd;
1136 
1137  i++;
1138  index+=2;
1139  i2cVal += 0x00000100;
1140  }
1141 
1142  baseAddress += 0x0010;
1143  checksum = (checksum ^ 0xFF)+1;
1144  iRec << Hex0N(UWord(checksum),2); // sprintf(&iRecord[index], "%02x", checksum);
1145 
1146  cout << iRec.str() << endl; // iRecord);
1147  } // for loop
1148 
1149  cout << ":00000001FF" << endl;
1150 
1151  return true;
1152 
1153 }
1154 
1156 {
1157  if (!features().CanDoIP())
1158  return false;
1159 
1160  if (!mac1 || !mac2)
1161  return false;
1162 
1163  if (_spiFlash)
1164  {
1165  vector<uint8_t> macData;
1166  macData.push_back(mac1->mac[3]);
1167  macData.push_back(mac1->mac[2]);
1168  macData.push_back(mac1->mac[1]);
1169  macData.push_back(mac1->mac[0]);
1170  macData.push_back(0);
1171  macData.push_back(0);
1172  macData.push_back(mac1->mac[5]);
1173  macData.push_back(mac1->mac[4]);
1174 
1175  macData.push_back(mac2->mac[3]);
1176  macData.push_back(mac2->mac[2]);
1177  macData.push_back(mac2->mac[1]);
1178  macData.push_back(mac2->mac[0]);
1179  macData.push_back(0);
1180  macData.push_back(0);
1181  macData.push_back(mac2->mac[5]);
1182  macData.push_back(mac2->mac[4]);
1183 
1184  bool oldVerboseMode = _spiFlash->GetVerbosity();
1185  _spiFlash->SetVerbosity(false);
1186  uint32_t offset = _spiFlash->Offset(SPI_FLASH_SECTION_MAC);
1187  _spiFlash->Erase(offset, uint32_t(macData.size()));
1188  if (_spiFlash->Write(offset, macData, uint32_t(macData.size())))
1189  {
1190  _spiFlash->SetVerbosity(oldVerboseMode);
1191  return true;
1192  }
1193  else
1194  {
1195  _spiFlash->SetVerbosity(oldVerboseMode);
1196  return false;
1197  }
1198  }
1199  else
1200  {
1201  uint32_t baseAddress = _macOffset;
1202 
1204 
1206 
1207 
1208  uint32_t lo = 0;
1209  lo |= uint32_t((mac1->mac[0]) << 24) & 0xff000000;
1210  lo |= uint32_t((mac1->mac[1]) << 16) & 0x00ff0000;
1211  lo |= uint32_t((mac1->mac[2]) << 8) & 0x0000ff00;
1212  lo |= uint32_t(mac1->mac[3]) & 0x000000ff;
1213 
1214  uint32_t hi = 0;
1215  hi |= uint32_t((mac1->mac[4]) << 24) & 0xff000000;
1216  hi |= uint32_t((mac1->mac[5]) << 16) & 0x00ff0000;
1217 
1218  uint32_t lo2 = 0;
1219  lo2 |= uint32_t((mac2->mac[0]) << 24) & 0xff000000;
1220  lo2 |= uint32_t((mac2->mac[1]) << 16) & 0x00ff0000;
1221  lo2 |= uint32_t((mac2->mac[2]) << 8) & 0x0000ff00;
1222  lo2 |= uint32_t(mac2->mac[3]) & 0x000000ff;
1223 
1224  uint32_t hi2 = 0;
1225  hi2 |= uint32_t((mac2->mac[4]) << 24) & 0xff000000;
1226  hi2 |= uint32_t((mac2->mac[5]) << 16) & 0x00ff0000;
1227 
1228 
1229  ProgramFlashValue(baseAddress, lo);
1230  baseAddress += 4;
1231  ProgramFlashValue(baseAddress, hi);
1232  baseAddress += 4;
1233  ProgramFlashValue(baseAddress, lo2);
1234  baseAddress += 4;
1235  ProgramFlashValue(baseAddress, hi2);
1236 
1242 
1244 
1245  return true;
1246  }
1247 }
1248 
1250 {
1251  if (!features().CanDoIP())
1252  return false;
1253 
1254  if (_spiFlash)
1255  {
1256  vector<uint8_t> macData;
1257  bool oldVerboseMode = _spiFlash->GetVerbosity();
1258  _spiFlash->SetVerbosity(false);
1259  uint32_t offset = _spiFlash->Offset(SPI_FLASH_SECTION_MAC);
1260  if (_spiFlash->Read(offset, macData, 16))
1261  {
1262  _spiFlash->SetVerbosity(oldVerboseMode);
1263  if (macData.size() < 16)
1264  return false;
1265 
1266  mac1.mac[0] = macData.at(3);
1267  mac1.mac[1] = macData.at(2);
1268  mac1.mac[2] = macData.at(1);
1269  mac1.mac[3] = macData.at(0);
1270  mac1.mac[4] = macData.at(7);
1271  mac1.mac[5] = macData.at(6);
1272 
1273  mac2.mac[0] = macData.at(8+3);
1274  mac2.mac[1] = macData.at(8+2);
1275  mac2.mac[2] = macData.at(8+1);
1276  mac2.mac[3] = macData.at(8+0);
1277  mac2.mac[4] = macData.at(8+7);
1278  mac2.mac[5] = macData.at(8+6);
1279  return true;
1280  }
1281  else
1282  {
1283  _spiFlash->SetVerbosity(oldVerboseMode);
1284  return false;
1285  }
1286  }
1287  else
1288  {
1289  uint32_t lo, hi, lo2, hi2;
1290  uint32_t baseAddress = GetBaseAddressForProgramming(MAC_FLASHBLOCK);
1292 
1293  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1297  baseAddress += 4;
1298 
1299  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1303  baseAddress += 4;
1304 
1305  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1309  baseAddress += 4;
1310 
1311  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1315 
1317 
1318  //if (lo == 0xffffffff && hi == 0xffffffff && lo2 == 0xffffffff && hi2 == 0xffffffff)
1319  //return false;
1320 
1321  mac1.mac[0] = (lo & 0xff000000) >> 24;
1322  mac1.mac[1] = (lo & 0x00ff0000) >> 16;
1323  mac1.mac[2] = (lo & 0x0000ff00) >> 8;
1324  mac1.mac[3] = lo & 0x000000ff;
1325  mac1.mac[4] = (hi & 0xff000000) >> 24;
1326  mac1.mac[5] = (hi & 0x00ff0000) >> 16;
1327 
1328  mac2.mac[0] = (lo2 & 0xff000000) >> 24;
1329  mac2.mac[1] = (lo2 & 0x00ff0000) >> 16;
1330  mac2.mac[2] = (lo2 & 0x0000ff00) >> 8;
1331  mac2.mac[3] = lo2 & 0x000000ff;
1332  mac2.mac[4] = (hi2 & 0xff000000) >> 24;
1333  mac2.mac[5] = (hi2 & 0x00ff0000) >> 16;
1334  }
1335  return true;
1336 }
1337 
1338 bool CNTV2KonaFlashProgram::ProgramLicenseInfo (const string & licenseString)
1339 {
1340  if (!features().CanDoIP())
1341  return false;
1342 
1343  if (_spiFlash)
1344  {
1345  vector<uint8_t> licenseData;
1346  for (string::const_iterator it(licenseString.begin()); it != licenseString.end(); ++it)
1347  licenseData.push_back(uint8_t(*it));
1348  licenseData.push_back(0);
1349 
1350  bool oldVerboseMode = _spiFlash->GetVerbosity();
1351  _spiFlash->SetVerbosity(false);
1352  uint32_t offset = _spiFlash->Offset(SPI_FLASH_SECTION_LICENSE);
1353  _spiFlash->Erase(offset, uint32_t(licenseData.size()));
1354  if (_spiFlash->Write(offset, licenseData, uint32_t(licenseData.size())))
1355  _spiFlash->SetVerbosity(oldVerboseMode);
1356  else
1357  {
1358  _spiFlash->SetVerbosity(oldVerboseMode);
1359  return false;
1360  }
1361  }
1362  else
1363  {
1365 
1367 
1369 
1370  size_t len (licenseString.size());
1371  size_t words ((len/4) + 2);
1372  NTV2Buffer data8(words*4);
1373  ULWord * data32 = data8;
1374  data8.Fill(0x0000);
1375  strcat(data8,licenseString.c_str());
1376 
1378 
1379  for (size_t i(0); i < words; i++)
1380  {
1381  ProgramFlashValue(sectorAddress, data32[i]);
1382  sectorAddress += 4;
1383  }
1384 
1385  // Protect Device
1397  }
1398  return true;
1399 }
1400 
1401 bool CNTV2KonaFlashProgram::ReadLicenseInfo(string& serialString)
1402 {
1403  const uint32_t maxSize = 100;
1404  if (!features().CanDoIP())
1405  return false;
1406 
1407  if (_spiFlash)
1408  {
1409  vector<uint8_t> licenseData;
1410  bool oldVerboseMode = _spiFlash->GetVerbosity();
1411  uint32_t offset = _spiFlash->Offset(SPI_FLASH_SECTION_LICENSE);
1412  _spiFlash->SetVerbosity(false);
1413  if (_spiFlash->Read(offset, licenseData, maxSize))
1414  {
1415  _spiFlash->SetVerbosity(oldVerboseMode);
1416  serialString = "";
1417  if (licenseData.size() < 4)
1418  return false;
1419  else if (licenseData[0] == 0xff && licenseData[1] == 0xff && licenseData[2] == 0xff && licenseData[3] == 0xff)
1420  return false;
1421  else
1422  {
1423  serialString.assign(licenseData.begin(), licenseData.end());
1424 
1425  // remove any trailing nulls
1426  size_t found = serialString.find('\0');
1427  if (found != string::npos)
1428  serialString.resize(found);
1429  }
1430  }
1431  else
1432  {
1433  _spiFlash->SetVerbosity(oldVerboseMode);
1434  return false;
1435  }
1436  }
1437  else
1438  {
1439  ULWord license[maxSize];
1440  memset (license,0x0,sizeof(license));
1441 
1442  uint32_t baseAddress = GetBaseAddressForProgramming(LICENSE_BLOCK);
1444 
1445  bool terminated = false;
1446  bool good = false;
1447  for(uint32_t i = 0; i < maxSize; i++)
1448  {
1449  WriteRegister(kRegXenaxFlashAddress,baseAddress);
1452  ReadRegister(kRegXenaxFlashDOUT, license[i]);
1453  if (license[i] == 0xffffffff)
1454  {
1455  good = true; // uninitialized memory
1456  break;
1457  }
1458  if (license[i] == 0)
1459  {
1460  good = true;
1461  terminated = true;
1462  break;
1463  }
1464  baseAddress += 4;
1465  }
1466 
1467  std::string res;
1468  if (terminated)
1469  res = reinterpret_cast<char*>(license);
1470 
1471  serialString = res;
1472  return good;
1473  }
1474  return true;
1475 }
1476 
1478 {
1479  if (ROMHasBankSelect())
1480  {
1481  if (int(bankNumber) > int(BANK_3))
1482  return false; // illegal value
1485  WriteRegister(kRegXenaxFlashAddress, uint32_t(bankNumber));
1486 
1489  KFPDBUG ("selected bank: " << ReadBankSelect());
1490  }
1491  return true;
1492 }
1493 
1495 {
1496  uint32_t bankNumber = 0;
1497  if (ROMHasBankSelect())
1498  {
1501  ReadRegister(kRegXenaxFlashDOUT, bankNumber);
1502  }
1503  return bankNumber&0xf;
1504 }
1505 
1506 bool CNTV2KonaFlashProgram::SetMCSFile (const string & inMCSFileName)
1507 {
1508  if (!_bQuiet)
1509  cout << "Parsing MCS File" << endl;
1510  return _mcsFile.Open(inMCSFileName.c_str());
1511 }
1512 
1514 {
1515  if (!_mcsFile.isReady())
1516  {cerr << "MCS bitfile not open" << endl; return false;}
1517  if (!IsOpen())
1518  {cerr << "Device not open" << endl; return false;}
1519 
1520  if (_spiFlash)
1521  {
1522  if (!_mcsFile.isReady())
1523  {cerr << "MCS file not ready" << endl; return false;}
1524 
1525  // now the main FPGA part
1527 
1528  vector<uint8_t> fpgaData;
1529  uint16_t fpgaPartitionOffset = 0;
1530 
1531  _mcsFile.GetPartition(fpgaData, 0x0000, fpgaPartitionOffset, false);
1532  _bitFileSize = uint32_t(fpgaData.size());
1533  // +_256 for fastFlash Programming
1535  _bitFileBuffer.Fill(0xFFFFFFFF);
1536  ::memcpy(_bitFileBuffer, &fpgaData[0], _bitFileSize);
1537 
1538  // Parse header to make sure this is a xilinx bitfile.
1539  ostringstream msgs;
1540  if (!_parser.ParseHeader(_bitFileBuffer, msgs))
1541  {cerr << "Can't parse header" << endl << msgs.str() << endl; return false;}
1542 
1543  // handle the fpga part
1544  string msg = Program(verify);
1545  // handle the SOC part
1546  return ProgramSOC(verify);
1547  }
1548 
1549  bool hasErasedSOCs = false;
1550  uint16_t linearOffsetToBankOffset = 0x0000;
1551  uint16_t basePartitionAddress = linearOffsetToBankOffset;
1552  bool bPartitionValid = true;
1553  uint32_t partitionCount = 0;
1554  while (bPartitionValid)
1555  {
1559 
1560  uint16_t partitionOffset = 0;
1561  FlashBlockID blockID = MAIN_FLASHBLOCK;
1562  ParsePartitionFromFileLines(basePartitionAddress, partitionOffset);
1563  if (basePartitionAddress < 0x0100)
1564  {
1565  blockID = MAIN_FLASHBLOCK;
1566  linearOffsetToBankOffset = 0x0000;
1567  //Program Main
1568  if (!_bQuiet)
1569  cout << "Erase Main Bitfile Bank" << endl;
1573  }
1574  else if (basePartitionAddress >= 0x0100 && basePartitionAddress < 0x0200)
1575  {
1576  blockID = MCS_INFO_BLOCK;
1577  linearOffsetToBankOffset = 0x0100;
1578  //Program Comment
1579  if (!_bQuiet)
1580  cout << "Erase Package Info Block" << endl;
1584  }
1585  else if (basePartitionAddress >= 0x0200 && basePartitionAddress < 0x0400)
1586  {
1587  if (!hasErasedSOCs)
1588  {
1589  if (!_bQuiet)
1590  cout << "Erase SOC Bank 1" << endl;
1593  if (!_bQuiet)
1594  cout << "Erase SOC Bank 2" << endl;
1597  hasErasedSOCs = true;
1598  }
1599  if (basePartitionAddress >= 0x0200 && basePartitionAddress < 0x0300)
1600  {
1601  blockID = SOC1_FLASHBLOCK;
1602  linearOffsetToBankOffset = 0x0200;
1604  }
1605  else
1606  {
1607  blockID = SOC2_FLASHBLOCK;
1608  linearOffsetToBankOffset = 0x0300;
1610  }
1611  }
1612  else
1613  {
1614  break;
1615  }
1616 
1617  uint16_t baseOffset = basePartitionAddress - linearOffsetToBankOffset;
1618  uint32_t programOffset = uint32_t(baseOffset) << 16 | partitionOffset;
1619 
1620  if (_bankSize == 0)
1621  {
1622  bPartitionValid = false;
1623  break;
1624  }
1625 
1626  SetFlashBlockIDBank(blockID);
1627 
1628  uint32_t baseAddress = GetBaseAddressForProgramming(blockID) + programOffset;
1629  if (blockID == MCS_INFO_BLOCK)
1630  baseAddress = _mcsInfoOffset;
1631  uint32_t bufferIndex = 0;
1632  uint32_t blockSize = 512;
1633  uint32_t dwordsPerBlock = blockSize / 4;
1634  uint32_t totalBlockCount ((uint32_t(_partitionBuffer.size()) + blockSize) / blockSize);
1635  uint32_t percentComplete = 0;
1636 
1637  WriteRegister(kVRegFlashSize, totalBlockCount);
1638  for (uint32_t blockCount = 0; blockCount < totalBlockCount; blockCount++)
1639  {
1640  WriteRegister(kVRegFlashStatus,blockCount);
1641  if (baseAddress == 0x01000000 && blockCount > 0 && blockID == SOC1_FLASHBLOCK)
1642  {
1643  blockID = SOC2_FLASHBLOCK;
1644  SetFlashBlockIDBank(blockID);
1645  baseAddress = GetBaseAddressForProgramming(blockID);
1647  }
1648  uint32_t remainderBytes = static_cast<uint32_t>(_partitionBuffer.size() - bufferIndex);
1651 
1652  for (uint32_t dwordCount = 0; dwordCount < dwordsPerBlock; dwordCount++)
1653  {
1654  uint32_t partitionValue = 0xFFFFFFFF;
1655  if (remainderBytes >= 4)
1656  {
1657  partitionValue = uint32_t(_partitionBuffer[bufferIndex + 0]) << 24 |
1658  uint32_t(_partitionBuffer[bufferIndex + 1]) << 16 |
1659  uint32_t(_partitionBuffer[bufferIndex + 2]) << 8 |
1660  uint32_t(_partitionBuffer[bufferIndex + 3]);
1661  bufferIndex += 4;
1662  remainderBytes -= 4;
1663  }
1664  else
1665  {
1666  switch (remainderBytes)
1667  {
1668  case 3:
1669  partitionValue = 0xff;
1670  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1671  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 1]) << 16;
1672  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 2]) << 8;
1673  break;
1674  case 2:
1675  partitionValue = 0xffff;
1676  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1677  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 1]) << 16;
1678  break;
1679  case 1:
1680  partitionValue = 0xffffff;
1681  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1682  break;
1683  default:
1684  break;
1685  }
1686  remainderBytes = 0;
1687  }
1688  partitionValue = NTV2EndianSwap32(partitionValue);
1689  WriteRegister(kRegXenaxFlashDIN, partitionValue);
1690  }
1691  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1693 
1695 
1696  baseAddress += blockSize;
1697 
1698  percentComplete = (blockCount * 100) / totalBlockCount;
1699  if (!_bQuiet)
1700  cout << "Partition " << DEC(partitionCount) << " program status: " << DEC(percentComplete) << "%\r" << flush;
1701  }
1702  if (!_bQuiet)
1703  cout << "Partition " << DEC(partitionCount) << " program status: 100% " << endl;
1704 
1705  if (verify)
1706  {
1707  switch (blockID)
1708  {
1709  default:
1710  case MAIN_FLASHBLOCK:
1712  break;
1713  case SOC1_FLASHBLOCK:
1715  break;
1716  case SOC2_FLASHBLOCK:
1718  break;
1719  case MCS_INFO_BLOCK:
1721  break;
1722  }
1723 
1724  if (!VerifySOCPartition(blockID, programOffset))
1725  {
1727  cerr << "Verify Error" << endl;
1728  return false;
1729  }
1730  }
1731  partitionCount++;
1732 
1733  IntelRecordInfo recordInfo;
1734  _mcsFile.GetCurrentParsedRecord(recordInfo);
1735  if (recordInfo.recordType != IRT_ELAR)
1736  bPartitionValid = false;
1737  else
1738  basePartitionAddress = recordInfo.linearAddress;
1739 
1740  }
1741 
1742  //Protect Device
1748 
1755 
1757  return true;
1758 }
1759 
1760 bool CNTV2KonaFlashProgram::ProgramSOC (const bool verify)
1761 {
1762  if (!_mcsFile.isReady())
1763  {cerr << "MCS bitfile not open" << endl; return false;}
1764 
1765  if (_spiFlash)
1766  {
1767  if (!IsOpen())
1768  {cerr << "Device not open" << endl; return false;}
1769  if (!_mcsFile.isReady())
1770  {cerr << "MCS bitfile not ready" << endl; return false;}
1771 
1772  vector<uint8_t> ubootData;
1773  vector<uint8_t> imageData;
1774  vector<uint8_t> mcsInfoData;
1775  uint16_t ubootPartitionOffset = 0;
1776  uint16_t imagePartitionOffset = 0;
1777  uint16_t mcsInfoPartitionOffset = 0;
1778  _mcsFile.GetPartition(ubootData, 0x0400, ubootPartitionOffset, false);
1779  if (ubootData.empty())
1780  {cerr << "Could not find uboot data in MCS file" << endl; return false;}
1781 
1782  _mcsFile.GetPartition(imageData, 0x0410, imagePartitionOffset, false);
1783  if (imageData.empty())
1784  {cerr << "Could not find kernel data in MCS file" << endl; return false;}
1785 
1786  _mcsFile.GetPartition(mcsInfoData, 0x05F4, mcsInfoPartitionOffset, false);
1787  if (mcsInfoData.empty())
1788  {cerr << "Could not find mcs info in MCS file" << endl; return false;}
1789 
1790  uint32_t ubootFlashOffset = _spiFlash->Offset(SPI_FLASH_SECTION_UBOOT);
1791  uint32_t imageFlashOffset = _spiFlash->Offset(SPI_FLASH_SECTION_KERNEL);
1792  uint32_t mcsFlashOffset = _spiFlash->Offset(SPI_FLASH_SECTION_MCSINFO);
1793 
1794  uint32_t ubootSize = uint32_t(ubootData.size());
1795  uint32_t imageSize = uint32_t(imageData.size());
1796  uint32_t mcsInfoSize = uint32_t(mcsInfoData.size());
1797 
1798  // erase uboot
1799  _spiFlash->Erase(ubootFlashOffset, ubootSize);
1800 
1801  // write uboot
1802  _spiFlash->Write(ubootFlashOffset, ubootData, ubootSize);
1803 
1804  // verify uboot
1805  if (verify)
1806  _spiFlash->Verify(ubootFlashOffset, ubootData);
1807 
1808  // erase image
1809  _spiFlash->Erase(imageFlashOffset, imageSize);
1810 
1811  // write image
1812  _spiFlash->Write(imageFlashOffset, imageData, imageSize);
1813 
1814  // verify image
1815  if (verify)
1816  _spiFlash->Verify(imageFlashOffset, imageData);
1817 
1818  // erase mcs info
1819  _spiFlash->Erase(mcsFlashOffset, mcsInfoSize);
1820 
1821  // write mcs info
1822  _spiFlash->Write(mcsFlashOffset, mcsInfoData, mcsInfoSize);
1823 
1824  // verify mcs info
1825  if (verify)
1826  _spiFlash->Verify(mcsFlashOffset, mcsInfoData);
1827  return true;
1828  } // if _spiFlash
1829 
1830  // Not _spiFlash:
1831  if (!IsOpen())
1832  {cerr << "Device not open" << endl; return false;}
1833  if (!_bQuiet)
1834  cout << "Erase SOC Bank 1" << endl;
1836  if (!_bQuiet)
1837  cout << "Erase SOC Bank 2" << endl;
1839 
1840  //1st partition is assumed to be at 32M mark
1841  //the 32bit address is 0x02000000
1842  //the ELAR address is 0x0200
1843  uint16_t partition32M = 0x0200;
1844  uint16_t basePartitionAddress = partition32M;
1845  bool bPartitionValid = true;
1846  uint32_t partitionCount = 0;
1847  while (bPartitionValid)
1848  {
1849  uint16_t partitionOffset = 0;
1850  ParsePartitionFromFileLines(basePartitionAddress, partitionOffset);
1851  uint16_t baseOffset = basePartitionAddress - partition32M;
1852  uint32_t programOffset = uint32_t(baseOffset) << 16 | partitionOffset;
1853 
1854  FlashBlockID blockID = SOC1_FLASHBLOCK;
1855  if (programOffset >= 0x01000000)
1856  blockID = SOC2_FLASHBLOCK;
1857 
1858  if (_bankSize == 0)
1859  return true;
1860 
1861  SetFlashBlockIDBank(blockID);
1862  uint32_t baseAddress = GetBaseAddressForProgramming(blockID) + programOffset;
1863  uint32_t bufferIndex = 0;
1864  uint32_t blockSize = 512;
1865  uint32_t dwordsPerBlock = blockSize / 4;
1866  uint32_t totalBlockCount = static_cast<uint32_t>((_partitionBuffer.size() + blockSize) / blockSize);
1867  uint32_t percentComplete = 0;
1868  for (uint32_t blockCount = 0; blockCount < totalBlockCount; blockCount++)
1869  {
1870  if (baseAddress == 0x01000000 && blockCount > 0)
1871  {
1873  baseAddress = GetBaseAddressForProgramming(blockID);
1874  }
1875  uint32_t remainderBytes = static_cast<uint32_t>(_partitionBuffer.size() - bufferIndex);
1878 
1879  for (uint32_t dwordCount = 0; dwordCount < dwordsPerBlock; dwordCount++)
1880  {
1881  uint32_t partitionValue = 0xFFFFFFFF;
1882  if (remainderBytes >= 4)
1883  {
1884  partitionValue = uint32_t(_partitionBuffer[bufferIndex + 0]) << 24 |
1885  uint32_t(_partitionBuffer[bufferIndex + 1]) << 16 |
1886  uint32_t(_partitionBuffer[bufferIndex + 2]) << 8 |
1887  uint32_t(_partitionBuffer[bufferIndex + 3]);
1888  bufferIndex += 4;
1889  remainderBytes -= 4;
1890  }
1891  else
1892  {
1893  switch (remainderBytes)
1894  {
1895  case 3:
1896  partitionValue = 0xff;
1897  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1898  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 1]) << 16;
1899  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 2]) << 8;
1900  break;
1901  case 2:
1902  partitionValue = 0xffff;
1903  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1904  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 1]) << 16;
1905  break;
1906  case 1:
1907  partitionValue = 0xffffff;
1908  partitionValue |= uint32_t(_partitionBuffer[bufferIndex + 0]) << 24;
1909  break;
1910  default:
1911  break;
1912  }
1913  remainderBytes = 0;
1914  }
1915  partitionValue = NTV2EndianSwap32(partitionValue);
1916  WriteRegister(kRegXenaxFlashDIN, partitionValue);
1917  } // for dwordCount
1918  WriteRegister(kRegXenaxFlashAddress, baseAddress);
1920 
1922 
1923  baseAddress += blockSize;
1924 
1925  percentComplete = (blockCount * 100) / totalBlockCount;
1926  if (!_bQuiet)
1927  cout << "Partition " << DEC(partitionCount+2) << " program status: " << DEC(percentComplete) << "%\r" << flush;
1928  } // for blockCount
1929  if (!_bQuiet)
1930  cout << "Partition " << DEC(partitionCount+2) << " program status: 100% " << endl;
1931 
1932  if (verify && !VerifySOCPartition(blockID, programOffset))
1933  {
1935  cerr << "Verify failed" << endl;
1936  return false;
1937  }
1938 
1939  partitionCount++;
1940  IntelRecordInfo recordInfo;
1941  _mcsFile.GetCurrentParsedRecord(recordInfo);
1942  if (recordInfo.recordType != IRT_ELAR)
1943  bPartitionValid = false;
1944  else
1945  basePartitionAddress = recordInfo.linearAddress;
1946  } // while bPartitionValid
1947 
1948  //Protect Device
1954 
1961  return true;
1962 }
1963 
1964 static bool getFileSize (const string & fileName, size_t & outSizeBytes)
1965 {
1966  outSizeBytes = 0;
1967  ifstream ifs(fileName.c_str(), ios::binary | ios::in);
1968  if (ifs.fail())
1969  return false; // open failed
1970  if (!ifs.seekg (0, ios::end))
1971  return false; // seek failed
1972  ifstream::pos_type curOffset(ifs.tellg());
1973  if (int(curOffset) == -1)
1974  return false;
1975  outSizeBytes = size_t(curOffset);
1976  return true;
1977 }
1978 
1979 bool CNTV2KonaFlashProgram::ProgramCustom (const string &sCustomFileName, const uint32_t addr, ostream & outMsgs)
1980 {
1981  if (!IsOpen())
1982  {outMsgs << "Device not open" << endl; return false;}
1983 
1984  if (_spiFlash)
1985  {
1986  vector<uint8_t> writeData;
1987  size_t sz(0), maxFlashSize(_spiFlash->Size());
1988  // open file and read data
1989  if (!getFileSize(sCustomFileName, sz))
1990  {outMsgs << "getFileSize failed for '" << sCustomFileName << "'" << endl; return false;}
1991  if (sz > maxFlashSize)
1992  {outMsgs << "File size " << DEC(sz) << " exceeds max flash size " << DEC(maxFlashSize) << endl; return false;}
1993 
1994  ifstream ifs(sCustomFileName.c_str(), ios::binary | ios::in);
1995  if (ifs.fail())
1996  {outMsgs << "Unable to open file '" << sCustomFileName << "'" << endl; return false;}
1997 
1998  writeData.resize(sz);
1999  ifs.read(reinterpret_cast<char*>(&writeData[0]), streamsize(sz));
2000  if (!ifs.good())
2001  {outMsgs << "Error reading data from file '" << sCustomFileName << "'" << endl; return false;}
2002 
2003  // erase flash
2004  uint32_t writeSize = uint32_t(writeData.size());
2005  bool eraseGood = _spiFlash->Erase(addr, writeSize);
2006  if (!eraseGood)
2007  {outMsgs << "Error erasing sectors, addr=" << xHEX0N(addr,8) << " length=" << DEC(writeSize) << endl; return false;}
2008 
2009  // write flash
2010  _spiFlash->Write(addr, writeData, writeSize);
2011 
2012  bool result = true, verify = true;
2013  if (verify)
2014  {
2015  result = _spiFlash->Verify(addr, writeData);
2016  }
2017  return result;
2018  } // if _spiFlash
2019  else
2020  {
2021  static const size_t MAX_CUSTOM_FILE_SIZE (8<<20); // 1M
2022  NTV2Buffer customFileBuffer(MAX_CUSTOM_FILE_SIZE);
2023  size_t customSize(0), sz(0);
2024 
2025  uint32_t bank(addr / _bankSize), offset(addr % _bankSize);
2026  if (offset + customSize > _bankSize)
2027  {outMsgs << "Custom write spans banks -- unsupported"; return false;}
2028  if (offset % _sectorSize)
2029  {outMsgs << "Write not on sector boundary -- unsupported"; return false;}
2030  if (!getFileSize(sCustomFileName, sz))
2031  {outMsgs << "Error getting file size for '" << sCustomFileName << "'"; return false;}
2032  if (sz > MAX_CUSTOM_FILE_SIZE)
2033  {outMsgs << "File size " << DEC(sz) << " exceeds max supported size " << DEC(MAX_CUSTOM_FILE_SIZE); return false;}
2034 
2035  ifstream ifs(sCustomFileName.c_str(), ios::binary | ios::in);
2036  if (!ifs.fail())
2037  {outMsgs << "Unable to open file '" << sCustomFileName << "'" << endl; return false;}
2038 
2039  customSize = size_t(ifs.readsome(customFileBuffer, streamsize(customFileBuffer.GetByteCount())));
2040  if (!customSize)
2041  {outMsgs << "No data read from custom file '" << sCustomFileName << "'" << endl; return false;}
2042 
2043  static const BankSelect BankIdxToBankSelect[] = {BANK_0, BANK_1, BANK_2, BANK_3};
2044 
2045  SetBankSelect(BankIdxToBankSelect[bank]);
2051 
2052  const uint32_t customSectors ((uint32_t(customSize) + _sectorSize - 1) / (_sectorSize));
2053  for (uint32_t i(0); i < customSectors; i++)
2054  {
2055  if (!_bQuiet)
2056  cout << "Erasing sectors - " << DECN(i,3) << " of " << DECN(customSectors,3) << "\r" << flush;
2057  EraseSector(offset + (i * _sectorSize));
2058  }
2059 
2062 
2063  uint32_t blockSize (512);
2064  uint32_t dwordsPerBlock (blockSize / 4);
2065  uint32_t totalBlockCount ((uint32_t(customSize) + blockSize - 1) / blockSize);
2066  uint32_t percentComplete (0);
2067  uint32_t baseAddress (offset);
2068  size_t remainderBytes (customSize);
2069  uint32_t bufferIndex (0);
2070  for (uint32_t blockCount(0); blockCount < totalBlockCount; blockCount++)
2071  {
2074 
2075  for (uint32_t dwordCount(0); dwordCount < dwordsPerBlock; dwordCount++)
2076  {
2077  uint32_t partitionValue = 0xFFFFFFFF;
2078  if (remainderBytes >= 4)
2079  {
2080  partitionValue = uint32_t(_customFileBuffer[bufferIndex + 0]) << 24
2081  | uint32_t(_customFileBuffer[bufferIndex + 1]) << 16
2082  | uint32_t(_customFileBuffer[bufferIndex + 2]) << 8
2083  | uint32_t(_customFileBuffer[bufferIndex + 3]);
2084  bufferIndex += 4;
2085  remainderBytes -= 4;
2086  }
2087  else switch (remainderBytes)
2088  {
2089  case 3:
2090  partitionValue = 0xff;
2091  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 0]) << 24;
2092  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 1]) << 16;
2093  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 2]) << 8;
2094  remainderBytes = 0;
2095  break;
2096  case 2:
2097  partitionValue = 0xffff;
2098  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 0]) << 24;
2099  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 1]) << 16;
2100  remainderBytes = 0;
2101  break;
2102  case 1:
2103  partitionValue = 0xffffff;
2104  partitionValue |= uint32_t(_customFileBuffer[bufferIndex + 0]) << 24;
2105  remainderBytes = 0;
2106  break;
2107  default:
2108  break;
2109  }
2110  partitionValue = NTV2EndianSwap32(partitionValue);
2111  WriteRegister(kRegXenaxFlashDIN, partitionValue);
2112  } // for each dword
2113  WriteRegister(kRegXenaxFlashAddress, baseAddress);
2116 
2117  baseAddress += blockSize;
2118 
2119  percentComplete = (blockCount * 100) / totalBlockCount;
2120  if (!_bQuiet)
2121  cout << "Program status: " << DEC(percentComplete) << "% (" << DECN(blockCount,4) << " of " << DECN(totalBlockCount,4) << " blocks)\r" << flush;
2122  } // for each block
2123 
2124  //Protect Device
2130 
2137  } // else !_spiFlash
2138  return true;
2139 }
2140 
2141 bool CNTV2KonaFlashProgram::ProgramKonaxMB (const string &sCustomFileName, const uint32_t addr, ostream & outMsgs)
2142 {
2144  {
2146  }
2147  else
2148  return false;
2149 
2150  return ProgramCustom(sCustomFileName, addr, outMsgs);
2151 }
2152 
2154 {
2155  BankSelect bankID = BANK_0;
2156  switch (blockID)
2157  {
2158  case MAIN_FLASHBLOCK:
2159  bankID = BANK_0;
2160  break;
2161  case FAILSAFE_FLASHBLOCK:
2163  break;
2164  case MCS_INFO_BLOCK:
2165  case MAC_FLASHBLOCK:
2166  case LICENSE_BLOCK:
2167  bankID = BANK_1;
2168  break;
2169  case SOC1_FLASHBLOCK:
2170  bankID = BANK_2;
2171  break;
2172  case SOC2_FLASHBLOCK:
2173  bankID = BANK_3;
2174  break;
2175  default:
2176  return false;
2177  }
2178  return SetBankSelect(bankID);
2179 }
2180 
2182 {
2184 }
2185 
2186 void CNTV2KonaFlashProgram::ParsePartitionFromFileLines(uint32_t address, uint16_t & partitionOffset)
2187 {
2188  _partitionBuffer.clear();
2189  _partitionBuffer.resize(0);
2190  bool getnext = false;
2191  if (address != 0x0000 && address != 0x0200)
2192  getnext = true;
2193  _mcsFile.GetPartition(_partitionBuffer, uint16_t(address), partitionOffset, getnext);
2194  _bankSize = uint32_t(_partitionBuffer.size());
2195  return;
2196 }
2197 
2198 bool CNTV2KonaFlashProgram::VerifySOCPartition(FlashBlockID flashID, uint32_t flashBlockOffset)
2199 {
2200  SetFlashBlockIDBank(flashID);
2201 
2202  uint32_t errorCount = 0;
2203  uint32_t baseAddress = flashBlockOffset;
2204 
2205  uint32_t dwordsPerPartition = _bankSize / 4;
2206  uint32_t percentComplete = 0;
2207  uint32_t bufferIndex = 0;
2208  WriteRegister(kVRegFlashSize,dwordsPerPartition);
2209  for (uint32_t dwordCount = 0; dwordCount < dwordsPerPartition; dwordCount += 100)//dwordCount++)
2210  {
2211  WriteRegister(kVRegFlashStatus,dwordCount);
2212  WriteRegister(kRegXenaxFlashAddress, baseAddress);
2215  uint32_t flashValue;
2216  ReadRegister(kRegXenaxFlashDOUT, flashValue);
2217  uint32_t partitionValue = uint32_t(_partitionBuffer[bufferIndex + 0]) << 24
2218  | uint32_t(_partitionBuffer[bufferIndex + 1]) << 16
2219  | uint32_t(_partitionBuffer[bufferIndex + 2]) << 8
2220  | uint32_t(_partitionBuffer[bufferIndex + 3]);
2221  partitionValue = NTV2EndianSwap32(partitionValue);
2222  bufferIndex += 400;//4;
2223  baseAddress += 400;//4;
2224 
2225  if (flashValue != partitionValue)
2226  {
2227  cerr << "Error " << DEC(dwordCount) << " E(" << xHEX0N(partitionValue,8) << "),R(" << xHEX0N(flashValue,8) << ")" << endl;
2228  errorCount++;
2229  if (errorCount > 1)
2230  break;
2231  }
2232 
2233  percentComplete = (dwordCount * 100) / dwordsPerPartition;
2234  if (!_bQuiet)
2235  cout << "Program verify: " << DEC(percentComplete) << "%\r" << flush;
2236  }
2237 
2238  if (errorCount)
2239  {
2240  if (!_bQuiet)
2241  cerr << "Program verify failed: " << DEC(percentComplete) << "%" << endl;
2242  return false;
2243  }
2244  else if (!_bQuiet)
2245  cout << "Program verify: 100% " << endl;
2246  return true;
2247 }
2248 
2249 void CNTV2KonaFlashProgram::DisplayData (const uint32_t address, const uint32_t wordCount)
2250 {
2251  const uint32_t WORDS_PER_LINE(4);
2252  uint32_t addr(address), bank(999), offset(addr % _bankSize);
2253 // SetBankSelect(BankSelect(bank));
2254 
2255  uint32_t lineCount(0);
2256  for (uint32_t words(0); words < wordCount; words++, offset += 4, addr += 4)
2257  {
2258  uint32_t newBank(addr / _bankSize), newOffset(addr % _bankSize);
2259  if (newBank != bank)
2260  {
2261  if (!SetBankSelect(BankSelect(bank = newBank)))
2262  break;
2263  offset = newOffset;
2264  if (words)
2265  cout << endl;
2266  cout << Hex0N(bank * _bankSize + offset,8) << ": ";
2267  }
2271  uint32_t flashValue;
2272  ReadRegister(kRegXenaxFlashDOUT, flashValue);
2273  flashValue = NTV2EndianSwap32(flashValue);
2274  cout << Hex0N(flashValue,8) << " ";
2275  if (++lineCount == WORDS_PER_LINE)
2276  {
2277  cout << endl
2278  << Hex0N((bank * _bankSize + offset + 4),8) << ": ";
2279  lineCount = 0;
2280  }
2281  NTV2_ASSERT((bank * _bankSize + offset) == addr);
2282  } // for each word of requested wordCount
2283  if (lineCount)
2284  cout << endl;
2285 }
2286 
2287 bool CNTV2KonaFlashProgram::FullProgram (vector<uint8_t> & dataBuffer)
2288 {
2289  if (!IsOpen())
2290  return false;
2291  uint32_t baseAddress = 0;
2292  if (!_bQuiet)
2293  cout << "Erasing ROM" << endl;
2294  EraseChip();
2295  BankSelect currentBank = BANK_0;
2296  SetBankSelect(currentBank);
2297 
2298  uint32_t* bitFilePtr = reinterpret_cast<uint32_t*>(dataBuffer.data());
2299  uint32_t twoFixtysixBlockSizeCount = uint32_t((dataBuffer.size()+256)/256);
2300  uint32_t percentComplete = 0;
2302  WriteRegister(kVRegFlashSize, twoFixtysixBlockSizeCount);
2303  for ( uint32_t count = 0; count < twoFixtysixBlockSizeCount; count++, baseAddress += 256, bitFilePtr += 64 )
2304  {
2305  if (baseAddress == _bankSize)
2306  {
2307  baseAddress = 0;
2308  switch(currentBank)
2309  {
2310  case BANK_0: currentBank = BANK_1; break;
2311  case BANK_1: currentBank = BANK_2; break;
2312  case BANK_2: currentBank = BANK_3; break;
2313  case BANK_3: currentBank = BANK_0; break;
2314  }
2315  SetBankSelect(currentBank);
2316  }
2317  FastProgramFlash256(baseAddress, bitFilePtr);
2318  percentComplete = (count*100)/twoFixtysixBlockSizeCount;
2319 
2321  if(!_bQuiet && (count%100 == 0))
2322  cout << "Program status: " << DEC(percentComplete) << "%\r" << flush;
2323  }
2324  if(!_bQuiet)
2325  cout << "Program status: 100% " << endl;
2326 
2327  // Protect Device
2333 
2335 
2343  return true;
2344 }
2345 
2347 {
2348  MacAddr mac1, mac2;
2349  ReadMACAddresses(mac1, mac2);
2350  if(mac1.mac[1] != 0x0C || mac2.mac[1] != 0x0c)
2351  {
2352  if (!_bQuiet)
2353  cout << "Reprogramming the Mac Addresses!" << endl;
2354  string serialString;
2355  GetSerialNumberString(serialString);
2356  MakeMACsFromSerial(serialString.c_str(), &mac1, &mac2);
2357  return ProgramMACAddresses(&mac1, &mac2);
2358  }
2359  return true;
2360 }
2361 
2362 bool CNTV2KonaFlashProgram::MakeMACsFromSerial( const char *sSerialNumber, MacAddr *pMac1, MacAddr *pMac2)
2363 {
2364  // NOTE: We do both auto if either is auto
2365  // TODO: Check if this is an IP board, etc etc
2366  if (strstr(sSerialNumber, "demo") == sSerialNumber)
2367  { // If the serial number begins with demo
2368  int demoNum = 0;
2369  if (sscanf(sSerialNumber + 4, "%d", &demoNum) != 1)
2370  return false;
2371  if ((demoNum < 1) || (demoNum > 128))
2372  {cerr << "WARNING: Outside serial numbers demo0001 to demo0128" << endl; return false;}
2373  pMac2->mac[0] = pMac1->mac[0] = 0x0;
2374  pMac2->mac[1] = pMac1->mac[1] = 0x0c;
2375  pMac2->mac[2] = pMac1->mac[2] = 0x17;
2376  pMac2->mac[3] = pMac1->mac[3] = 0x88;
2377  pMac2->mac[4] = pMac1->mac[4] = 0x12;
2378  pMac1->mac[5] = uint8_t((demoNum - 1) * 2);
2379  pMac2->mac[5] = pMac1->mac[5] + 1;
2380  return true;
2381  }
2382  else if (strstr(sSerialNumber, "1IP") == sSerialNumber)
2383  { // If the serial number begins with 1IP
2384  // 00050 to 08241 (qty 8192) maps to A000 to DFFF (16384 addresses)
2385  // First 4 bytes are: 00:0c:17:42 and next 2 bytes are computed
2386  // as mac1=((serNo - 50)*2 + 0xA000) and
2387  // mac2 = mac1 + 1
2388  int serNum = 0;
2389  if (sscanf(sSerialNumber + 4, "%d", &serNum) != 1)
2390  return false;
2391  if ((serNum < 50) || (serNum > 8241))
2392  {cerr << "WARNING: Outside serial numbers 1IP00050 to 1IP08241" << endl; return false;}
2393 
2394  int mac16LSBs = (0xA000) + (serNum - 50) * 2;
2395 
2396  pMac2->mac[0] = pMac1->mac[0] = 0x0;
2397  pMac2->mac[1] = pMac1->mac[1] = 0x0c;
2398  pMac2->mac[2] = pMac1->mac[2] = 0x17;
2399  pMac2->mac[3] = pMac1->mac[3] = 0x42;
2400  pMac2->mac[4] = pMac1->mac[4] = uint8_t(mac16LSBs >> 8);
2401  pMac2->mac[5] = pMac1->mac[5] = mac16LSBs & 0x0ff;
2402  // The above byte will always be same for the second mac
2403  // based on above allocation
2404  pMac2->mac[5] = pMac1->mac[5] + 1;
2405  return true;
2406  }
2407  else if (strstr(sSerialNumber, "ENG") == sSerialNumber)
2408  { // ENG IoIp - if the serial starts with ENG
2409  // 0000 to 0127 (qty 128) maps to 1B00 to 1BFF (256 addresses)
2410  // First 4 bytes are: 00:0c:17:88 and next 2 bytes are computed
2411  // as mac1= (0x1B00) + (serNum * 2) and
2412  // mac2 = mac1 + 1
2413  int serNum = 0;
2414  if (sscanf(sSerialNumber + 5, "%d", &serNum) != 1)
2415  return false;
2416 
2417  if (serNum > 127)
2418  {cerr << "WARNING: Outside serial numbers ENG00000 to ENG00127" << endl; return false;}
2419 
2420  int mac16LSBs = (0x1B00) + (serNum * 2);
2421 
2422  pMac2->mac[0] = pMac1->mac[0] = 0x0;
2423  pMac2->mac[1] = pMac1->mac[1] = 0x0c;
2424  pMac2->mac[2] = pMac1->mac[2] = 0x17;
2425  pMac2->mac[3] = pMac1->mac[3] = 0x88;
2426  pMac2->mac[4] = pMac1->mac[4] = uint8_t(mac16LSBs >> 8);
2427  pMac2->mac[5] = pMac1->mac[5] = mac16LSBs & 0xff;
2428  // The above byte will always be same for the second mac
2429  // based on above allocation
2430  pMac2->mac[5] = pMac1->mac[5] + 1;
2431  return true;
2432  }
2433  else if (strstr(sSerialNumber, "6XT") == sSerialNumber)
2434  { // IoIP and DNxIP serial numbers
2435  // IoIP Gen 1 [6XT000250 - 6XT008441]
2436  // DNxIP Gen 1 [6XT200250 - 6XT208441]
2437  // IoIP Gen 2 [6XT100250 - 6XT108441]
2438  // DNxIP Gen 2 [6XT300250 - 6XT308441]
2439 
2440  int serNum = 0;
2441  if (sscanf(sSerialNumber + 4, "%d", &serNum) != 1)
2442  return false;
2443 
2444  if ((serNum < 250) || (serNum > 8441))
2445  {cerr << "WARNING: Outside serial numbers range 250 to 8441" << endl; return false;}
2446 
2447  // 0250 to 8441 (qty 8192) maps to 16384 addresses
2448  // First 3 bytes are: 00:0c:17 and next 3 bytes are computed
2449  int mac24LSBs = -1;
2450  if (strstr(sSerialNumber, "6XT0") == sSerialNumber)
2451  {
2452  mac24LSBs = (0x48A000) + ((serNum - 250) * 2);
2453  }
2454  else if (strstr(sSerialNumber, "6XT2") == sSerialNumber)
2455  {
2456  mac24LSBs = (0x48E000) + ((serNum - 250) * 2);
2457  }
2458  else if (strstr(sSerialNumber, "6XT1") == sSerialNumber)
2459  {
2460  mac24LSBs = (0x4B2000) + ((serNum - 250) * 2);
2461  }
2462  else if (strstr(sSerialNumber, "6XT3") == sSerialNumber)
2463  {
2464  mac24LSBs = (0x4B6000) + ((serNum - 250) * 2);
2465  }
2466  else
2467  {
2468  return false;
2469  }
2470 
2471  pMac2->mac[0] = pMac1->mac[0] = 0x0;
2472  pMac2->mac[1] = pMac1->mac[1] = 0x0c;
2473  pMac2->mac[2] = pMac1->mac[2] = 0x17;
2474  pMac2->mac[3] = pMac1->mac[3] = (mac24LSBs & 0xFF0000) >> 16;
2475  pMac2->mac[4] = pMac1->mac[4] = (mac24LSBs & 0x00FF00) >> 8;
2476  pMac2->mac[5] = pMac1->mac[5] = (mac24LSBs & 0x0000FF) >> 0;
2477  // The above byte will always be same for the second mac
2478  // based on above allocation
2479  pMac2->mac[5] = pMac1->mac[5] + 1;
2480  return true;
2481  }
2482  else
2483  cerr << "Unrecognized or unspecified serial number '" << sSerialNumber << "'" << endl;
2484  return false;
2485 }
2486 
2487 
2488 
2489 #ifdef MSWindows
2490 #pragma warning(default: 4800)
2491 #endif
static std::string FlashBlockIDToString(const FlashBlockID inID, const bool inShortDisplay=(0))
Defines the KonaIP/IoIP registers.
long stol(const std::string &str, std::size_t *idx, int base)
Definition: common.cpp:127
uint32_t GetBaseAddressForProgramming(FlashBlockID flashBlockNumber)
bool Allocate(const size_t inByteCount, const bool inPageAligned=false)
Allocates (or re-allocates) my user-space storage using the given byte count. I assume full responsib...
See KONA IP.
Definition: ntv2enums.h:71
IntelRecordType recordType
Definition: ntv2mcsfile.h:42
See Io IP.
Definition: ntv2enums.h:41
I interrogate and control an AJA video/audio capture/playout device.
Definition: ntv2card.h:28
#define BIT(_x_)
Definition: ajatypes.h:578
BankSelect
Definition: ntv2enums.h:4286
#define MAXMCSINFOSIZE
Declares the AJADebug class.
virtual UWord GetIndexNumber(void) const
uint32_t U32(const int inIndex) const
#define DEVICE_IS_KONAX(__d__)
Definition: ntv2enums.h:144
#define MAXBITFILE_HEADERSIZE
ULWord GetByteCount(void) const
_FLASH_COMMAND
Definition: ntv2enums.h:4294
#define SAREK_REGS
Declares the AJATime class.
void DisplayData(const uint32_t address, const uint32_t len)
std::string GetDate(void) const
#define kRegSarekSpiSelect
#define DEVICE_IS_IOIP(__d__)
Definition: ntv2enums.h:139
Defines a number of handy byte-swapping macros.
virtual uint32_t Size(SpiFlashSection sectionID=SPI_FLASH_SECTION_TOTAL)=0
Definition: json.hpp:5362
FlashBlockID
Definition: ntv2enums.h:4274
#define false
uint32_t ULWord
Definition: ajatypes.h:223
bool SetMCSFile(const std::string &sMCSFileName)
virtual class DeviceCapabilities & features(void)
Definition: ntv2card.h:148
bool EraseSector(uint32_t sectorAddress)
bool SetBankSelect(BankSelect bankNumber)
virtual bool Verify(const uint32_t address, const std::vector< uint8_t > &dataWritten)=0
virtual bool Read(const uint32_t address, std::vector< uint8_t > &data, uint32_t maxBytes=1)=0
static bool getFileSize(const string &fileName, size_t &outSizeBytes)
bool NTV2DeviceROMHasBankSelect(const NTV2DeviceID inDeviceID)
virtual bool Erase(const uint32_t address, uint32_t bytes)=0
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:476
bool VerifySOCPartition(FlashBlockID flashID, uint32_t FlashBlockOffset)
virtual bool SetWarmBootFirmwareReload(bool enable)
bool Fill(const T &inValue)
Fills me with the given scalar value.
bool Deallocate(void)
Deallocates my user-space storage (if I own it – i.e. from a prior call to Allocate).
bool SetBitFile(const std::string &inBitfileName, std::ostream &outMsgs, const FlashBlockID blockNumber=AUTO_FLASHBLOCK)
bool IsAllocatedBySDK(void) const
NTV2DeviceID _boardID
My cached device ID.
virtual bool IsOpen(void) const
bool SetFlashBlockIDBank(FlashBlockID blockID)
bool ParseHeader(const NTV2Buffer &inHdrBuffer, std::ostream &outMsgs)
#define KFPNOTE(__x__)
bool CreateBankRecord(BankSelect bankID)
#define AJA_NULL
Definition: ajatypes.h:167
virtual bool GetSerialNumberString(std::string &outSerialNumberString)
Answers with a string that contains my human-readable serial number.
Definition: ntv2card.cpp:229
bool VerifyFlash(FlashBlockID flashBlockNumber, bool fullVerify=(0))
virtual bool Write(const uint32_t address, const std::vector< uint8_t > data, uint32_t maxBytes=1)=0
virtual bool SetBoard(uint32_t index=0)
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
#define BIT_16
Definition: ajatypes.h:603
bool ReadLicenseInfo(std::string &licenseString)
virtual bool isReady(void) const
Definition: ntv2mcsfile.cpp:51
bool ProgramLicenseInfo(const std::string &licenseString)
static CNTV2FlashProgress gNullUpdater
virtual NTV2DeviceID GetDeviceID(void)
bool WriteCommand(_FLASH_COMMAND inCommand)
uint8_t UByte
Definition: ajatypes.h:218
uint16_t linearAddress
Definition: ntv2mcsfile.h:40
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device...
bool NTV2DeviceCanReportRunningFirmwareDate(const NTV2DeviceID inDeviceID)
virtual bool Open(const std::string &inMCSFilePath)
Opens the bitfile at the given path, then parses its header.
Definition: ntv2mcsfile.cpp:73
Describes a user-space buffer on the host computer. I have an address and a length, plus some optional attributes (allocated by SDK?, page-aligned? etc.).
See KONA IP.
Definition: ntv2enums.h:72
NTV2BitfileHeaderParser _parser
bool ProgramMACAddresses(MacAddr *mac1, MacAddr *mac2)
#define DEC(__x__)
virtual bool GetVerbosity()
uint32_t GetNumberOfSectors(FlashBlockID flashBlockNumber)
#define KFPERR(__x__)
virtual bool GetCurrentParsedRecord(IntelRecordInfo &recordInfo)
bool ReadHeader(FlashBlockID flashBlock)
std::string Program(bool fullVerify=(0))
#define NTV2_UNUSED(__p__)
Definition: ajatypes.h:132
bool ProgramFlashValue(uint32_t address, uint32_t value)
bool EraseChip(UWord chip=0)
#define KFPDBUG(__x__)
bool FullProgram(std::vector< uint8_t > &dataBuffer)
uint16_t UWord
Definition: ajatypes.h:221
std::vector< uint8_t > _partitionBuffer
uint8_t mac[6]
virtual bool WriteRegister(const ULWord inRegNum, const ULWord inValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Updates or replaces all or part of the 32-bit contents of a specific register (real or virtual) on th...
virtual uint32_t Offset(SpiFlashSection sectionID=SPI_FLASH_SECTION_TOTAL)=0
See Io IP.
Definition: ntv2enums.h:40
#define xHEX0N(__x__, __n__)
bool FastProgramFlash256(uint32_t address, uint32_t *buffer)
bool IsInstalledFWRunning(bool &outIsRunning, std::ostream &outErrorMsgs)
Declares the CNTV2KonaFlashProgram class.
#define kRegSarekControl
#define ENUM_CASE_RETURN_VAL_OR_ENUM_STR(condition, retail_name, enum_name)
bool ProgramSOC(bool verify=(!(0)))
bool CheckFlashErasedWithBlockID(FlashBlockID flashBlockNumber)
Private include file for all ajabase sources.
void ParsePartitionFromFileLines(uint32_t address, uint16_t &partitionOffset)
bool ProgramFromMCS(bool verify)
std::string AsString(void) const
virtual bool UpdatePercentage(const size_t inPercentage)
UWord NTV2DeviceGetSPIFlashVersion(const NTV2DeviceID inDeviceID)
bool EraseBlock(FlashBlockID blockNumber)
#define MCS_STEPS
void * GetHostPointer(void) const
#define HEX0N(__x__, __n__)
Definition: debug.cpp:1175
bool ReadFlash(NTV2Buffer &outBuffer, const FlashBlockID flashID, CNTV2FlashProgress &inFlashProgress=CNTV2FlashProgress::nullUpdater)
virtual void SetVerbosity(bool verbose)
#define DECN(__x__, __n__)
#define Hex0N(__x__, __n__)
bool ProgramKonaxMB(const std::string &sCustomFileName, const uint32_t addr, std::ostream &outMsgs)
void DetermineFlashTypeAndBlockNumberFromFileName(const std::string &bitFileName)
bool ProgramCustom(const std::string &sCustomFileName, const uint32_t addr, std::ostream &outMsgs)
#define NTV2EndianSwap32(__val__)
Definition: ntv2endian.h:19
bool CreateSRecord(bool bChangeEndian)
virtual bool GetRunningFirmwareDate(UWord &outYear, UWord &outMonth, UWord &outDay)
Reports the (local Pacific) build date of the currently-running firmware.
virtual uint32_t GetPartition(UByteSequence &patitionBuffer, uint16_t baseELARaddress, uint16_t &partitionOffset, bool nextPartition=false)
static CNTV2FlashProgress & nullUpdater
bool ReadMACAddresses(MacAddr &mac1, MacAddr &mac2)
bool MakeMACsFromSerial(const char *sSerialNumber, MacAddr *pMac1, MacAddr *pMac2)