/* SPDX-License-Identifier: MIT */
/**
	@file		ntv2konaflashprogram.h
	@brief		Declares the CNTV2KonaFlashProgram class.
	@copyright	(C) 2010-2022 AJA Video Systems, Inc.  All rights reserved.
**/

#ifndef NTV2KONAFLASHPROGRAM_H
#define NTV2KONAFLASHPROGRAM_H

#include "ntv2card.h"
#include <fstream>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include "ntv2debug.h"
#include "ntv2mcsfile.h"
#include "ntv2spiinterface.h"
#include "ntv2bitfile.h"

#define MAXBITFILE_HEADERSIZE 512
#define MAXMCSINFOSIZE 256
#define MAXMCSLICENSESIZE 256
#define MCS_STEPS	   6

struct MacAddr
{
	uint8_t mac[6];
	std::string AsString(void) const;
};


class AJAExport CNTV2FlashProgress
{
	public:
		static CNTV2FlashProgress & nullUpdater;

						CNTV2FlashProgress()	{}
		virtual			~CNTV2FlashProgress()	{}
		virtual bool	UpdatePercentage (const size_t inPercentage)	{(void) inPercentage; return true;}
};	//	CNTV2PercentUpdater


class AJAExport CNTV2KonaFlashProgram : public CNTV2Card
{
public:
	CNTV2KonaFlashProgram();
	CNTV2KonaFlashProgram (const UWord boardNumber);
	virtual ~CNTV2KonaFlashProgram();
	static std::string	FlashBlockIDToString (const FlashBlockID inID, const bool inShortDisplay = false);	//	New in SDK 16.0

public:
	virtual bool	SetBoard (uint32_t index = 0);
	bool			ReadHeader (FlashBlockID flashBlock);
	bool			ReadInfoString();
	bool			SetBitFile (const std::string & inBitfileName, std::ostream & outMsgs, const FlashBlockID blockNumber = AUTO_FLASHBLOCK);	//	New in SDK 16.0
	bool			SetMCSFile (const std::string & sMCSFileName);
	std::string		Program (bool fullVerify = false);
	bool			ProgramFromMCS(bool verify);
	bool			ProgramSOC(bool verify = true);
	bool			ProgramCustom (const std::string & sCustomFileName, const uint32_t addr, std::ostream & outMsgs);
    bool			ProgramKonaxMB (const std::string & sCustomFileName, const uint32_t addr, std::ostream & outMsgs);
	bool			EraseBlock (FlashBlockID blockNumber);
	bool			EraseChip (UWord chip = 0);
	bool			CreateSRecord (bool bChangeEndian);
	bool			CreateEDIDIntelRecord ();
	void			SetQuietMode ();
	bool			VerifyFlash (FlashBlockID flashBlockNumber, bool fullVerify = false);
	bool			ReadFlash (NTV2Buffer & outBuffer, const FlashBlockID flashID, CNTV2FlashProgress & inFlashProgress = CNTV2FlashProgress::nullUpdater);	//	New in SDK 16.0
	bool			SetBankSelect (BankSelect bankNumber);
	bool			SetFlashBlockIDBank(FlashBlockID blockID);
	bool			ROMHasBankSelect();
	uint32_t		ReadBankSelect ();
	bool			SetMBReset();
	bool			IsInstalledFWRunning (bool & outIsRunning, std::ostream & outErrorMsgs);
	bool			WriteCommand(_FLASH_COMMAND inCommand);

	std::string		GetDesignName (void) const	{return _parser.DesignName();}
	std::string		GetPartName (void) const	{return _parser.PartName();}
	std::string		GetDate (void) const		{return _parser.Date();}
	std::string		GetTime (void) const		{return _parser.Time();}
	const NTV2BitfileHeaderParser & Parser (void) const	{return _parser;}
	uint32_t		GetNumBytes(void) const		{return _numBytes;}
	const std::string &	GetMCSInfo (void) const	{return _mcsInfo;}
	void ParsePartitionFromFileLines(uint32_t address, uint16_t & partitionOffset);
	bool CreateBankRecord(BankSelect bankID);

	bool ProgramMACAddresses(MacAddr * mac1, MacAddr * mac2);
	bool ReadMACAddresses(MacAddr & mac1, MacAddr & mac2);
	bool ProgramLicenseInfo(const std::string & licenseString);
	bool ReadLicenseInfo(std::string & licenseString);
	void DisplayData(const uint32_t address, const uint32_t len);
	bool ProgramInfoFromString(std::string infoString);
	bool FullProgram(std::vector<uint8_t> & dataBuffer);

	int32_t	 NextMcsStep() {return ++_mcsStep;}

	bool WaitForFlashNOTBusy();
	bool ProgramFlashValue(uint32_t address, uint32_t value);
	bool FastProgramFlash256(uint32_t address, uint32_t* buffer);
	bool EraseSector(uint32_t sectorAddress);
	bool CheckFlashErasedWithBlockID(FlashBlockID flashBlockNumber);
	uint32_t ReadDeviceID();
	bool SetDeviceProperties();
	void DetermineFlashTypeAndBlockNumberFromFileName(const std::string & bitFileName);

	uint32_t GetSectorAddressForSector(FlashBlockID flashBlockNumber,uint32_t sectorNumber)
	{
		return GetBaseAddressForProgramming(flashBlockNumber)+(sectorNumber*_sectorSize);
	}

	uint32_t GetBaseAddressForProgramming(FlashBlockID flashBlockNumber)
	{
		switch ( flashBlockNumber )
		{
			default:
			case MAIN_FLASHBLOCK:		return _mainOffset;
			case FAILSAFE_FLASHBLOCK:	return _failSafeOffset;
			case SOC1_FLASHBLOCK:		return _soc1Offset;
			case SOC2_FLASHBLOCK:		return _soc2Offset;
			case MAC_FLASHBLOCK:		return _macOffset;
			case MCS_INFO_BLOCK:		return _mcsInfoOffset;
			case LICENSE_BLOCK:			return _licenseOffset;
		}

	}

	uint32_t GetNumberOfSectors(FlashBlockID flashBlockNumber)
	{
		switch ( flashBlockNumber )
		{
			default:
			case MAIN_FLASHBLOCK:		return _numSectorsMain;
			case FAILSAFE_FLASHBLOCK:	return _numSectorsFailSafe;
			case SOC1_FLASHBLOCK:		return _numSectorsSOC1;
			case SOC2_FLASHBLOCK:		return _numSectorsSOC2;
			case MAC_FLASHBLOCK:		return 1;
			case MCS_INFO_BLOCK:		return 1;
			case LICENSE_BLOCK:			return 1;
		}
	}

	bool VerifySOCPartition(FlashBlockID flashID, uint32_t FlashBlockOffset);
	bool CheckAndFixMACs();
	bool MakeMACsFromSerial( const char *sSerialNumber, MacAddr *pMac1, MacAddr *pMac2 );

protected:
	NTV2Buffer		_bitFileBuffer;
	uint8_t *		_customFileBuffer;
	uint32_t		_bitFileSize;
	NTV2BitfileHeaderParser	_parser;
	std::string		_bitFileName;
	std::string		_mcsInfo;
	uint32_t		_spiDeviceID;
	uint32_t		_flashSize;
	uint32_t		_bankSize;
	uint32_t		_sectorSize;
	uint32_t		_mainOffset;
	uint32_t		_failSafeOffset;
	uint32_t		_macOffset;
	uint32_t		_mcsInfoOffset;
	uint32_t		_licenseOffset;
	uint32_t		_soc1Offset;
	uint32_t		_soc2Offset;
	uint32_t		_numSectorsMain;
	uint32_t		_numSectorsSOC1;
	uint32_t		_numSectorsSOC2;
	uint32_t		_numSectorsFailSafe;
	uint32_t		_numBytes;
	FlashBlockID	_flashID;
	uint32_t		_deviceID;
	bool			_bQuiet;
	int32_t			_mcsStep;
	CNTV2MCSfile	_mcsFile;
	std::vector<uint8_t> _partitionBuffer;
	uint32_t		_failSafePadding;
	CNTV2SpiFlash * _spiFlash;
	bool			_hasExtendedCommandSupport;
};	//	CNTV2KonaFlashProgram

#endif	//	NTV2KONAFLASHPROGRAM_H
