434 lines
20 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|