public override async Task SendRequest(ReqType reqType, uint seq, byte[] plBuff, int offset, int len) { try { if (len > config.CMD_MAX_PLSZ) { throw new ArgumentException("len > CMD_MAX_PLSZ", nameof(len)); } //write sequence number int pos = config.CMD_HDR_SIZE; int seqLen = 0; if (seq > 0) { if (config.CMD_SEQ_SIZE == 4) { sendBuff[pos++] = (byte)(seq & 0xFF); sendBuff[pos++] = (byte)((seq >> 8) & 0xFF); sendBuff[pos++] = (byte)((seq >> 16) & 0xFF); sendBuff[pos++] = (byte)((seq >> 24) & 0xFF); } else { throw new Exception("config.CMD_SEQ_SIZE != 4"); } seqLen = config.CMD_SEQ_SIZE; } else { len = 0; } //write payload Buffer.BlockCopy(plBuff, offset, sendBuff, pos, len); pos += len; sendBuff[0] = (byte)((int)reqType | (len + seqLen + config.CMD_CRC_SIZE)); //write crc int testLen = len + seqLen + config.CMD_HDR_SIZE; sendBuff[testLen] = CRC8.Calculate(sendBuff, 0, testLen); //send data using (var cts = new CancellationTokenSource()) { cts.CancelAfter(UseCommitTimeout?config.COMMIT_TIMEOUT:config.CMD_TIMEOUT); await link.WriteAsync(sendBuff, 0, testLen + config.CMD_CRC_SIZE, cts.Token); } } catch (TaskCanceledException ex) { throw new TimeoutException("SendRequest was timed out", ex); } }
public override async Task <Answer> ReceiveAnswer() { try { int bRead = 0; using (var cts = new CancellationTokenSource()) { cts.CancelAfter(UseCommitTimeout?config.COMMIT_TIMEOUT:config.CMD_TIMEOUT); bRead = await link.ReadAsync(recvBuff, 0, 1, cts.Token); if (bRead != 1) { throw new NotSupportedException("Stream has reached EOF and cannot receive data"); } } int remSz = recvBuff[0] & config.CMD_SIZE_MASK; if (remSz < config.CMD_MIN_REMSZ || remSz > config.CMD_MAX_REMSZ) { return(Answer.Invalid); } if (!Enum.TryParse <AnsType>((recvBuff[0] & config.ANS_ALL_MASK).ToString(), out AnsType ans)) { return(Answer.Invalid); } //calculate plSize var plSize = remSz - config.CMD_CRC_SIZE; switch (ans) { case AnsType.Ok: case AnsType.Pong: if (plSize != config.CMD_SEQ_SIZE) { return(Answer.Invalid); } break; case AnsType.DataMarker: if (plSize != config.CMD_SEQ_SIZE + 1) { return(Answer.Invalid); } break; case AnsType.Data: if (plSize < config.CMD_SEQ_SIZE) { return(Answer.Invalid); } break; case AnsType.Resync: break; default: return(Answer.Invalid); } var rem = remSz; using (var cts = new CancellationTokenSource()) { cts.CancelAfter(UseCommitTimeout?config.COMMIT_TIMEOUT:config.CMD_TIMEOUT); while (rem > 0) { rem -= await link.ReadAsync(recvBuff, config.CMD_HDR_SIZE + (remSz - rem), rem, cts.Token); } } //verify CRC var testSz = config.CMD_HDR_SIZE + remSz - 1; if (recvBuff[testSz] != CRC8.Calculate(recvBuff, 0, testSz)) { return(Answer.Invalid); } //decode sequence number uint seq = 0; var seqPos = config.CMD_HDR_SIZE; int dataSize = 0; if (plSize >= config.CMD_SEQ_SIZE) { if (config.CMD_SEQ_SIZE == 4) { seq = unchecked ((uint)(recvBuff[seqPos] | recvBuff[seqPos + 1] << 8 | recvBuff[seqPos + 2] << 16 | recvBuff[seqPos + 3] << 24)); } else { throw new Exception("config.CMD_SEQ_SIZE != 4"); } dataSize = plSize - config.CMD_SEQ_SIZE; } var dataPos = (dataSize > 0) ? config.CMD_HDR_SIZE + config.CMD_SEQ_SIZE : 0; return(new Answer(ans, seq, recvBuff, dataPos, dataSize)); } catch (Exception ex) when(ex is TaskCanceledException || ex is TimeoutException) { throw new TimeoutException("ReceiveAnswer was timed out", ex); } }