using Edge.Core.Parser;
using Edge.Core.Parser.BinaryParser.Util;
using Edge.Core.Processor;
using Edge.Core.Processor.Communicator;
using Edge.Core.Processor.Dispatcher.Attributes;
using Edge.Core.UniversalApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ShengJu_CUT100_DES.MessageEntity.Incoming;
using ShengJu_CUT100_DES.MessageEntity.Outgoing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using static ShengJu_CUT100_DES.MessageEntity.Outgoing.ModifyPredefinedFileKey;
namespace ShengJu_CUT100_DES
{
///
/// at least at 2021.4, 这模块还不支持并线,因为模块内部并没有区分请求中的地址值。
///
[MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))]
[MetaPartsRequired(typeof(ComPortCommunicator<>))]
[MetaPartsRequired(typeof(TcpClientCommunicator<>))]
[MetaPartsDescriptor(
"lang-zh-cn:ShengJu CUT100_DES 感应卡读写卡模块lang-en-us:ShengJu CUT100_DES contactless card read&write module",
"lang-zh-cn:用于驱动 盛炬CUT100_DES 感应卡读写卡模块, 波特率19200, None, 8, 1lang-en-us:Used for driven ShengJu CUT100_DES contactless card read&write module, BaudRate 19200, None, 8, 1",
new[] { "lang-zh-cn:支付终端lang-en-us:Terminal" })]
[UniversalApi(Name = GenericAlarm.UniversalApiEventName, EventDataType = typeof(GenericAlarm[]), Description = "Fire GenericAlarms to AlarmBar for attracting users.")]
[UniversalApi(Name = OnCardTapEventName, EventDataType = typeof(object), Description = "Fired once a DesFire EV1 card detected by module and card UID is read")]
public class GroupHandler : TestableActivePollingDeviceHandler
{
public const string OnCardTapEventName = "OnCardTap";
public event EventHandler OnModuleStateChange;
public event EventHandler OnCardTap;
private ILogger logger = NullLogger.Instance;
private IServiceProvider services;
protected IContext context;
private DeviceConfigV1 deviceConfig;
private IEnumerable cardReaderModules;
private const int singleModuleOfflineTimeThresholdByMs = 15000;
//private Dictionary boardsLastImcomingMsgReceivedTimes;
private Timer singleModuleOfflineCheckTimer;
[UniversalApi]
public IEnumerable CardReaderModuels => this.cardReaderModules;
public class CardReaderModule
{
private ILogger logger = NullLogger.Instance;
private IContext context;
public enum CardReaderModuleStateEnum { Offline, Online }
public string Name { get; set; }
public string Description { get; set; }
public byte PhysicalAddress { get; }
public string HardwareFirmware { get; set; }
public string UnderlyingCommunicatorIdentity { get; set; }
public CardReaderModuleStateEnum ModuleState { get; set; }
///
/// used for track the last received message which for caculate the offline state of this device.
///
public DateTime? LastIncomingMessageReceivedTime { get; set; }
internal CardReaderModule(byte physicalAddress, ILogger logger)
{
this.PhysicalAddress = physicalAddress;
this.logger = logger;
}
internal void SetContext(IContext context)
{
this.context = context;
}
internal async Task ReadCardUID(byte modulePhysicalAddress)
{
var readCardUidResponse = await this.context.Outgoing.WriteAsync(
new ActivateATypeCardRequest() { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress
&& (testResponse is GenericFailureResponse || testResponse is ActivateATypeCardResponse), 4000);
if (readCardUidResponse is ActivateATypeCardResponse rp)
{
if (rp.UID.Any())
return new CardOperationResult(200, rp.UID) { CardReaderModule = this };
else
return new CardOperationResult(404) { CardReaderModule = this, ModuleResultCode = "No UID was read" };
}
else if (readCardUidResponse is GenericFailureResponse failedResponse)
{
this.logger.LogInformation($"ReadCardUID failed with module code: {failedResponse.模块返回状态}, cpu code: {failedResponse.CpuCardState} for module with physical address: {failedResponse.ModulePhysicalAddress}");
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedResponse.模块返回状态.ToString(), CpuCardResultCode = failedResponse.CpuCardState.ToString() };
}
else
{
this.logger.LogInformation($"ReadCardUID timed out for module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
return new CardOperationResult(500) { CardReaderModule = this, ModuleResultCode = "Device response timed out" };
}
}
internal async Task FormatCardByResetToNewRootKeyAndBuildDefaultFileStructures(byte modulePhysicalAddress, byte[] oldRootKeyBytes, byte[] newRootKeyBytes)
{
if (oldRootKeyBytes == null || !oldRootKeyBytes.Any())
throw new ArgumentException(nameof(oldRootKeyBytes));
if (newRootKeyBytes == null || !newRootKeyBytes.Any())
throw new ArgumentException(nameof(newRootKeyBytes));
var formatCardResponse = await this.context.Outgoing.WriteAsync(
new FormatCardRequest(oldRootKeyBytes, newRootKeyBytes) { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress
&& (testResponse is GenericFailureResponse || testResponse is GenericSuccessResponse), 4000);
if (formatCardResponse is GenericSuccessResponse)
{
this.logger.LogInformation($"Format Card successfully on module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity}), will auto re-read card app dirs...");
var readAppDirsResponse = await this.context.Outgoing.WriteAsync(
new ReadAppDirsRequest(newRootKeyBytes) { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress && (testResponse is GenericFailureResponse || testResponse is ReadAppDirsResponse), 4000);
if (readAppDirsResponse is ReadAppDirsResponse successReadAppDirsResponse)
{
this.logger.LogInformation($" Read Card AppDirs, count: {successReadAppDirsResponse.DirCount}, " +
$"dirIds: {successReadAppDirsResponse.DirIds.Select(did => did.Select(i => i.ToString("X2")).Aggregate("0x", (acc, n) => acc + " " + n)).Aggregate((acc, n) => acc + ", " + n)} " +
$"on module (phyAdrs: {successReadAppDirsResponse.ModulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
}
else if (readAppDirsResponse is GenericFailureResponse failedReadAppDirsResponse)
{
this.logger.LogInformation($" Read Card AppDirs failed with module code: {failedReadAppDirsResponse.模块返回状态}, cpu code: {failedReadAppDirsResponse.CpuCardState} for module (phyAdrs: {failedReadAppDirsResponse.ModulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
}
else
{
this.logger.LogInformation($" Read Card AppDirs timed out for module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
}
return new CardOperationResult(200) { CardReaderModule = this };
}
else if (formatCardResponse is GenericFailureResponse failedFormatCardResponse)
{
this.logger.LogInformation($"Format Card failed with module code: {failedFormatCardResponse.模块返回状态}, cpu code: {failedFormatCardResponse.CpuCardState} for module with physical address: {failedFormatCardResponse.ModulePhysicalAddress}");
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedFormatCardResponse.模块返回状态.ToString(), CpuCardResultCode = failedFormatCardResponse.CpuCardState.ToString() };
}
else
{
this.logger.LogInformation($"Format Card timed out for module with physical address: {modulePhysicalAddress}");
return new CardOperationResult(500) { CardReaderModule = this, ModuleResultCode = "Device response timed out" };
}
}
internal async Task WriteCard(byte modulePhysicalAddress, byte fileId, byte blockAddress, byte[] dataBytes, byte[] writeKeyBytes)
{
if (writeKeyBytes == null || !writeKeyBytes.Any())
throw new ArgumentException(nameof(writeKeyBytes));
var writeAppFileRequestResponse = await this.context.Outgoing.WriteAsync(
new WriteAppFileRequest(fileId, blockAddress, writeKeyBytes, dataBytes) { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress
&& (testResponse is GenericFailureResponse || testResponse is GenericSuccessResponse), 4000);
if (writeAppFileRequestResponse is GenericSuccessResponse successResponse)
{
return new CardOperationResult(200) { CardReaderModule = this };
}
else if (writeAppFileRequestResponse is GenericFailureResponse failedResponse)
{
this.logger.LogInformation($"Write Card failed with module code: {failedResponse.模块返回状态}, cpu code: {failedResponse.CpuCardState} for module with physical address: {failedResponse.ModulePhysicalAddress}");
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedResponse.模块返回状态.ToString(), CpuCardResultCode = failedResponse.CpuCardState.ToString() };
}
else
{
this.logger.LogInformation($"Write Card timed out for module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
return new CardOperationResult(500) { CardReaderModule = this, ModuleResultCode = "Device response timed out" };
}
}
internal async Task ReadCard(byte modulePhysicalAddress, byte fileId, byte blockAddress, byte[] readKeyBytes)
{
if (readKeyBytes == null || !readKeyBytes.Any())
throw new ArgumentException(nameof(readKeyBytes));
var readAppFileRequestResponse = await this.context.Outgoing.WriteAsync(
new ReadAppFileRequest(fileId, blockAddress, readKeyBytes) { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress
&& (testResponse is GenericFailureResponse || testResponse is ReadAppFileResponse), 4000);
if (readAppFileRequestResponse is ReadAppFileResponse successResponse)
{
return new CardOperationResult(200, successResponse.Data) { CardReaderModule = this };
}
else if (readAppFileRequestResponse is GenericFailureResponse failedResponse)
{
this.logger.LogInformation($"Read Card failed with module code: {failedResponse.模块返回状态}, cpu code: {failedResponse.CpuCardState} for module with physical address: {failedResponse.ModulePhysicalAddress}");
if (failedResponse.模块返回状态 == MessageEntity.IncomingMessageBase.ModuleStateEnum.读取CPU卡文件失败)
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedResponse.模块返回状态.ToString() + ", 请保持卡片靠近读卡器", CpuCardResultCode = failedResponse.CpuCardState.ToString() };
else
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedResponse.模块返回状态.ToString(), CpuCardResultCode = failedResponse.CpuCardState.ToString() };
}
else
{
this.logger.LogInformation($"Read Card timed out for module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
return new CardOperationResult(500) { CardReaderModule = this, ModuleResultCode = "与读卡器通讯超时" };
}
}
internal async Task ModifyPredefinedFileKey(byte modulePhysicalAddress, PredefinedFileKeyTypeEnum fileKeyType, byte[] oldKeyBytes, byte[] newKeyBytes)
{
if (oldKeyBytes == null || !oldKeyBytes.Any())
throw new ArgumentException(nameof(oldKeyBytes));
if (newKeyBytes == null || !newKeyBytes.Any())
throw new ArgumentException(nameof(newKeyBytes));
var modifyPredefinedFileKeyResponse = await this.context.Outgoing.WriteAsync(
new ModifyPredefinedFileKey(fileKeyType, oldKeyBytes, newKeyBytes) { ModulePhysicalAddress = modulePhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == modulePhysicalAddress
&& (testResponse is GenericFailureResponse || testResponse is GenericSuccessResponse), 4000);
if (modifyPredefinedFileKeyResponse is GenericSuccessResponse successResponse)
{
return new CardOperationResult(200) { CardReaderModule = this };
}
else if (modifyPredefinedFileKeyResponse is GenericFailureResponse failedResponse)
{
this.logger.LogInformation($"Modify Predefined FileKey failed with module code: {failedResponse.模块返回状态}, cpu code: {failedResponse.CpuCardState} for module with physical address: {failedResponse.ModulePhysicalAddress}");
return new CardOperationResult(400) { CardReaderModule = this, ModuleResultCode = failedResponse.模块返回状态.ToString(), CpuCardResultCode = failedResponse.CpuCardState.ToString() };
}
else
{
this.logger.LogInformation($"Modify Predefined FileKey timed out for module (phyAdrs: {modulePhysicalAddress}, comm: {this.context.Communicator.Identity})");
return new CardOperationResult(500) { CardReaderModule = this, ModuleResultCode = "Device response timed out" };
}
}
}
public class CardOperationResult
{
public CardOperationResult(int overallResultCode, byte[] data)
{
this.OverallResultCode = overallResultCode;
if (data != null && data.Any())
{
this.Data = data.Select(b => (int)b).ToArray();
this.PrettyUTF8DecodedData = Encoding.UTF8.GetString(data);
this.PrettyHexStrData = "0x" + data.ToHexLogString();
}
}
public CardOperationResult(int overallResultCode) : this(overallResultCode, null)
{
}
public int OverallResultCode { get; set; }
public string ModuleResultCode { get; set; }
public string CpuCardResultCode { get; set; }
public CardReaderModule CardReaderModule { get; set; }
///
/// for better serialize, here use int instead of byte.
///
public int[] Data { get; }
public string PrettyUTF8DecodedData { get; }
///
/// like: 0x11 22 33 44
///
public string PrettyHexStrData { get; }
}
#region device config
public class CardReaderModuleConfigV1
{
public byte PhysicalAddress { get; set; }
///
/// a meaningful name is required, and must be global unique
///
public string Name { get; set; }
public string Description { get; set; }
}
public class DeviceConfigV1
{
public List CardReaderModuleConfigs { get; set; }
}
#endregion
public GroupHandler(DeviceConfigV1 deviceConfig, IServiceProvider services)
{
this.services = services;
var loggerFactory = services.GetRequiredService();
this.logger = loggerFactory.CreateLogger("DynamicPrivate_ShengJu_CUT100_DES");
if (deviceConfig.CardReaderModuleConfigs.Select(mc => mc.PhysicalAddress).GroupBy(pa => pa).Any(g => g.Count() >= 2))
throw new ArgumentException("Duplicated PhysicalAddress for moduels were found, please make sure they're unique per comm channel");
if (deviceConfig.CardReaderModuleConfigs.Select(mc => mc.Name).GroupBy(pa => pa).Any(g => g.Count() >= 2))
throw new ArgumentException("Duplicated card module name were found, card module name is essential for tell the usage of it, please make sure they're unique");
this.deviceConfig = deviceConfig;
this.cardReaderModules = deviceConfig.CardReaderModuleConfigs.Select(mc => new CardReaderModule(mc.PhysicalAddress, this.logger)
{
Name = mc.Name,
Description = mc.Description,
ModuleState = CardReaderModule.CardReaderModuleStateEnum.Offline,
}).ToList();
}
public override void Init(IContext context)
{
base.Init(context);
this.context = context;
this.context.Communicator.OnConnected += (sender, e) => { };
this.context.Communicator.OnDisconnected += (sender, e) => { };
foreach (var m in this.cardReaderModules)
{
m.SetContext(context);
m.UnderlyingCommunicatorIdentity = this.context.Communicator.Identity;
};
//accuracy is 1000ms
this.singleModuleOfflineCheckTimer = new Timer(1000);
this.singleModuleOfflineCheckTimer.Elapsed += async (a, b) =>
{
var offlineModules = this.cardReaderModules.Where(b => DateTime.Now.Subtract(b.LastIncomingMessageReceivedTime ?? DateTime.MinValue).TotalMilliseconds >= singleModuleOfflineTimeThresholdByMs);
foreach (var om in offlineModules)
{
if (om.ModuleState == CardReaderModule.CardReaderModuleStateEnum.Offline) continue;
om.ModuleState = CardReaderModule.CardReaderModuleStateEnum.Offline;
this.OnModuleStateChange?.Invoke(this, new ModuleStateChangeEventArg(om));
var universalApiHub = this.services.GetRequiredService();
await universalApiHub.FireEvent(this.context.Processor, GenericAlarm.UniversalApiEventName,
new GenericAlarm[] {
new GenericAlarm()
{
Category = $"单块读卡器模块通讯断开",
Title = $"单块读卡器模块通讯断开",
Detail = $"单块读卡器模块通讯断开, Module: {om.Name??""} with address: {om.PhysicalAddress}",
Severity = GenericAlarmSeverity.Warning
} });
}
};
this.singleModuleOfflineCheckTimer.Start();
var activePollingOutgoing =
this.context.Outgoing as TimeWindowWithActivePollingOutgoing;
int prePolledIndex = 0;
activePollingOutgoing.PollingMsgProducer = () =>
{
var poll = new ActivateATypeCardRequest();
poll.ModulePhysicalAddress = this.deviceConfig.CardReaderModuleConfigs[prePolledIndex].PhysicalAddress;
prePolledIndex++;
if (prePolledIndex == this.deviceConfig.CardReaderModuleConfigs.Count)
prePolledIndex = 0;
return poll;
};
this.context.Incoming.LongTimeNoSeeMessageTimeout = 12000;
this.context.Incoming.OnLongTimeNoSeeMessage += async (a, b) =>
{
this.logger.LogInformation("ShengJu_CUT100_DES group is offline due to long time no see msg incoming");
foreach (var m in this.CardReaderModuels)
m.ModuleState = CardReaderModule.CardReaderModuleStateEnum.Offline;
this.OnModuleStateChange?.Invoke(this, new ModuleStateChangeEventArg(this.cardReaderModules));
var universalApiHub = this.services.GetRequiredService();
await universalApiHub?.FireEvent(this.context.Processor, GenericAlarm.UniversalApiEventName, new[] {
new GenericAlarm() {
Title = "同一通讯组中的多个(如有)读卡器模块均离线",
Detail=this.deviceConfig.CardReaderModuleConfigs.Select(mc=>$"Module: {mc.Name??""} with address: {mc.PhysicalAddress}").Aggregate("",(acc,n)=>acc+", "+n)+" are offline."
} });
};
#region Load keys
//this.blankCardDefaultRootKey = Enumerable.Repeat(0x00, 16).ToArray();
//this.newRootKey = Enumerable.Repeat(0x11, 16).ToArray();
//this.file1DefaultReadKey = Enumerable.Repeat(0x00, 16).ToArray();
//this.file1DefaultWriteKey = Enumerable.Repeat(0x00, 16).ToArray();
#endregion
}
public override async Task Process(IContext context)
{
if (!(this.cardReaderModules.FirstOrDefault(b => b.PhysicalAddress == context.Incoming.Message.ModulePhysicalAddress) is CardReaderModule operatingModule))
{
this.logger.LogInformation($"Could not find local defined module with physical address: {context.Incoming.Message.ModulePhysicalAddress}, please define it in device config, now will ignore this incoming device message");
return;
}
operatingModule.LastIncomingMessageReceivedTime = DateTime.Now;
if (operatingModule.ModuleState == CardReaderModule.CardReaderModuleStateEnum.Offline)
{
operatingModule.ModuleState = CardReaderModule.CardReaderModuleStateEnum.Online;
var readModuleInfoResponse = await this.context.Outgoing.WriteAsync(
new ReadModuleInfoRequest() { ModulePhysicalAddress = operatingModule.PhysicalAddress },
(_, testResponse) => testResponse.ModulePhysicalAddress == operatingModule.PhysicalAddress && (testResponse is GenericFailureResponse || testResponse is ReadModuleInfoResponse), 4000);
if (readModuleInfoResponse is ReadModuleInfoResponse successReadModuleInfoResponse)
{
operatingModule.HardwareFirmware = successReadModuleInfoResponse.ModelAndVersion;
this.logger.LogInformation($"Module (phyAdrs: {operatingModule.PhysicalAddress}, comm: {operatingModule.UnderlyingCommunicatorIdentity}) is online, read module Info: {successReadModuleInfoResponse.ModelAndVersion}");
}
else if (readModuleInfoResponse is GenericFailureResponse failedReadModuleInfoResponse)
{
this.logger.LogInformation($"Module (phyAdrs: {operatingModule.PhysicalAddress}, comm: {operatingModule.UnderlyingCommunicatorIdentity}) is online, but read module info failed due to response: {failedReadModuleInfoResponse.模块返回状态}");
}
else
{
this.logger.LogInformation($"Module (phyAdrs: {operatingModule.PhysicalAddress}, comm: {operatingModule.UnderlyingCommunicatorIdentity}) is online, but read module info timed out");
}
this.OnModuleStateChange?.Invoke(this, new ModuleStateChangeEventArg(operatingModule));
var universalApiHub = this.services.GetRequiredService();
await universalApiHub.FireEvent(this.context.Processor, GenericAlarm.UniversalApiEventName,
new GenericAlarm[] {
new GenericAlarm()
{
Category = $"单块读卡器模块上线",
Title = $"单块读卡器模块上线",
Detail = $"单块读卡器模块上线, Module: {operatingModule.Name??""} with address: {operatingModule.PhysicalAddress} on comm: {operatingModule.UnderlyingCommunicatorIdentity}",
Severity = GenericAlarmSeverity.Warning
} });
}
if (context.Incoming.Message is ActivateATypeCardResponse activateATypeCardResponse && activateATypeCardResponse.UID.Any())
{
this.logger.LogDebug($"Card with UID: 0x{activateATypeCardResponse.UID.ToHexLogString()} is read on module (phyAdrs: {operatingModule.PhysicalAddress}, comm: {operatingModule.UnderlyingCommunicatorIdentity})");//, will auto read card app dirs...");
this.OnCardTap?.Invoke(this, new CardTapEventArg(activateATypeCardResponse.UID, operatingModule));
var universalApiHub = this.services.GetRequiredService();
await universalApiHub?.FireEvent(this.context.Processor, OnCardTapEventName,
new
{
Module = this.cardReaderModules.FirstOrDefault(b => b.PhysicalAddress == context.Incoming.Message.ModulePhysicalAddress),
activateATypeCardResponse.UID
});
//var readAppDirsResponse = await this.context.Outgoing.WriteAsync(
// new ReadAppDirsRequest(this.newRootKey) { ModulePhysicalAddress = md.PhysicalAddress },
// (_, testResponse) => testResponse.ModulePhysicalAddress == md.PhysicalAddress && (testResponse is GenericFailureResponse || testResponse is ReadAppDirsResponse), 4000);
//if (readAppDirsResponse is ReadAppDirsResponse successReadAppDirsResponse)
//{
// this.logger.LogInformation($" Read Card AppDirs, count: {successReadAppDirsResponse.DirCount}, " +
// $"dirIds: {successReadAppDirsResponse.DirIds.Select(did => did.Select(i => i.ToString("X2")).Aggregate("0x", (acc, n) => acc + " " + n)).Aggregate((acc, n) => acc + ", " + n)} " +
// $"for module with physical address: {successReadAppDirsResponse.ModulePhysicalAddress}");
//}
//else if (readAppDirsResponse is GenericFailureResponse failedReadAppDirsResponse)
//{
// this.logger.LogInformation($" Read Card AppDirs failed with module code: {failedReadAppDirsResponse.模块返回状态}, cpu code: {failedReadAppDirsResponse.CpuCardState} for module with physical address: {failedReadAppDirsResponse.ModulePhysicalAddress}");
//}
//else
//{
// this.logger.LogInformation($" Read Card AppDirs timed out for module with physical address: {md.PhysicalAddress}");
//}
}
}
public async Task FormatCardByResetToNewRootKeyAndBuildDefaultFileStructures(string cardReaderModuleName, byte[] oldRootKeyBytes, byte[] newRootKeyBytes)
{
IEnumerable targetModules;
if (cardReaderModuleName != "*")
targetModules = this.cardReaderModules.Where(m => m.Name == cardReaderModuleName);
else
targetModules = this.cardReaderModules;
if (!targetModules.Any()) return new CardOperationResult[] { new CardOperationResult(404) { ModuleResultCode = $"找不到读卡器, 它的名称是: {cardReaderModuleName ?? ""}" } };
var batchFormatTasks = targetModules.Select(m => m.FormatCardByResetToNewRootKeyAndBuildDefaultFileStructures(m.PhysicalAddress, oldRootKeyBytes.Take(16).ToArray(), newRootKeyBytes.Take(16).ToArray()));
var results = await Task.WhenAll(batchFormatTasks);
return results;
}
public async Task WriteCard(string cardReaderModuleName, byte fileId, byte blockAddress, byte[] dataBytes, byte[] writeKeyBytes)
{
IEnumerable targetModules;
if (cardReaderModuleName != "*")
targetModules = this.cardReaderModules.Where(m => m.Name == cardReaderModuleName);
else
targetModules = this.cardReaderModules;
if (!targetModules.Any()) return new CardOperationResult[] { new CardOperationResult(404) { ModuleResultCode = $"找不到读卡器, 它的名称是: {cardReaderModuleName ?? ""}" } };
var batchWriteTasks = targetModules.Select(m => m.WriteCard(m.PhysicalAddress, fileId, blockAddress, dataBytes, writeKeyBytes.Take(16).ToArray()));
var results = await Task.WhenAll(batchWriteTasks);
return results;
}
public async Task ReadCard(string cardReaderModuleName, byte fileId, byte blockAddress, byte[] readKeyBytes)
{
IEnumerable targetModules;
if (cardReaderModuleName != "*")
targetModules = this.cardReaderModules.Where(m => m.Name == cardReaderModuleName);
else
targetModules = this.cardReaderModules;
if (!targetModules.Any()) return new CardOperationResult[] { new CardOperationResult(404) { ModuleResultCode = $"找不到读卡器, 它的名称是: {cardReaderModuleName ?? ""}" } };
var batchReadTasks = targetModules.Select(m => m.ReadCard(m.PhysicalAddress, fileId, blockAddress, readKeyBytes.Take(16).ToArray()));
var results = await Task.WhenAll(batchReadTasks);
return results;
}
public async Task ReadCardUID(string cardReaderModuleName)
{
IEnumerable targetModules;
if (cardReaderModuleName != "*")
targetModules = this.cardReaderModules.Where(m => m.Name == cardReaderModuleName);
else
targetModules = this.cardReaderModules;
if (!targetModules.Any()) return new CardOperationResult[] { new CardOperationResult(404) { ModuleResultCode = $"找不到读卡器, 它的名称是: {cardReaderModuleName ?? ""}" } };
var batchTasks = targetModules.Select(m => m.ReadCardUID(m.PhysicalAddress));
var results = await Task.WhenAll(batchTasks);
return results;
}
public async Task ModifyPredefinedFileKey(string cardReaderModuleName, PredefinedFileKeyTypeEnum fileKeyType, byte[] oldKeyBytes, byte[] newKeyBytes)
{
IEnumerable targetModules;
if (cardReaderModuleName != "*")
targetModules = this.cardReaderModules.Where(m => m.Name == cardReaderModuleName);
else
targetModules = this.cardReaderModules;
if (!targetModules.Any()) return new CardOperationResult[] { new CardOperationResult(404) { ModuleResultCode = $"找不到读卡器, 它的名称是: {cardReaderModuleName ?? ""}" } };
var batchTasks = targetModules.Select(m => m.ModifyPredefinedFileKey(m.PhysicalAddress, fileKeyType, oldKeyBytes.Take(16).ToArray(), newKeyBytes.Take(16).ToArray()));
var results = await Task.WhenAll(batchTasks);
return results;
}
}
}