tbf/NfcHandler/ST25DV_Device.cs
2024-07-25 12:14:58 +02:00

434 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//*****************************************************************************
// Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved.
// Author: Venkat, Rajeshwar
//*****************************************************************************
namespace Sensus.iPerl.NfcHandler
{
public class ST25DV_Device
{
private readonly byte[] ST25DV_CMD_GET_SYSTEM_INFO = { 0x2B }; //Command code
private byte[] ST25DV_CMD_READ_SINGLE_BLOCK = { 0x20, 0x00 }; //Command code, EEPROM block number (this will be received from caller).
private byte[] ST25DV_CMD_WRITE_SINGLE_BLOCK = { 0x21, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Command code, EEPROM block number (this will be received from caller), 4-byte payload to be written (this will be received from caller).
private byte[] ST25DV_CMD_READ_MULTIPLE_BLOCKS = { 0x23, 0x00, 0x00 }; //Command code, EEPROM starting block number (this will be received from caller), number of blocks (this will be received from caller)
private byte[] ST25DV_CMD_READ_CONFIG = { 0xA0, 0x02, 0x00 }; //Command code, IC Mfg Code, Register address (this will be received from caller)
private byte[] ST25DV_CMD_READ_DYNAMIC_CONFIG = { 0xAD, 0x02, 0x00 }; //Command code, IC Mfg Code, Register address (this will be received from caller)
private byte[] ST25DV_CMD_WRITE_DYNAMIC_CONFIG = { 0xAE, 0x02, 0x00, 0x00 }; //Command code, IC Mfg Code, Register address, register value to be written
private readonly byte[] ST25DV_CMD_READ_MAILBOX_CONTROL_REG = { 0xAD, 0x02, 0x0D }; //Command code, IC Mfg Code, MB_CTRL_Dyn Register address
private readonly byte[] ST25DV_CMD_READ_MAILBOX_MESSAGE_LENGTH = { 0xAB, 0x02 }; //Command code, IC Mfg Code
private byte[] ST25DV_CMD_READ_MESSAGE = { 0xAC, 0x02, 0x00, 0x00 }; //Command code, IC Mfg Code, Mailbox pointer(mostly this is 0), NumberofBytesToRead (this will be received from caller)
private byte[] ST25DV_CMD_MANAGE_GPO = { 0xA9, 0x02, 0x00 }; //Command code, IC Mfg Code, GPO value
public readonly byte GPO_MANAGE_SET_PULSE = 0x80; // Command code to set a pulse on the GPO pin (if enabled by FW in the Meter)
private CR95HF_Reader _CR95HF_Reader;
private System.Timers.Timer _CycleTimeoutTimer = new System.Timers.Timer();
private static readonly Dictionary<byte, string> ST25DV_ErrorCodes = new Dictionary<byte, string>
{
{0x00 , "Success, No error" },
{0x01 , "Command is not supported" },
{0x02 , "Command is not recognized(format error)" },
{0x03 , "Option not supported" },
{0x0F , "Error with no information given" },
{0x10 , "The specified block is not available" },
{0x11 , "The specified block is already locked and thus cannot be locked again" },
{0x12 , "The specified block is locked and its contents cannot be changed" },
{0x13 , "The specified block was not successfully programmed" },
{0x14 , "The specified block was not successfully locked" },
{0x15 , "The specified block is protected in read" }
};
public event DelNfc_ST25DV_MessageHandler MessageEvent;
public ST25DV_Device(CR95HF_Reader CR95HFReader)
{
_CR95HF_Reader = CR95HFReader;
}
#region Message Event
private void OnMessageEvent(string message)
{
NfcMessageEventArgs e = new NfcMessageEventArgs();
e.Message = message;
if (MessageEvent != null)
{
MessageEvent(this, e);
}
e = null;
}
#endregion
public bool ST25DV_GetSystemInfo(out byte[] responseData)
{
byte[] response = new byte[20];
responseData = null;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_GET_SYSTEM_INFO, out response))
{
if (response == null)
{
return false;
}
//Success - ResponseFlags = 0x00, 14 bytes payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
responseData = new byte[14];
for (int i=0; i<14; i++)
{
responseData[i] = response[i + 1];
}
//OnMessageEvent("Read GetSystemInfo: " + Tools.ByteArrayToHexString(responseData));
return true;
}
else
{
if ((responseData[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(responseData[1])))
OnMessageEvent("Read GetSystemInfo: Failed with ST25DV error - " + ST25DV_ErrorCodes[responseData[1]]);
}
}
OnMessageEvent("Read GetSystemInfo: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadSingleBlock(byte blockNumber, out byte[] outBuffer, bool logEnabled = false)
{
byte[] response = null;
outBuffer = null;
int StartingByteAddress = Convert.ToInt32(blockNumber) * 4;
ST25DV_CMD_READ_SINGLE_BLOCK[1] = blockNumber;
if (logEnabled)
{
OnMessageEvent("Read EEPROM: 0x04" + " bytes from the address 0x" + Tools.DecimalToHexString(StartingByteAddress.ToString(), 1));
}
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_SINGLE_BLOCK, out response))
{
//Success - ResponseFlags = 0x00, payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = new byte[4];
for (int i = 0; i < 4; i++)
{
outBuffer[i] = response[1 + i];
}
if (logEnabled)
{
OnMessageEvent("Read EEPROM: " + Tools.BytesToHex(outBuffer));
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read EEPROM: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read EEPROM: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_WriteSingleBlock(byte blockNumber, byte[] inBuffer, bool logEnabled = false)
{
byte[] response = null;
int StartingByteAddress = Convert.ToInt32(blockNumber) * 4;
ST25DV_CMD_WRITE_SINGLE_BLOCK[1] = blockNumber;
for (int i = 0; i < 4; i++)
{
ST25DV_CMD_WRITE_SINGLE_BLOCK[2 + i] = inBuffer[i];
}
if (logEnabled)
{
OnMessageEvent("Write EEPROM: 0x04 bytes 0x" + Tools.BytesToHex(inBuffer) + " to the address 0x" + Tools.DecimalToHexString(StartingByteAddress.ToString(), 1));
}
//This will disable MB, 0x0D is MB_CTRL_Dyn register pointer and 0x00 is the value written
if (ST25DV_WriteDynamicConfiguration(0x0D, 0x00, false))
{
_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_WRITE_SINGLE_BLOCK, out response);
}
else
{
OnMessageEvent("Write EEPROM: MB disable failed");
return false;
}
//This function will leave ST25DV with MB disabled state and it needs to be enabled by I2C interface
return true;
}
public bool ST25DV_ReadMultipleBlocks(byte startingBlockNumber, byte numberOfBlocks, out byte [] outBuffer)
{
byte[] response = new byte[16]; //Maximum allowed to read is 16 bytes (4 blocks) with this command
outBuffer = null;
ST25DV_CMD_READ_MULTIPLE_BLOCKS[1] = startingBlockNumber;
ST25DV_CMD_READ_MULTIPLE_BLOCKS[2] = numberOfBlocks;
if (Convert.ToInt32(numberOfBlocks) >= 4) //maximum allowed to read with one command is 4 blocks (means 3)
{
OnMessageEvent("Read EEPROM: Invalid Input"); //TBD-needs to validate startingBlockNumber based on 4K or 16K or 64K chip read info
return false;
}
int totalReadBytes = (Convert.ToInt32(numberOfBlocks) + 1) * 4;
int StartingByteAddress = Convert.ToInt32(startingBlockNumber) * 4;
OnMessageEvent("Read EEPROM: " + "0x" + Tools.DecimalToHexString(totalReadBytes.ToString(),1) + " bytes from the byte " + "0x" + Tools.DecimalToHexString(StartingByteAddress.ToString(), 1));
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_MULTIPLE_BLOCKS, out response))
{
//Success - ResponseFlags = 0x00, payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = new byte[response.Length-4];
for (int i = 0; i < response.Length-4; i++)
{
outBuffer[i] = response[1 + i];
}
OnMessageEvent("Read EEPROM: " + Tools.BytesToHex(outBuffer));
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read EEPROM: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read EEPROM: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadConfiguration(byte regAddress, out byte outBuffer, bool logEnabled = false)
{
byte[] response = null;
ST25DV_CMD_READ_CONFIG[2] = regAddress;
outBuffer = 0x00;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_CONFIG, out response))
{
//Success - ResponseFlags = 0x00, 1 byte payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = response[1];
if (logEnabled)
{
OnMessageEvent("Read Static Config Register @address: " + "0x" + Tools.DecimalToHexString(Convert.ToInt32(regAddress).ToString(), 1) + " as " + Tools.ByteToHexString(outBuffer));
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read Static Config Register: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read Static Config Register: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadDynamicConfiguration(byte regAddress, out byte outBuffer, bool logEnabled = false)
{
byte[] response = null;
ST25DV_CMD_READ_DYNAMIC_CONFIG[2] = regAddress;
outBuffer = 0x00;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_DYNAMIC_CONFIG, out response))
{
//Success - ResponseFlags = 0x00, 1 byte payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = response[1];
if (logEnabled)
{
OnMessageEvent("Read Dynamic Config Register @address: " + "0x" + Tools.DecimalToHexString(Convert.ToInt32(regAddress).ToString(), 1) + " as " + Tools.ByteToHexString(outBuffer));
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read Dynamic Config Register: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read Dynamic Config Register: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_WriteGPOManageCommand(byte regValue, bool logEnabled)
{
byte[] response = null;
ST25DV_CMD_MANAGE_GPO[2] = regValue;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_MANAGE_GPO, out response))
{
//Success - ResponseFlags = 0x00, success
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
if (logEnabled)
{
OnMessageEvent("Write GPO Manage: Success");
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Write GPO Manage: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Write GPO Manage: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_WriteDynamicConfiguration(byte regAddress, byte regValue, bool logEnabled)
{
byte[] response = null;
ST25DV_CMD_WRITE_DYNAMIC_CONFIG[2] = regAddress;
ST25DV_CMD_WRITE_DYNAMIC_CONFIG[3] = regValue;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_WRITE_DYNAMIC_CONFIG, out response))
{
//Success - ResponseFlags = 0x00, success
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
if (logEnabled)
{
OnMessageEvent("Write Dynamic Config Register: Success");
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Write Dynamic Config Register: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Write Dynamic Config Register: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadMailboxControlReg(out byte outBuffer)
{
byte[] response = null;
outBuffer = 0x00;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_MAILBOX_CONTROL_REG, out response))
{
//Success - ResponseFlags = 0x00, 1 byte payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = response[1];
//OnMessageEvent("Read Dynamic Config Register MBCtrl @address: 0x0D" + " as " + Tools.ByteToHexString(outBuffer));
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read Dynamic Config Register MBCtrl: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read Dynamic Config Register MBCtrl: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadMailboxMessageLength(out byte outBuffer, bool logEnabled = false)
{
byte[] response = null;
outBuffer = 0x00;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_MAILBOX_MESSAGE_LENGTH, out response))
{
//Success - ResponseFlags = 0x00, 1 byte payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
outBuffer = response[1];
if (logEnabled)
{
OnMessageEvent("Read Mailbox Message Length: " + Tools.ByteToHexString(outBuffer));
}
return true;
}
else
{
if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1])))
OnMessageEvent("Read Mailbox Message Length: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
}
OnMessageEvent("Read Mailbox Message Length: Failed with ST25DV Unidentified error");
return false;
}
public bool ST25DV_ReadMessage(byte bytesToRead, out byte[] outBuffer)
{
byte[] response = null;
outBuffer = null;
ST25DV_CMD_READ_MESSAGE[2] = 0x00; //Pointer in mailbox, 0x00 indicates reads from beginning
ST25DV_CMD_READ_MESSAGE[3] = bytesToRead;
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_READ_MESSAGE, out response))
{
outBuffer = new byte[response.Length-4];
//Success - ResponseFlags = 0x00, payload
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
for (int i = 0; i < response.Length-4; i++)
{
outBuffer[i] = response[1 + i];
}
OnMessageEvent("Read Message: " + Tools.BytesToHex(outBuffer));
return true;
}
if ((response[0] == 0x01) && ST25DV_ErrorCodes.ContainsKey(response[1]))
OnMessageEvent("Read Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
OnMessageEvent("Read Message Failed: With ST25DV Unidentified error");
return false;
}
public bool ST25DV_WriteMessage(byte [] inBuffer)
{
byte[] response = null;
List<byte> ST25DV_CMD_WRITE_MESSAGE = new List<byte>();
ST25DV_CMD_WRITE_MESSAGE.Add(0xAA); //Write message command code
ST25DV_CMD_WRITE_MESSAGE.Add(0x02); //IC Mfg Code
ST25DV_CMD_WRITE_MESSAGE.Add(Convert.ToByte(inBuffer.Length - 1)); //This is the app given payload - 1
ST25DV_CMD_WRITE_MESSAGE.AddRange(inBuffer);
if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_WRITE_MESSAGE.ToArray(), out response))
{
//Success - ResponseFlags = 0x00
//Error - ResponseFlags = 0x01, 1 byte error code
if (response[0] == 0x00)
{
//OnMessageEvent("Write Message: " + Tools.ByteArrayToHexString(inBuffer));
return true;
}
if ((response[0] == 0x01) && ST25DV_ErrorCodes.ContainsKey(response[1]))
OnMessageEvent("Write Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]);
}
OnMessageEvent("Write Message Failed: With ST25DV Unidentified error");
return false;
}
}
}