/// <summary> /// Sends an array of `data` to a tag (with EPC starting with `tagId`) to a specific `address`. /// /// This transfer is done by sending BlockWrite commands individually, configuring the reader /// to resend on failure before sending the next BlockWrite command. /// </summary> public async Task <OperationResponse> SendData( ushort tagId, byte[] data, int bytesPerChunk, ushort address, TimeSpan?timeout = null, IProgressListener progress = null ) { if (data.Length % 2 != 0) { throw new Exception($"Data length must be a multiple of word size (16-bits) was: {data.Length}"); } this.PrepareReader(); var stopWatch = new Stopwatch(); stopWatch.Start(); var offset = address; foreach (var chunk in data.Split(bytesPerChunk)) { var message = $"Sending chunk ({chunk.Count()} bytes) to offset: {offset}"; Console.WriteLine(message); progress?.Update(tagId, 2.0 * (offset - address) / (double)data.Length, message); Profiler.StartScope($"SendDataBlock"); var bytes = chunk.ToArray(); var sendResponse = await this.SendDataBlock(tagId, offset, bytes, timeout); Profiler.EndScope(); if (sendResponse.status != SecuCode.StatusCode.Success) { return(sendResponse); } offset += (ushort)(bytes.Length / 2); } progress?.Update(tagId, 1.0, $"Wrote: {data.Length / 2} words"); stopWatch.Stop(); Console.WriteLine($"Wrote: {data.Length / 2} words in {stopWatch.Elapsed.TotalSeconds} seconds: {data.ToByteString()}"); progress?.Info($"Wrote: {data.Length / 2} words in {stopWatch.Elapsed.TotalSeconds} seconds"); return(new OperationResponse { status = SecuCode.StatusCode.Success }); }