Send following byte received via SerialPort (USB VCP) without delay - c#

I am trying to test a flash memory chip on an electronic device having USB comms. Using SerialPort (USB VCP).
I am sitting in a for loop scanning through the memory addresses in sequence with a small delay following each read. However I want to get rid of the delay and have this run as follows:
C# App sends byte command to i.e. read address 0 and return 32 bytes (address 0 to 31)
When C# app receives the 32 bytes then immediately send request for address 31 etc
repeat...
So how do I do it in this fast manner and not having to have a delay giving the serial port time to receive the bytes but rather have the next request send immediately following receipt of previous request results ?
Update #2
async private void buttonMemoryTest_Click(object sender, EventArgs e)
{
byte[] bytes = new byte[6];
memoryAddress = 0x00000000;
bytes[0] = 0x90;
bytes[1] = 0x01;
try
{
sendStopWatch.Stop();
sendStopWatch.Reset();
sendStopWatch.Start();
//2097152
for (UInt32 counter = 0; counter < 100; counter++)
{
bytes[2] = (byte)(memoryAddress >> 24);
bytes[3] = (byte)(memoryAddress >> 16);
bytes[4] = (byte)(memoryAddress >> 8);
bytes[5] = (byte)(memoryAddress);
serialPortComms.Write(bytes, 0, 6);
await Task.Delay(1);
memoryAddress += 32;
time = sendStopWatch.Elapsed;
textBoxMemoryTestTime.Text = Math.Round(time.TotalSeconds, 2) + "s";
textBoxPageCounter.Text = Convert.ToString(counter);
}
}
catch (InvalidOperationException)
{
}
catch (TimeoutException)
{
}
}
void serialPortComms_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = serialPortComms.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = serialPortComms.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string newStr = "";
//See if there was data send back
try
{
if (selfTestClicked == 1)
{
if (selfTestResponseASCII == 1)
{
newStr = Encoding.ASCII.GetString(data, 0, data.Length);
}
else
{
newStr = BitConverter.ToString(data).Replace("-", " ");
}
textBoxReceiveByte_AppendText(newStr);
}
else
{
//
if (checkBoxASCII.Checked)
{
//newStr = Encoding.UTF8.GetString(data, 0, data.Length);
newStr = Encoding.ASCII.GetString(data, 0, data.Length);
}
else
{
newStr = BitConverter.ToString(data).Replace("-", " ");
}
if (checkBoxCR_LF.Checked)
{
newStr += "\r\n";
}
textBoxReceiveByte_AppendText(newStr);
//textBoxReceiveByte_ChangeText(newStr);
//processRxData(data);
}
}
catch (IndexOutOfRangeException)
{
}
}

Related

Modbus TCP Communication C#

I am looking for a little help.
I have a program to communicate with a controller through Modbus TCP.
The only problem is I cannot extend the Nop from 125 to 400 because I got Illegal Data Address error message.
Could you please help me with this?
try
{
byte slaveid = 1;
byte function = 4;
ushort id = function;
ushort startAddress = 0;
uint NoP = 125;
byte[] frame = ReadInputRegistersMsg(id, slaveid, startAddress, function, NoP);
this.Write(frame); //data send to controller
Thread.Sleep(100);
byte[] buffReceiver = this.Read(); //data recieving from controller
int SizeByte = buffReceiver[8]; // Data what I got from the controller
UInt16[] temp = null;
if (function != buffReceiver[7])
{
byte[] byteMsg = new byte[9];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg);
byte[] errorbytes = new byte[3];
Array.Copy(buffReceiver, 6, errorbytes, 0, errorbytes.Length);
this.CheckValidate(errorbytes); // check the answer -> error message
}
else
{
byte[] byteMsg = new byte[9 + SizeByte];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg); // Show received messages in windows form app
Array.Copy(buffReceiver, 9, data, 0, data.Length);
temp = Word.ConvertByteArrayToWordArray(data); // Convert Byte[]-> Word[]
}
// Result
if (temp == null) return;
string result = string.Empty;
//foreach (var item in temp) // show all the data
for(int i=0;i<100;i++) // show the first 100 data
{
//result += string.Format("{0} ", item);
result += temp[i];
}
textBox3.Text = result; // insert the result into the textbox (windows form app)
}
catch
{
}
The ReadInputRegister Message is the following:
private byte[] ReadInputRegistersMsg(ushort id, byte slaveAddress, ushort startAddress, byte function, uint NoP)
{
byte[] frame = new byte[12];
frame[0] = (byte)(id >> 8); // Transaction Identifier High
frame[1] = (byte)id; // Transaction Identifier Low
frame[2] = 0; // Protocol Identifier High
frame[3] = 0; // Protocol Identifier Low
frame[4] = 0; // Message Length High
frame[5] = 6; // Message Length Low(6 bytes to follow)
frame[6] = slaveAddress; // Slave address(Unit Identifier)
frame[7] = function; // Function
frame[8] = (byte)(startAddress >> 8); // Starting Address High
frame[9] = (byte)startAddress; // Starting Address Low
frame[10] = (byte)(NoP >> 8); // Quantity of Registers High
frame[11] = (byte)NoP; // Quantity of Registers Low
return frame;
}
The hard limit for modbus is 125 NoP

Why files are not transfered (saved?) properly between client in C# and server in C via tcp?

I've set up TCP client in C# and server in C.
When I want to transfer file, some packets are lost and file is not saved properly.
I've compared PDF file I tried to transfer and half of packets were not saved, so I couldn't open it on another computer.
client code:
public void SendFile(string file, string destPath = "C:\\")
{
int bufferSize = 1024;
byte[] filebuff = new byte[bufferSize];
string fileName = destPath + file;
//send to TcpServer request to send file
stream.Write(textToBytes("RECEIVEFILE"), 0, 11);
try
{
FileStream streamFile = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader binReader = new BinaryReader(streamFile);
//send file name to TcpServer
stream.Write(textToBytes(file), 0, file.Length);
//get file size
long filesize = streamFile.Length;
//send file size to TcpServer
//sendData(stream, BitConverter.GetBytes(filesize));
//if file doesn't exist
if (file == null)
{
Console.WriteLine("Error.");
}
//if file is empty
if (filesize == 0)
{
Console.WriteLine("File size: 0");
return;
}
int totalLength = Convert.ToInt32(filesize);
Console.WriteLine("Totallength: " + totalLength);
long numberOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(streamFile.Length) / bufferSize));
int currentPacketLength;
for (int i = 0; i < numberOfPackets; i++)
{
if (filesize > bufferSize)
{
currentPacketLength = bufferSize;
totalLength = totalLength - currentPacketLength;
}
else
currentPacketLength = totalLength;
filebuff = new byte[currentPacketLength];
//streamFile.Read(filebuff, 0, currentPacketLength);
binReader.Read(filebuff, 0, currentPacketLength);
stream.Write(filebuff, 0, filebuff.Length);
}
streamFile.Close();
}
catch
{
Console.WriteLine("There's no file...");
}
}
public void DownloadFile(string fileName)
{
byte[] recBuffer = new byte[1024];
byte[] fileNameBytes;
long received = 0;
long receivedAll = 0;
byte[] fileData = new byte[1024];
stream.Write(textToBytes("SENDFILE"), 0, 8);
fileNameBytes = Encoding.UTF8.GetBytes(fileName);
stream.Write(fileNameBytes, 0, fileNameBytes.Length);
byte[] fileSizeBytes = new byte[4];
stream.Read(fileSizeBytes, 0, fileSizeBytes.Length);
int bytes = BitConverter.ToInt32(fileSizeBytes, 0);
Console.WriteLine("I'm downloading file...");
while (receivedAll < bytes)
{
received = stream.Read(fileData, 0, fileData.Length);
if (received < 0)
{
Console.WriteLine("Error");
break;
}
BinaryWriter bWrite = new BinaryWriter(File.Open("C:\\" + fileName, FileMode.Append));
bWrite.Write(fileData);
bWrite.Close();
receivedAll += received;
}
if(receivedAll == bytes)
{
Console.WriteLine("File downloaded successfuly.");
}
}
server code:
void ReceiveFile(int client_socket)
{
const int buffsize = 1024;
char buff[buffsize];
long filesize, received = 0, receivedall;
char filenamechar[512];
std::string filename, fullFilename;
memset(filenamechar, 0, 512);
/*
if(recv(client_socket, filenamechar, 512, 0) != 512)
{
printf("Error - filename.\n");
return;
}
fullFilename = "/Users/xxx/" + std::string(filenamechar);
*
if(recv(client_socket, &filesize, sizeof(long), 0) != sizeof(long))
{
printf("Child process: error.\n");
return;
}*/
filesize = 331776;
std::fstream fileFromClient;
fullFilename = "/Users/xxx/sockets.pdf";
fileFromClient.open(fullFilename, std::ios::binary | std::ios::out);
receivedall = 0;
while (receivedall < filesize)
{
memset(buff, 0, 1024);
received = recv(client_socket, buff, 1024, 0);
if(received <= 0)
{
std::cout << "error" << std::endl;
break;
}
receivedall += received;
fileFromClient << buff;
fputs(buff, stdout);
}
fileFromClient.close();
std::cout << "\nreceivedall: " << receivedall << std::endl;
std::cout << "filesize: " << filesize << std::endl;
if(receivedall != filesize)
printf("Error\n");
else
printf("File saved successfuly\n");
}
void SendFile(int client_socket)
{
char path[512];
char fileName[512];
char fullFileName[512];
long fileLen, sent, sentAll, read;
struct stat fileinfo;
FILE* file;
unsigned char bufor[1024];
memset(path, 0, 512);
strcpy(path, "/Users/xxxx/");
if (recv(client_socket, fileName, 512, 0) <= 0)
{
printf("Child process: error\n");
return;
}
strcpy(fullFileName, strcat(path, fileName));
printf("Child process: client wants file: %s\n", fullFileName);
if (stat(fullFileName, &fileinfo) < 0)
{
printf("Child process: can't get file info\n");
return;
}
if (fileinfo.st_size == 0)
{
printf("Child process: file size: 0\n");
return;
}
fileLen = fileinfo.st_size;
if (send(client_socket, &fileLen, sizeof(long), 0) != sizeof(long))
{
printf("Child process: error\n");
return;
}
sentAll = 0;
file = fopen(fullFileName, "rb");
if (file == NULL)
{
printf("Error\n");
return;
}
while (sentAll < fileLen)
{
read = fread(bufor, 1, 1024, file);
sent = send(client_socket, bufor, read, 0);
if (read != sent)
break;
sentAll += sent;
printf("Child process: sent %ld bytes\n", sentAll);
}
if (sentAll == fileLen)
printf("Child process: file sent successfuly\n");
else
printf("Child process: error\n");
fclose(file);
return;
}
How to guarantee that each packet will be saved properly?
One problem is with this line:
fileFromClient << buff;
This will write out the contents of buff until a zero byte is found. Since your are transferring a binary file, you can expect these bytes to be frequent. The rest of the received packet will not be written.
Rather than using the << operator, you should use
fileFromClient.write(buff, received);

How to get progress bar to update DURING execution of an app running in a backgroundworker

I have found a lot of information on the Backgroundworker updating a progress bar and I have written numerous versions of this code. But none of the versions has updated the progress bar DURING the time my upgrade application is running. Here is one of the DoWork handler versions that I have used:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
updater.updater();
int percents = 0;
// Progress bar
int total = 57;
for (int i = 0; i <= total; i++)
{
System.Threading.Thread.Sleep(100);
percents = (i * 100) / total;
bw.ReportProgress(percents, i);
}
If I run updater (my app) before ReportProgress (as shown), updater runs completely and then the progress bar updates from 0 to 100%. If I place updater after the ReportProgress call, the progress bar runs and THEN updater runs. If I replace the Thread.Sleep line with updater, it runs at the 0% interval of the progress bar.
Is it actually possible to have the progress bar update while a long-running app is executing in the backgroundworker? That is what the MSDN page for backgroundworker claims, but what they actually show is it running a series of short processes (Sleep) and not one long process. Most of the examples I have found on line use this format, making no reference to a longer running process that is not segmented into the ReportProgress section.
I would love to know if the backgroundworker is capable of doing this or is this a job for some other threading-type solution.
Thanks!
After seeing Tim's answer below, I attempted to implement an EventArg and Handler for the progress bar progress.
public class FWupdater
{
public string comPort;
public int percentage;
public State state;
public string path;
public const int ACK = 0x79;
public const int NACK = 0x1F;
public class PBProgressEventArgs : EventArgs
{
private int prog;
public int progress
{
set { prog = value; }
get { return this.prog; }
}
}
public class PBProgress
{
public event PBProgressHandler Progress;
public delegate void PBProgressHandler(PBProgress p, PBProgressEventArgs e);
public void Start()
{
if (Progress != null)
{
PBProgressEventArgs progressUpdate = new PBProgressEventArgs();
progressUpdate.progress = 0;
Progress(this, progressUpdate);
}
}
}
And then create an instance in the main program so that the backgroundworker could see it.
PBProgress progUpdater = new PBProgress();
But I can't get the backgroundworker to see the progress percentage from the DoWork method.
Including the updater code.
public void updater()
{
// Create a new SerialPort object.
SerialPort _serialPort;
_serialPort = new SerialPort(comPort, 115200, Parity.Even, 8, StopBits.One);
// for state machine
bool _continue = true;
try
{
_serialPort.Open();
if (_serialPort.IsOpen)
{
Console.WriteLine("");
Console.WriteLine("Serial Port is Open");
Console.WriteLine("");
}
else
{
MessageBox.Show("Serial Port is not open. Choose another port.");
}
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
catch (ArgumentOutOfRangeException ex)
{
MessageBox.Show(ex.Message);
}
catch (ArgumentException ex)
{
MessageBox.Show(ex.Message);
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
// Move through states until upgrade is complete
while (_continue)
{
switch (state)
{
case State.NORMAL:
// Beginning state for instance of upgrader
break;
case State.WAITING_TO_UPGRADE:
SetUpComm( _serialPort);
state = State.ERASING_FIRMWARE;
break;
case State.ERASING_FIRMWARE:
EraseFlashMemory(_serialPort);
state = State.UPGRADING_FIRMWARE;
break;
case State.UPGRADING_FIRMWARE:
WriteNewAppToFlash(_serialPort);
state = State.UPGRADE_COMPLETE;
break;
case State.UPGRADE_COMPLETE:
JumpToNewApp(_serialPort);
_continue = false;
_serialPort.Close();
break;
default:
break;
} // end SWITCH (state)
} // end WHILE (_continue) - main loop
} // end public void updater()
//
// ---- METHODS -------------------
public void SetUpComm(SerialPort _serialPort)
{
int byte_read = 0x00;
var sevenF = new byte[] { 0x7F };
// Send 0x55 and 0xAA to peripheral input to execute SwitchToBootloader()
var byte1 = new byte[] { 0x55 };
var byte2 = new byte[] { 0xAA };
_serialPort.Write(byte1, 0, 1);
_serialPort.Write(byte2, 0, 1);
// If in bootloader mode, where the boot pins on the board are set,
// the device will be looking to receive 0x7F to establish contact with the host.
// In this case, the bytes to trigger boot load from inside the firmware will be
// ignored and the following 0x7F will serve to trigger comm set-up .
// Wait for acknowledge byte from USART
while (byte_read != ACK)
{
// Write "7F" to start communicating with Bootloader
_serialPort.Write(sevenF, 0, 1);
Thread.Sleep(100);
// read ACK byte after parameters set and bootloader running
byte_read = _serialPort.ReadByte();
}
}
public void EraseFlashMemory(SerialPort _serialPort)
{
int byte_read = 0;
var ff = new byte[] { 0xFF };
Console.WriteLine("Erasing flash memory...");
Console.WriteLine("");
/* NOTE: the ERASE COMMAND is not supported by this device, use EXTENDED ERASE */
// Send 0x44 and 0xBB (extended erase memory command), see AN3155
var exeraseMem = new byte[] { 0x44 };
var bb = new byte[] { 0xBB };
_serialPort.Write(exeraseMem, 0, 1);
_serialPort.Write(bb, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for ERASE MEMORY start");
//Console.WriteLine("");
}
//// end sending EXTENDED ERASE COMMAND
//---------------------------------------
// Global erase (send 0xFFFF, and 0x00)
//---------------------------------------
//var globalErase = new byte[] { 0x00 };
//_serialPort.Write(ff, 0, 1);
//_serialPort.Write(ff, 0, 1);
//_serialPort.Write(globalErase, 0, 1);
// Erase all but the first page (16k)
// send number of pages to erase, msb first [11 pages, leaving page 0]
// *ALERT* send 10 pages (N) to erase 11, for some reason it erases N + 1, whatever...
var num_pages_msb = new byte[] { 0x00 };
var num_pages_lsb = new byte[] { 0x0A };
_serialPort.Write(num_pages_msb, 0, 1);
_serialPort.Write(num_pages_lsb, 0, 1);
// send page numbers, 2 bytes each, msb first
// PAGE 1
var page01_msb = new byte[] { 0x00 };
var page01_lsb = new byte[] { 0x01 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page01_lsb, 0, 1); // 1
// PAGE 2
var page02_lsb = new byte[] { 0x02 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page02_lsb, 0, 1); // 2
// PAGE 3
var page03_lsb = new byte[] { 0x03 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page03_lsb, 0, 1); // 3
// PAGE 4
var page04_lsb = new byte[] { 0x04 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page04_lsb, 0, 1); // 4
// PAGE 5
var page05_lsb = new byte[] { 0x05 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page05_lsb, 0, 1); // 5
// PAGE 6
var page06_lsb = new byte[] { 0x06 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page06_lsb, 0, 1); // 6
// PAGE 7
var page07_lsb = new byte[] { 0x07 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page07_lsb, 0, 1); // 7
// PAGE 8
var page08_lsb = new byte[] { 0x08 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page08_lsb, 0, 1); // 8
// PAGE 9
var page09_lsb = new byte[] { 0x09 };
_serialPort.Write(page01_msb, 0, 1); // 0
_serialPort.Write(page09_lsb, 0, 1); // 9
// PAGE 10
var page10_msb = new byte[] { 0x01 }; // 1
var page10_lsb = new byte[] { 0x00 }; // 0
_serialPort.Write(page10_msb, 0, 1);
_serialPort.Write(page10_lsb, 0, 1);
// PAGE 11
_serialPort.Write(page10_msb, 0, 1); // 1
_serialPort.Write(page01_lsb, 0, 1); // 1
// checksum = A
_serialPort.Write(num_pages_lsb, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
bw.ReportProgress(20);
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for ERASE MEMORY completed");
//Console.WriteLine("");
}
}
// -- end EXTENDED ERASE MEMORY --------------------------------------------------
public void WriteNewAppToFlash(SerialPort _serialPort)
{
// For testing
int blockCount = 0;
int byte_read = 0;
long checksum = 0;
var ff = new byte[] { 0xFF };
// ------------------------------------------------------------------------------
// -------- WRITE MEMORY --------------------------------------------------------
// ------------------------------------------------------------------------------
// for Address
int baseAddress = 0x08008000;
int offset = 0;
// for string from HEX file
string line;
string[] lineBuffer = new string[16];
int lineCount = 0;
int length;
int type;
int hexChecksum = 0;
bool sendAddress = true;
int counter = 0; // Counting the number of lines in the file
int byteCounter = 0; // Counting nmumber of bytes in the current block
// Create byte array with 256 bytes
byte[] buffer256 = new byte[256];
// Read the file and process one line at a time
System.IO.StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
// Store line into a line buffer. This will allow reprocessing of all lines
// in a block if there is an error sending a block of 256 bytes below
if( line[8] == '0')
{
lineBuffer[lineCount++] = line;
}
// Send WRITE COMMAND and the next address every 256 bytes
if (sendAddress == true)
{
/*
-------------------------------------------------------------------------------------------------------
SEND WRITE COMMAND
-----------------------------------------------------------------------------------------------------*/
do
{
// Send WRITE command - 0x31 and 0xCE
var writeMem = new byte[] { 0x31 };
var ce = new byte[] { 0xCE };
_serialPort.Write(writeMem, 0, 1);
_serialPort.Write(ce, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
} while (byte_read != ACK);
// -- end SEND 0x31 and 0xCE and wait for ACK -----------------------------------------
/*
-------------------------------------------------------------------------------------------------------
SEND CURRENT ADDRESS AND CHECKSUM TO FLASH MEMORY
-----------------------------------------------------------------------------------------------------*/
Byte[] currentAddr = BitConverter.GetBytes(baseAddress + offset);
// Increment offset by 0x100 (256 bytes)
offset = offset + 0x00000100;
// Reset Checksum and XOR address
checksum = 0;
foreach (byte b in currentAddr)
{
checksum ^= b;
}
Byte[] cksum = BitConverter.GetBytes(checksum);
// Send address, MSB first, LSB last
_serialPort.Write(currentAddr, 3, 1);
_serialPort.Write(currentAddr, 2, 1);
_serialPort.Write(currentAddr, 1, 1);
_serialPort.Write(currentAddr, 0, 1);
// Send checksum of address bytes
_serialPort.Write(cksum, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
if (byte_read == NACK)
{
// Handle
}
// -- end addr or increment ---------------------------------------------------------
sendAddress = false;
// Send number of bytes, always 256, the last group will be padded with 0xFF
_serialPort.Write(ff, 0, 1);
} // end IF for WRITE COMMAND and ADDRESS
/* FIRST CHARACTER in HEX FILE
The colon indicates the start of a "record"
Remove colon from beginning of string */
line = line.Substring(1, line.Length - 1);
// Create byte array from string for whole line from HEX file
var bytes = GetBytesFromByteString(line).ToArray();
// Identify RECORD TYPE of HEX line [byte 4]
type = bytes[3];
/* Next TWO CHARACTERS 00-data 03-start segment address
in HEX FILE are 01-EOF 04-extended linear address
the record type: 02-extended segment address 05-start linear address */
// BLOCK WRITE TO MEMORY
if (type == 0)
{
// Length of line is stored at byte 0, in this case 0x10, or 16 bytes of data
length = bytes[0];
// Add data from current line to buffer of 256 bytes
for (int i = 0; i < length; i++)
{
// Stuff all bytes from line into buffer of 256 bytes
buffer256[byteCounter++] = bytes[4 + i];
// Add byte to checksum
hexChecksum ^= bytes[4 + i];
}
// When buffer is full, send block of 256 bytes and checksum, reset variables for next block
if (byteCounter >= 255)
{
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
// For testing
// Console.WriteLine("block number [{0}]", ++blockCount);
//send checksum
_serialPort.Write(csByte_arr, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
while (byte_read != ACK)
{
Array.Clear(buffer256, 0, buffer256.Length);
hexChecksum = 0;
lineCount = 0;
// reprocess the previous 16 lines stored in the line buffer
for ( int j = 0; j < 16; j++ )
{
line = lineBuffer[j];
line = line.Substring(1, line.Length - 1);
var bytesLocal = GetBytesFromByteString(line).ToArray();
length = bytesLocal[0];
for (int i = 0; i < length; i++)
{
buffer256[byteCounter++] = bytesLocal[4 + i];
hexChecksum ^= bytesLocal[4 + i];
}
}
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByteLocal = Convert.ToByte(hexChecksum);
Byte[] csByte_arrLocal = BitConverter.GetBytes(csByteLocal);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
//send checksum
_serialPort.Write(csByte_arrLocal, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
}
// Clear buffer, reset byte count, clear checksum, set flag to send write cmd/send new addr
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
hexChecksum = 0;
lineCount = 0;
sendAddress = true;
}
} // end BLOCK WRITE TO MEMORY
else if (type == 1) // Marker for end of file
{
while (byteCounter != 0)
{
// Add 0xFF to the remaining bytes in this last block of 256
buffer256[byteCounter++] = 0xFF;
// Add byte to checksum
hexChecksum ^= 0xFF;
if (byteCounter >= 255)
{
byteCounter = 0;
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
// For testing
// Console.WriteLine("block number [{0}]", ++blockCount);
//send checksum
_serialPort.Write(csByte_arr, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
if (byte_read == NACK)
{
// ??
}
}
}
}
// end ELSE if TYPE == 1
counter++;
} // end WHILE loop for loading hex file
file.Close();
// For testing
// Console.WriteLine("File is closed.");
// System.Console.WriteLine("There were {0} lines.", counter);
// Console.WriteLine("");
// -- end WRITE MEMORY ------------------------------------------------------
} // end WriteNewAppToFlash
private void handleAppSerialError(IOException exc)
{
throw new NotImplementedException();
}
private void raiseAppSerialDataEvent(byte[] received)
{
throw new NotImplementedException();
}
public void JumpToNewApp(SerialPort _serialPort)
{
int byte_read = 0;
long checksum = 0;
var ff = new byte[] { 0xFF };
int baseAddress = 0x08000000;
// Jumps to flash memory 0x08000000, where the sector 0 code will perform a normal startup
// Send 0x21 ( GO ) and complement 0xDE
var go = new byte[] { 0x21 };
var de = new byte[] { 0xDE };
while (byte_read != 0x79)
{
_serialPort.Write(go, 0, 1);
_serialPort.Write(de, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for GO COMMAND start");
//Console.WriteLine("");
}
}
// -- end SEND GO COMMAND and wait for ACK -----------------------------------------
Byte[] startAddr = BitConverter.GetBytes(baseAddress);
// Reset Checksum and XOR address
checksum = 0;
foreach (byte b in startAddr)
{
checksum ^= b;
}
Byte[] cheksum = BitConverter.GetBytes(checksum);
// Send first byte (msb) of address
_serialPort.Write(startAddr, 3, 1);
// Send second byte of address
_serialPort.Write(startAddr, 2, 1);
// Send third byte of address
_serialPort.Write(startAddr, 1, 1);
// Send last byte (lsb) of address
_serialPort.Write(startAddr, 0, 1);
_serialPort.Write(cheksum, 0, 1);
Thread.Sleep(20);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
} // end JUMPTONEWAPP
// Converts a string to a byte array
public static IEnumerable<byte> GetBytesFromByteString(string str)
{
for (int index = 0; index < str.Length; index += 2)
{
yield return Convert.ToByte(str.Substring(index, 2), 16);
}
}
protected void AssertOpenPort()
{
// if( !IsOpen )
// throw new InvalidOperationException("Serial Port is not open");
}
} // end public class FWupdater
If you are looking for real progress, then your updater will need to raise progress as it goes. You can raise events out of updater, and subscribe to them from within worker_DoWork, and use ReportProgress to marshal it back to the UI thread for progress report:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
updater.Progress += updater_Progress;
try {
updater.updater();
} finally {
updater.Progress -= updater_Progress;
}
}
void updater_Progress(object sender, ProgressEvents evt) {
worker.ReportProgress(evt.Percent);
}
This of course requires you to create a Progress event in your Updater class and to invoke that event as your updater method does its work.
BackgroundWorker does two things for you:
Lets you run a task in a background thread so your UI thread stays responsive
Lets you easily marshal progress from the background thread to the UI thread without having to use Form.Invoke.
The DoWork event fires in a background thread. Everything in that event handler happens in order, like normal code-- while your UI thread happily continues operating. If you want fake progress, you would do the progress updating with a timer callback from the UI thread, while the BackgroundWorker runs your updater code in the background
The question was to get updates DURING the upgrade, so it makes sense to send out changes in percentage from the program doing the work you are trying to measure. The part I was missing was supplied by #mjwills - passing the BackgroundWorker as a parameter to the updater allowed me to call ReportProgress from the updater and increment the percentage value as I wished.
I used the BackgroundWorker (bw) set-up pretty much as shown in MSDN. Here are the methods for the bw, which I placed in my form class.
BackgroundWorker bw = new BackgroundWorker();
Then a button click event (shows end of method) when the client has the COM port and upgrade file selected, followed by the bw methods.
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.WorkerReportsProgress = true;
bw.RunWorkerAsync();
pbar.Maximum = 100;
pbar.Minimum = 0;
pbar.Value = 0;
// Percentage will be added to the end of this line during the upgrade
updateMsg.Content = "Upgrade in progress... ";
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
updater.updater(bw);
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbar.Value = e.ProgressPercentage;
updateMsg.Content = String.Format("Upgrade in progress... {0} %", e.ProgressPercentage);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
updateMsg.Content = "Upgrade Complete. Exit window to proceed...";
}
On the updater() side, define a percentage variable:
public int percentage;
Add the BackgroundWorker as a parameter:
public void updater( BackgroundWorker bw ) { <code> }
Then call ReportProgress to update the ProgressPercentage event in the bw_ProgressChanged method. Start at 0% and increment the percent variable:
bw.ReportProgress(percentage += 5);
Later on, I change the update to single percents while writing many blocks of data to flash memory:
// update progress bar in backgroundWorker thread
if ( blockCount % 10 == 0)
{
bw.ReportProgress(percentage++);
}
I would like to thank everyone for their input and I hope this answer saves someone writing an extra thousand lines of code. I hope to receive feedback on this answer and I am still interested in alternative, better solutions.
You can solve it like this
BackgroundWorker worker;
public void Init()
{
worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.ProgressChanged += Worker_ProgressChanged;
worker.WorkerReportsProgress = true; // This is important
worker.RunWorkerAsync();
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// Do your update progress here...
for (int i = 0; i <= 100; i++) // This simulates the update process
{
System.Threading.Thread.Sleep(100);
worker.ReportProgress(i); // Report progress from the background worker like this
}
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update the progress bar or other ui elements here...
// Use the e.ProgressPercentage
}
It is absolutely ok to run the background worker for a longer period of time. I have never experienced any problems with it, even when having one running at all time.

Reading all data from stream of TcpClient

I am working on a new machine at my works which is controlled via a PC. Current stuck on talking to a camera system that is connected via Ethernet.
Here is my code of opening a connection.
TcpClient client;
NetworkStream stream;
public bool OpenConnection()
{
client = new TcpClient();
try
{
//Camera.Open();
client.Connect("192.168.0.10", 8500);
stream = client.GetStream();
}
catch (Exception ex)
{
return false;
}
return true;
}
So far so good. Once the connection is open I then request some information from the camera
The message format I am using has STX(0x02) to indicate the start of the message and ETX(0x03) as the end of the message.
char StartOfPacket = (char)0x02;
char EndOfPacket= (char)0x03;
public bool RetrieveDigits(out string Digits)
{
// Send the trigger cammand to the vision system
Digits = "";
bool EverythingOK = true;
string DataToSend = StartOfPacket + "T1" + EndOfPacket;
byte[] buff = Encoding.ASCII.GetBytes(DataToSend);
if (LogCameraEvent != null)
LogCameraEvent(">> " + DataToSend);
try
{
stream.Write(buff, 0, buff.Length);
}
catch (Exception ex)
{
Logging.Instance.LogExceptionToFile(MethodBase.GetCurrentMethod(), ex);
EverythingOK = false;
}
Thread.Sleep(100);
byte[] buffer;
if (EverythingOK)
{
// Check the response
buffer = ReadCamera(10);
// Process the packets
string[] packets = ProcessPackets(buffer);
if (packets != null)
{
if (packets.Length > 0)
{
bool TriggerFound = false;
for (int i = 0; i < packets.Length; i++)
{
if (packets[i] == "T1")
{
TriggerFound = true;
continue;
}
else if (TriggerFound)
{
// If we are here then we should now be the data that was requested
if (string.IsNullOrEmpty(packets[i]))
{
Digits = packets[i-1]; // previous packet may have data from previous trigger. Need to look into why this happens.
}
else
Digits = packets[i];
EverythingOK = true;
break;
}
else
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
return EverythingOK;
}
Here is the part where I think the issue may lie, getting the response.
private byte[] ReadCamera(int ExpectedLength)
{
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
int chunk;
while(stream.DataAvailable)
{
chunk = stream.Read(Buffer, read, Buffer.Length-read);
read += chunk;
// If we have reached the end of our buffer, check to see if theres any more information
if(read == Buffer.Length)
{
if(!stream.DataAvailable)
return Buffer;
// Nope. Resize the buffer, put the byte we've just read and continue
byte[] newBuffer = new byte[Buffer.Length * 2];
Array.Copy(Buffer, newBuffer, Buffer.Length);
Buffer = newBuffer;
//read++;
}
else if(!stream.DataAvailable)
return Buffer;
Thread.Sleep(50);
}
// Buffer is now too big, shrink it
byte[] ret = new byte[read];
Array.Copy(Buffer, ret, read);
return ret;
}
private string[] ProcessPackets(byte[] data)
{
// look for the stat char
List<string> Packets = new List<string>();
byte Start = 0x02;
bool StartFound = false;
byte End = 0x03;
StringBuilder sb = new StringBuilder();
for(int i =0; i<data.Length; i++)
{
if(StartFound)
{
// Check to see if its the end
if (data[i] == End)
{
Packets.Add(sb.ToString());
sb.Clear();
}
else
sb.Append(Encoding.ASCII.GetChars(data, i, 1));
}
// Find the start
if (!StartFound)
{
if (data[i] == Start)
{
StartFound = true;
}
}
}
return Packets.ToArray();
}
Let me explain what should happen and then what is happening. Through RetrieveDigits method I am sending "T1" to the camera. What the camera will do is respond with "T1" followed by 2 ascii characters, for now we will say AA. Using a diagnostic app on the camera system I can monitor the Ethernet and I see the following.
(>> means Received by Camera)
(<< means Sent from Camera)
>>[STX]T1[ETX]
<<[STX]T1[ETX][STX]AA[ETX]
So I see what the camera has sent. I confirmed the PC has has received the data using wire shark.
Now further down in the RetrieveDigits method you can see I process the packets received, loop through the packets until I find "T1" and then assume the next packet will be the data I am after and I set Digits to this value.
What I am finding is that sometimes when I run the app I see that Digits is set to "".
I am also finding that sometimes my data received will be "AA" then "T1" rather than "T1" then "AA". What I suspect is happening is that when its back to front, the "AA" is actually from the previous data sent from the camera and for some reason it was missed when reading from the stream.
Any idea why this could be happening as I am reading the data until Stream.Available is false.
Edit:
Modified the ReadCamera code to process the packets, reading 1 byte at a time.
private string[] ReadCamera(int ExpectedLength, int ExpectedPackets)
{
List<string> Packets = new List<string>();
bool StartFound = false;
StringBuilder sb = new StringBuilder();
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
while (true)
{
read += stream.Read(Buffer, read, 1);
// Check to see if the byte read is the start of a packet
if (Buffer[read - 1] == StartOfPacket)
{
StartFound = true;
}
else if (StartFound)
{
// Check to see if the byte read is the end of a packet
if (Buffer[read - 1] == EndOfPacket)
{
Packets.Add(sb.ToString());
sb.Clear();
StartFound = false;
if (Packets.Count == ExpectedPackets)
break;
}
else
{
sb.Append(Encoding.ASCII.GetChars(Buffer, read - 1, 1));
}
}
}
// For Debuggin purposes
foreach(string s in Packets)
if (LogCameraEvent != null)
LogCameraEvent("<< " + s);
return Packets.ToArray();
}
and modified calling the method like so
// Check the response
string[] packets = ReadCamera(10,2);
// Process the packets
//string[] packets = ProcessPackets(buffer);

Modbus and C# -- problem in reading response

I am a newbie to modbus and need some help. I am trying to connect using modbus and serial communication. so far i managed to send data but i am unable to get any. the following is my code.
Building packet
private byte[] BuildPacket(int meter_address,int function,int table_name,int table_offset,int high_byte, int low_byte)
{
try
{
byte[] packet = new byte[6];
packet[0] = Convert.ToByte(meter_address);
packet[1] = Convert.ToByte(function);
packet[2] = Convert.ToByte(table_name);
packet[3] = Convert.ToByte(table_offset);
packet[4] = Convert.ToByte(high_byte);
packet[5] = Convert.ToByte(low_byte);
byte[] checksum = DoCheckSum(packet);
byte[] sendPacket = new byte[8];
sendPacket[0] = packet[0];
sendPacket[1] = packet[1];
sendPacket[2] = packet[2];
sendPacket[3] = packet[3];
sendPacket[4] = packet[4];
sendPacket[5] = packet[5];
sendPacket[6] = checksum[0];
sendPacket[7] = checksum[1];
return sendPacket;
}
catch (Exception)
{
throw;
}
}
Checksum for modbus
try
{
ushort CRCFull = 0xFFFF;
byte CRCHigh = 0xFF, CRCLow = 0xFF;
char CRCLSB;
for (int i = 0; i < (packet.Length); i++)
{
CRCFull = (ushort)(CRCFull ^ packet[i]);
for (int j = 0; j < 8; j++)
{
CRCLSB = (char)(CRCFull & 0x0001);
CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
if (CRCLSB == 1)
CRCFull = (ushort)(CRCFull ^ 0xA001);
}
}
byte[] crcByte = new byte[2];
crcByte[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
crcByte[0] = CRCLow = (byte)(CRCFull & 0xFF);
return crcByte;
}
catch (Exception ex)
{
throw ex;
}
}
Connection through serial and modbus
public void ConnectSerialModBus(string COM, int baud)
{
SerialPort port = new SerialPort(COM, baud, Parity.None, 8, StopBits.One);
if (!(port.IsOpen))
{
byte[] sendPacket = BuildPacket(3, 4, 11, 0, 1, 200);
port.Open();
port.RtsEnable = false;
port.Handshake = Handshake.None;
//SEND PACKET TO DEVICE
port.Write(sendPacket, 0, sendPacket.Length);
#region RECEIVE DATA FROM SERIAL
//MAKE PROCESS STOP FOR 5sec
Thread.Sleep(3000);
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.RtsEnable = true;
int size = port.ReadBufferSize;
byte[] readingbyte = new byte[size];
port.Read(readingbyte, 0, readingbyte.Length);
string reading = Encoding.GetEncoding("Windows-1252").GetString(readingbyte);
port.Close();
port.Dispose();
#endregion
}
}
The problem is when it comes to reading the response, the program gets stuck. if possible please help me out figure what is wrong with it.
found a solution to the problem, the problem was with the thread.sleep. was giving it 3secs which is too much for the rtf to receive the packet. changed to 10ms and worked fine.

Categories

Resources