I have a sample pascal program presented in the technical reference book of the S350 / 360 coin counter machine, which provides communication between the machine and the computer using an RS232C cable. I came up with the following equivalent C # code, and for some reason, only procedures that require only writing data to the serial port are executed and work successfully. I can only write data to the port, but I can not read data from it. I checked this using Serial Sniffer, and it turned out that he only sniffs the data written to the port using the C # program, but cannot read the data back. Could you guys help me with what is happening here?
First of all, this is the original Pascal code of the sample program.
uses crt;
const
{ COM1: RS232 port address }
RXTX = $3F8; { $2F8 if COM2: is used }
ACK = 6;
NAK = 21;
ESC = 27;
var
dummy,
checkSum : integer;
key : char;
protocol : integer;
procedure InitComm;
{ Set baudrate to 9600, 8 bits, no parity, 1 stop bit }
var i : integer;
begin
i := 1843200 div 9600 div 16;
port[RXTX + 3] := $80;
port[RXTX + 1] := hi(i);
port[RXTX]:= lo(i);
port[RXTX + 3] := 3;
port[RXTX + 4] := $A;
while odd(port[RXTX + 5]) do
begin
dummy := port[RXTX];
delay(10);
end;
end; { InitComm }
procedure Tx(data : integer);
{ Transmit a character on serial channel }
begin
while port[RXTX + 5] and $20 = 0 do;
port[RXTX] := data and $FF;
end; { Tx }
function RxWait : integer;
{ Waits for a character from serial channel }
begin
while not odd(port[RXTX + 5]) do;
RxWait := port[RXTX];
end; { RxWait }
procedure Tx2(data : integer);
{ Transmit a char on serial channel + Calculate check sum }
begin
Tx(data);
checkSum := (checkSum + data) and $FF;
end; { Tx2 }
procedure TxCommand(c1, c2 : char;
sendCheckSum : boolean);
{ Transmit command (no data) on serial channel }
begin
Tx(ESC);
checkSum := 0;
Tx2(ord(c1));
Tx2(ord(c2));
if sendCheckSum then
begin
Tx2(checkSum);
dummy := RxWait;
end;
end; { TxCommand }
function ReadNumber(n : integer) : real;
{ Read n bytes from serial channel }
var
number: real;
i : integer;
begin
number := 0;
checkSum := 0;
for i := 1 to n do
number := number * 256 + RxWait;
dummy := RxWait;
ReadNumber := number;
end; { ReadNumber }
procedure Revisions;
var
tmp : integer;
sw,
prot : real;
begin
TxCommand('P', 'R', FALSE);
checkSum := 0;
tmp := RxWait;
sw := tmp + RxWait / 100.0;
protocol := RxWait;
prot := protocol + RxWait / 100.0;
dummy := RxWait;
tmp := RxWait;
writeln('Software revision: ', sw:4:2);
writeln('Protocol revision: ', prot:4:2);
end; { Revisions }
procedure ReadCountReg;
begin
TxCommand('R', 'C', FALSE);
writeln(ReadNumber(4):11:0, ' coins counted.');
dummy := RxWait;
end; { ReadCountReg }
procedure ReadAccReg;
begin
TxCommand('R', 'A', FALSE);
writeln(ReadNumber(4):11:0, ' coins in accumulator.');
dummy := RxWait;
end; { ReadAccReg }
procedure Setbatch(limit : longint);
begin
TxCommand('W', 'L', FALSE);
case protocol of
1 : begin
Tx2(limit div 256);
Tx2(limit mod 256);
end;
2 : begin
Tx2( limit div 16777216);
Tx2((limit div 65536) mod 256);
Tx2((limit div 256) mod 256);
Tx2( limit mod 256);
end;
end; { case protocol }
Tx2(checkSum);
dummy := RxWait;
end; { Setbatch }
In the protocol descriptions, two logical operators are used, + for arithmetic addition and ^ for logical I. All messages have the following structure:
Computer SC 350/360
βββββββ> ESC (message start)
βββββββ> Command
<ββββββ> Data (direction depends on command)
<ββββββ> Check sum (direction depends on command)
<βββββββ Receipt:
- ACK (if check sum is correct) or
- NAK (if check sum is incorrect)
If the data is a binary number, the most significant byte (character) is sent first. If the data is a text string, the first character of the string is sent first. A text string always ends with a NULL character.
:
,
(ESC), . -
sum ^ 255.
- ,
250 ,
:
; "TxCommand" ( "M", "1", "" ); ; pascal #.Net , . , "ReadCountReg" , "ReadCountReg" "Setbatch".
#:
public class CoinCounter : IDisposable
{
private const int RXTX = 0x3F8;
private const int ACK = 6;
private const int NAK = 21;
private const int ESC = 27;
private int dummy, checkSum;
private char key;
private int protocol;
public SerialPort port;
private bool _disposed = false;
public CoinCounter()
{
port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
port.Handshake = Handshake.None;
port.Open();
port.DtrEnable = true;
port.RtsEnable = true;
}
public void ClosePort()
{
if (port.IsOpen)
port.Close();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
_disposed = true;
}
}
private void DisposeManagedResources()
{
port.Dispose();
}
private void DisposeUnmanagedResources() { }
~CoinCounter()
{
Dispose(false);
}
public void Tx(int data)
{
port.Write(new byte[] { (byte)(data & 0xFF) }, 0, 1);
}
public int RxWait()
{
int readByte = 0;
CommTimer timer = new CommTimer();
timer.Start(250);
while ((port.BytesToRead == 0) && (timer.timedout == false))
{
}
if (port.BytesToRead > 0)
readByte = port.ReadByte();
return readByte;
}
public void Tx2(int data)
{
Tx(data);
checkSum = (checkSum + data) & 0xFF;
}
public void TxCommand(char c1, char c2, bool sendCheckSum)
{
Tx(ESC);
checkSum = 0;
Tx2((int)c1);
Tx2((int)c2);
if (sendCheckSum)
{
Tx2(checkSum);
dummy = RxWait();
}
}
public double ReadNumber(int n)
{
double number;
int i;
number = checkSum = 0;
for (i = 0; i < n; i++)
number = number * 256 + RxWait();
dummy = RxWait();
return number;
}
public void Revisions(out double softVersion, out double protocolVersion)
{
int tmp;
TxCommand('P', 'R', false);
checkSum = 0;
tmp = RxWait();
softVersion = tmp + RxWait() / 100.0;
protocol = RxWait();
protocolVersion = protocol + RxWait() / 100.0;
dummy = RxWait();
tmp = RxWait();
}
public double ReadCountReg()
{
TxCommand('R', 'C', false);
double coinsCounted = ReadNumber(4);
dummy = RxWait();
return coinsCounted;
}
public double ReadAccReg()
{
TxCommand('R', 'A', false);
double coinsInAccumulator = ReadNumber(4);
dummy = RxWait();
return coinsInAccumulator;
}
public void SetBatch(long limit)
{
TxCommand('W', 'L', false);
switch (protocol)
{
case 1:
Tx2((int)(limit / 256));
break;
case 2:
Tx2((int)(limit / 16777216));
Tx2((int)(limit / 65536) % 256);
Tx2((int)(limit / 256) % 256);
Tx2((int)(limit % 256));
break;
}
Tx2(checkSum);
dummy = RxWait();
}
public class CommTimer
{
public System.Timers.Timer tmrComm = new System.Timers.Timer();
public bool timedout = false;
public CommTimer()
{
timedout = false;
tmrComm.AutoReset = false;
tmrComm.Enabled = false;
tmrComm.Interval = 1000;
tmrComm.Elapsed += new ElapsedEventHandler(OnTimedCommEvent);
}
public void OnTimedCommEvent(object source, ElapsedEventArgs e)
{
timedout = true;
tmrComm.Stop();
}
public void Start(double timeoutperiod)
{
tmrComm.Interval = timeoutperiod;
tmrComm.Stop();
timedout = false;
tmrComm.Start();
}
}
}
, :
1. .
2. .
, , , "ReadCountReg" . :
Computer SC 350/360
βββββββ> ESC
βββββββ> "R"
βββββββ> "C"
<βββββββ CountRegister (CR)
<βββββββ (CR ^ FF00,000016 + CR ^ FF,000016 + CR ^ FF0016 +CR ^ FF16) ^ FF16
<βββββββ ACK
, , , .