Converting from C++ (GetAsyncKeyState) to C# - WPF - c#

I have a new problem with a piece of code from c++. I have a keypress to make a key toggle or something similar...maybe the code will explain better then me :
while (1) {
Sleep (1);
if (GetAsyncKeyState(VK_TAB) & 1) {
toggle = !toggle;
if(toggle)
{
code here...();
}
else
{
code here...();
}
}
}
In c++ everything is fine...but porting to C# - WPF, is giving me crashes.
Any idea what is the most easy way ?
Thank you,
edit 2 :
Why isn't working ? I have registered the key for the action..but is not starting.
It's because i am already inside the method ?
KeyboardHook hook = new KeyboardHook();
// take action on keys pressed.
hook.KeyPressed += new EventHandler<KeyPressedEventArgs>(fireUp);
// register the event that is fired after the key press.
hook.RegisterHotKey(ModKeys.None, Keys.Tab);
void fireUp(object sender, KeyPressedEventArgs e)
{
bool toggle = false;
toggle = !toggle;
byte[] byt = { 0xC7,0x83,0x1A,0x05,0x00,0x00,0x00,0x00,0x00,0x00 };
for (int i = 6; i < 10; ++i)
{
byt[i] = (byte)(atkSpd & 0xFF);
atkSpd = atkSpd >> 8;
}
if (toggle)
{
Write(vMemory + 8, byt, 10);
Write(vMemory, BitConverter.GetBytes((vMemory + 8)), 8);
Write(atkBase, new byte[] { 0xFF, 0x24, 0x25 }, 3);
Write(atkBase + 3, BitConverter.GetBytes((vMemory)), 4);
}
else
{
Write(atkBase, new byte[] { 0x66, 0x89, 0xB3, 0x1A, 0x05, 0x00, 0x00 }, 7);
}
}

Is there any reason why you can't use an KeyDown/KeyPress/KeyUp event?
private void tabPress(object sender, KeyEventArgs e)
{
if (e.Key == Key.Tab)
{
if(toggle)
{
code here...();
}
else
{
code here...();
}
}
}
In my opinion this is better approach, not to mention that is more efficient (not checking all the time).
If you want to use the approach you've posted, I'd say that crash happens because the while loop is infinite, not allowing anything else to happen. It would've helped if you provided an exception you get at crash or at least some more info on what actually happens.

Finally, i fix it.
public partial class MainWindow : Window
{
private bool toggle = true;
}
private void fireUp(rwKey hotKey)
{
byte[] byt ={0xC7,0x83,0x1A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8B,0x74,0x24,
0x40,0x48,0x8B,0x6C,0x24,0x48,0x48,0x8B,0x5C,0x24,0x50,0x48,0x83,0xC4,0x58,0xC3};
for (int i = 6; i < 10; ++i) { byt[i] = (byte)(atkSpd & 0xFF); atkSpd = atkSpd >> 8; }
bool kd = (toggle = !toggle);
if (kd)
{
Write(vMemory + 8, byt, 30);
Write(vMemory, BitConverter.GetBytes((vMemory + 8)), 8);
Write(atkBase, new byte[] { 0xFF, 0x24, 0x25 }, 3);
Write(atkBase + 3, BitConverter.GetBytes((vMemory)), 4);
}
else
{
Write(atkBase, new byte[] { 0x66, 0x89, 0xB3, 0x1A, 0x05, 0x00, 0x00 }, 7);
}
}

Related

Decreasing volume of .wav file creates heavy distortion

I have a problem that just baffles me. I import a .wav file and read them as bytes. Then I turn them into integers that I then all divide by 2 (or some other number) in order to decrease the volume. Then I make a new .wav file into which I put the new data. The result is loud and heavy distortion over the original track.
Scroll to the Main() method for the relevant (C#-)code:
using System;
using System.IO;
namespace ConsoleApp2 {
class basic {
public static byte[] bit32(int num) { //turns int into byte array of length 4
byte[] numbyt = new byte[4] { 0x00, 0x00, 0x00, 0x00 };
int pow;
for (int k = 3; k >= 0; k--) {
pow = (int)Math.Pow(16, 2*k + 1);
numbyt[k] += (byte)(16*(num/pow));
num -= numbyt[k]*(pow/16);
numbyt[k] += (byte)(num/(pow/16));
num -= (num/(pow/16))*pow/16;
}
return numbyt;
}
public static byte[] bit16(int num) { //turns int into byte array of length 2
if (num < 0) {
num += 65535;
}
byte[] numbyt = new byte[2] { 0x00, 0x00 };
int pow;
for (int k = 1; k >= 0; k--) {
pow = (int)Math.Pow(16, 2*k + 1);
numbyt[k] += (byte)(16*(num/pow));
num -= numbyt[k]*(pow/16);
numbyt[k] += (byte)(num/(pow/16));
num -= (num/(pow/16))*pow/16;
}
return numbyt;
}
public static int bitint16(byte[] numbyt) { //turns byte array of length 2 into int
int num = 0;
num += (int)Math.Pow(16, 2)*numbyt[1];
num += numbyt[0];
return num;
}
}
class wavfile: FileStream {
public wavfile(string name, int len) : base(name, FileMode.Create) {
int samplerate = 44100;
byte[] riff = new byte[] { 0x52, 0x49, 0x46, 0x46 };
this.Write(riff, 0, 4);
byte[] chunksize;
chunksize = basic.bit32(36 + len*4);
this.Write(chunksize, 0, 4);
byte[] wavebyte = new byte[4] { 0x57, 0x41, 0x56, 0x45 };
this.Write(wavebyte, 0, 4);
byte[] fmt = new byte[] { 0x66, 0x6d, 0x74, 0x20 };
this.Write(fmt, 0, 4);
byte[] subchunk1size = new byte[] { 0x10, 0x00, 0x00, 0x00 };
this.Write(subchunk1size, 0, 4);
byte[] formchann = new byte[] { 0x01, 0x00, 0x02, 0x00 };
this.Write(formchann, 0, 4);
byte[] sampleratebyte = basic.bit32(samplerate);
this.Write(sampleratebyte, 0, 4);
byte[] byterate = basic.bit32(samplerate*4);
this.Write(byterate, 0, 4);
byte[] blockalign = new byte[] { 0x04, 0x00 };
this.Write(blockalign, 0, 2);
byte[] bits = new byte[] { 0x10, 0x00 };
this.Write(bits, 0, 2);
byte[] data = new byte[] { 0x64, 0x61, 0x74, 0x61 };
this.Write(data, 0, 4);
byte[] samplesbyte = basic.bit32(len*4);
this.Write(samplesbyte, 0, 4);
}
public void sound(int[] w, int len, wavfile wavorigin = null) {
byte[] wavbyt = new byte[len*4];
for (int t = 0; t < len*2; t++) {
byte[] wavbit16 = basic.bit16(w[t]);
wavbyt[2*t] = wavbit16[0];
wavbyt[2*t + 1] = wavbit16[1];
}
this.Write(wavbyt, 0, len*4);
System.Media.SoundPlayer player = new System.Media.SoundPlayer();
player.SoundLocation = this.Name;
while (true) {
player.Play();
Console.WriteLine("repeat?");
if (Console.ReadLine() == "no") {
break;
}
}
}
}
class Program {
static void Main() {
int[] song = new int[45000*2];
byte[] songbyt = File.ReadAllBytes("name.wav"); //use your stereo, 16bits per sample wav-file
for (int t = 0; t < 45000*2; t++) {
byte[] songbytsamp = new byte[2] { songbyt[44 + 2*t], songbyt[44 + 2*t + 1] }; //I skip the header
song[t] = basic.bitint16(songbytsamp)/2; //I divide by 2 here, remove the "/2" to hear the normal sound again
//song[t] *= 2;
}
wavfile wav = new wavfile("test.wav", 45000); //constructor class that writes the header of a .wav file
wav.sound(song, 45000); //method that writes the data from "song" into the .wav file
}
}
}
The problem is not the rounding down that happens when you divide an odd number by 2; you can uncomment the line that says song[t] *= 2; and hear for yourself that all of the distortion has completely disappeared again.
I must be making a small stupid mistake somewhere, but I cannot find it. I just want to make the sound data quieter to avoid distortion when I add more sounds to it.
Well, I knew it would be something stupid, and I was right. I forgot to account for the fact that negative numbers are written in signed 16 bit language as the numbers above 2^15, and when you divide by 2, you push them into (very large) positive values. I altered my code to substract 2^16 from any number that's above 2^15 before dividing by 2. I have to thank this person though: How to reduce volume of wav stream?
If this means that my question was a duplicate, then go ahead and delete it, but I'm letting it stay for now, because someone else might find it helpful.
Using Math.Pow to do bit and byte operations is a really bad idea. That function takes double values as inputs and returns a double. It also does exponentiation (not a trivial operation). Using traditional bit shift and mask operations is clearer, much faster and less likely to introduce noise (because of the inaccuracy of doubles).
As you noticed, you really want to work with unsigned quantities (like uint/UInt32 and ushort/UInt16). Sign extension trips up everyone when doing this sort of work.
This is not a full answer to your question, but it does present a way to do the byte operations that is arguably better.
First, create a small struct to hold a combination of a bit-mask and a shift quantity:
public struct MaskAndShift {
public uint Mask {get; set;}
public int Shift {get; set;}
}
Then I create two arrays of these structs for describing what should be done to extract individual bytes from a uint or a ushort. I put them both in a static class named Worker:
public static class Worker {
public static MaskAndShift[] Mask32 = new MaskAndShift[] {
new MaskAndShift {Mask = 0xFF000000, Shift = 24},
new MaskAndShift {Mask = 0x00FF0000, Shift = 16},
new MaskAndShift {Mask = 0x0000FF00, Shift = 8},
new MaskAndShift {Mask = 0x000000FF, Shift = 0},
};
public static MaskAndShift[] Mask16 = new MaskAndShift[] {
new MaskAndShift {Mask = 0x0000FF00, Shift = 8},
new MaskAndShift {Mask = 0x000000FF, Shift = 0},
};
}
Looking at the first entry in the first array, it says "to extract the first byte from a uint, mask that uint with 0xFF000000 and shift the result 24 bits to the right". If you have endian-ness issues, you can simply re-order the entries in the array.
Then I created this static function (in the Worker class) to convert a uint / UInt32 to an array of four bytes:
public static byte[] UintToByteArray (uint input) {
var bytes = new byte[4];
int i = 0;
foreach (var maskPair in Mask32) {
var masked = input & maskPair.Mask;
if (maskPair.Shift != 0) {
masked >>= maskPair.Shift;
}
bytes[i++] = (byte) masked;
}
return bytes;
}
The code to do the same operation for a 16 bit ushort (aka UInt16) looks nearly the same (there's probably an opportunity for some refactoring here):
public static byte[] UShortToByteArray (ushort input) {
var bytes = new byte[2];
int i = 0;
foreach (var maskPair in Mask16) {
var masked = input & maskPair.Mask;
if (maskPair.Shift != 0) {
masked >>= maskPair.Shift;
}
bytes[i++] = (byte) masked;
}
return bytes;
}
The reverse operation is much simpler (however, if you have endian-ness issues, you'll need to write the code). Here I just take the entries of the array, add them into a value and shift the result:
public static uint ByteArrayToUint (byte[] bytes) {
uint result = 0;
//note that the first time through, result is zero, so shifting is a noop
foreach (var b in bytes){
result <<= 8;
result += b;
}
return result;
}
Doing this for the 16 bit version ends up being effectively the same code, so...
public static ushort ByteArrayToUshort (byte[] bytes) {
return (ushort) ByteArrayToUint(bytes);
}
Bit-twiddling never works the first time. So I wrote some test code:
public static void Main(){
//pick a nice obvious pattern
uint bit32Test = (((0xF1u * 0x100u) + 0xE2u) * 0x100u + 0xD3u) * 0x100u + 0xC4u;
Console.WriteLine("Start");
Console.WriteLine("Input 32 Value: " + bit32Test.ToString("X"));
var bytes32 = Worker.UintToByteArray(bit32Test);
foreach (var b in bytes32){
Console.WriteLine(b.ToString("X"));
}
Console.WriteLine();
ushort bit16Test = (ushort)((0xB5u * 0x100u) + 0xA6u);
Console.WriteLine("Input 16 Value: " + bit16Test.ToString("X"));
var bytes16 = Worker.UShortToByteArray(bit16Test);
foreach (var b in bytes16){
Console.WriteLine(b.ToString("X"));
}
Console.WriteLine("\r\nNow the reverse");
uint reconstitued32 = Worker.ByteArrayToUint(bytes32);
Console.WriteLine("Reconstituted 32: " + reconstitued32.ToString("X"));
ushort reconstitued16 = Worker.ByteArrayToUshort(bytes16);
Console.WriteLine("Reconstituted 16: " + reconstitued16.ToString("X"));
}
The output from that test code looks like:
Start
Input 32 Value: F1E2D3C4
F1
E2
D3
C4
Input 16 Value: B5A6
B5
A6
Now the reverse
Reconstituted 32: F1E2D3C4
Reconstituted 16: B5A6
Also note that I do everything in hexadecimal - it makes everything so much easier to read and to understand.

C# - Reading Sequence of Hex Bytes in Binary

So I've been googling & googling for this, but I can't find a solution for my case. I could find things about byte arrays. but I hope there's also a simpler solution for my case.
Maybe it's just me using the wrong search terms, don't know.
Anyways, I already have a kinda working code which is:
static void Main(string[] args)
{
// Open the file to search in
BinaryReader br = new BinaryReader(File.OpenRead("D:/Users/Joey/Desktop/prod"));
for (int i = 0; i <= br.BaseStream.Length; i++)
{
// Search the file for the given byte
if (br.BaseStream.ReadByte() == (byte)0xC0)
{
Console.WriteLine("Found the byte at offset " + i); //write to the console on which offset it has been found
}
}
}
This example works.
However, I need it to be able to search for more than just one byte.
For example: C0035FD6
I feel like I'm missing something so simple, but I just can't seem to figure it out.
If anyone has gotten a solution for me, that would be great :D
You can use this extension to search for AOB:
public static class StreamExtensions
{
public static IEnumerable<long> ScanAOB(this Stream stream, params byte[] aob)
{
long position;
byte[] buffer = new byte[aob.Length - 1];
while ((position = stream.Position) < stream.Length)
{
if (stream.ReadByte() != aob[0]) continue;
if (stream.Read(buffer, 0, aob.Length - 1) == 0) continue;
if (buffer.SequenceEqual(aob.Skip(1)))
{
yield return position;
}
}
}
public static IEnumerable<long> ScanAOB(this Stream stream, params byte?[] aob)
{
long position;
byte[] buffer = new byte[aob.Length - 1];
while ((position = stream.Position) < stream.Length)
{
if (stream.ReadByte() != aob[0]) continue;
if (stream.Read(buffer, 0, aob.Length - 1) == 0) continue;
if (buffer.Cast<byte?>().SequenceEqual(aob.Skip(1), new AobComparer()))
{
yield return position;
}
}
}
private class AobComparer : IEqualityComparer<byte?>
{
public bool Equals(byte? x, byte? y) => x == null || y == null || x == y;
public int GetHashCode(byte? obj) => obj?.GetHashCode() ?? 0;
}
}
Example:
void Main()
{
using (var stream = new MemoryStream(FakeData().ToArray()))
{
stream.ScanAOB(0x1, 0x2).Dump("Addresses of: 01 02");
stream.Position = 0;
stream.ScanAOB(0x03, 0x12).Dump("Addresses of: 03 12");
stream.Position = 0;
stream.ScanAOB(0x04, null, 0x06).Dump("Addresses of: 04 ?? 06");
}
}
// Define other methods and classes here
IEnumerable<byte> FakeData()
{
return Enumerable.Range(0, 2)
.SelectMany(_ => Enumerable.Range(0, 255))
.Select(x => (byte)x);
}
Give this a shot. You will need to verify the arrays are correct. In a binary stream, a byte array is just a collection of bytes starting at offset with count bytes as its size.
//here is where you initialize your array. you may need to tweak the values to match your byte range (array)
byte[] dataArray = new byte[9] { 0x93, 0x0E, 0x40, 0xF9, 0x53, 0x00, 0x00, 0xB5, 0xDE };
//here is where you initialize the NEW array you want to write where your matching array lives
byte[] newArray = new byte[9] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Open the file to search in
BinaryReader br = new BinaryReader(File.OpenRead("D:/Users/Joey/Desktop/prod"));
for (int i = 0; i <= br.BaseStream.Length; i++)
{
// Search the file for the STARTING byte of my match
if (br.BaseStream.ReadByte() == (byte)0x93)
{
Console.WriteLine("Found the starting byte at offset " + i); //write to the console on which offset it has been found
byte[] tempArray = new byte[9];
tempArray = br.ReadBytes(9);
//now compare the arrays to see if you have a full match:
int matched = 0;
for (int j=0; j<tempArray.Length; j++)
{
if(tempArray[j] == dataArray[j])
{
matched++;
}
}
//if the arrays match, write your new values:
if(matched == tempArray.Length-1)
{
br.BaseStream.Write(newArray, i, 9);
break; //exit the loop when finished
}
}
}

How to simplify these methods to avoid confusion?

I've come here today to ask a question about these methods. I've taken lead on a personal project as a hobby and unfortunately I can't contact the old developer to ask what these methods even do. I'm pretty new to C# so I was asking if anyone could help me in simplifying them, to avoid the confusion I'm having? If anyone could actually tell me what they do also that would really help.
I'm just a little confused about them as of now... They were in the utilities folder. The project is an emulation server for a game, sending and receiving packets is the main focus.
public static int DecodeInt32(byte[] v)
{
if ((v[0] | v[1] | v[2] | v[3]) < 0)
{
return -1;
}
return (v[0] << 0x18) + (v[1] << 0x10) + (v[2] << 8) + v[3];
}
public static int DecodeInt16(byte[] v)
{
if ((v[0] | v[1]) < 0)
{
return -1;
}
return (v[0] << 8) + v[1];
}
Here is a part of code that uses them, might help in finding out?
using (BinaryReader Reader = new BinaryReader(new MemoryStream(Data)))
{
if (Data.Length < 4)
return;
int MsgLen = Utilities.DecodeInt32(Reader.ReadBytes(4));
if ((Reader.BaseStream.Length - 4) < MsgLen)
{
this._halfData = Data;
this._halfDataRecieved = true;
return;
}
else if (MsgLen < 0 || MsgLen > 5120)//TODO: Const somewhere.
return;
byte[] Packet = Reader.ReadBytes(MsgLen);
using (BinaryReader R = new BinaryReader(new MemoryStream(Packet)))
{
int Header = Utilities.DecodeInt16(R.ReadBytes(2));
byte[] Content = new byte[Packet.Length - 2];
Buffer.BlockCopy(Packet, 2, Content, 0, Packet.Length - 2);
ClientPacket Message = new ClientPacket(Header, Content);
try
{
Server.GetGame().GetPacketManager().TryExecutePacket(this, Message);
}
catch (Exception e)
{
ExceptionLogger.LogException(e);
}
this._deciphered = false;
}
if (Reader.BaseStream.Length - 4 > MsgLen)
{
byte[] Extra = new byte[Reader.BaseStream.Length - Reader.BaseStream.Position];
Buffer.BlockCopy(Data, (int)Reader.BaseStream.Position, Extra, 0, (int)(Reader.BaseStream.Length - Reader.BaseStream.Position));
this._deciphered = true;
HandleMoreData(Extra);
}
}
The BinaryReader has the methods ReadInt16 and ReadInt32 (and many others). Therefore you could replace the decoding methods.
int MsgLen = Utilities.DecodeInt32(Reader.ReadBytes(4));
becomes
int MsgLen = Reader.ReadInt32();
I assume that the Endianness of the bytes is right for the BinaryReader methods.

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.

Replace two bytes in a generic list

I want to replace every occurrence of one of those magic 2-byte packages in my List<byte> with a single byte:
{ 0xF8, 0x00 } -> Replace with 0xF8
{ 0xF8, 0x01 } -> Replace with 0xFB
{ 0xF8, 0x02 } -> Replace with 0xFD
{ 0xF8, 0x03 } -> Replace with 0xFE
For example:
List<byte> message
= new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x02, 0xF8, 0x03, 0xFE };
// will be converted to:
List<byte> expected
= new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0xFB, 0xFD, 0xFE, 0xFE };
This is my solution so far, which works but I don't like it because its readability is quite bad:
public static void RemoveEscapeSequences(List<byte> message)
{
// skipped parameter checks
for (int index = 0; index < message.Count - 1; ++index)
{
if (message[index] == 0xF8)
{
// found an escaped byte, look at the following byte to determine replacement
switch (message[index + 1])
{
case 0x0:
message[index] = 0xF8;
message.RemoveAt(index + 1);
break;
case 0x1:
message[index] = 0xFB;
message.RemoveAt(index + 1);
break;
case 0x2:
message[index] = 0xFD;
message.RemoveAt(index + 1);
break;
case 0x3:
message[index] = 0xFE;
message.RemoveAt(index + 1);
break;
}
}
}
}
Is there a shorter solution with improved readability?
You can do something like this - it'll be slightly slower, though:
public static void RemoveEscapeSequences(List<byte> message)
{
var replaceBytes = new Dictionary<byte, byte>()
{
{0x00, 0xF8}, {0x01, 0xFB}, {0x02, 0xFD}, {0x03, 0xFE}
};
// skipped parameter checks
for (int index = 0; index < message.Count - 1; ++index)
{
if (message[index] == 0xF8)
{
if(replaceBytes.ContainsKey(message[index + 1]))
{
message[index] = replaceBytes[message[index + 1]];
message.RemoveAt(index + 1);
}
}
}
}
You can use following extension method:
public static IEnumerable<byte> Escape(this IEnumerable<byte> source)
{
if (source == null)
throw new ArgumentNullException("source");
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
byte current = enumerator.Current;
if (current != 0xF8)
{
yield return current;
continue;
}
if (!enumerator.MoveNext())
yield return current;
byte next = enumerator.Current;
switch (next)
{
case 0x00: yield return 0xF8; break;
case 0x01: yield return 0xFB; break;
case 0x02: yield return 0xFD; break;
case 0x03: yield return 0xFE; break;
default:
yield return current;
yield return next;
break;
}
}
}
}
Usage:
List<byte> result = message.Escape().ToList();
foreach(var b in message.Escape())
Console.Write("0x{0:x} ", b);
Here's a very simple/understandable version, that should be efficient too:
private static List<byte> ComputeBytes(List<byte> input)
{
byte magicValueFirstByte = 0xF8;
var secondByteToBeReplaced = new List<byte> { 0x00, 0x01, 0x02, 0x03 };
var replacements = new List<byte> { 0xF8, 0xFB, 0xFD, 0xFE };
var output = new List<byte>();
for (int i = 0; i < input.Count; i++)
{
var currentValue = input[i];
if (currentValue == magicValueFirstByte && i < input.Count - 1)
{
int index = secondByteToBeReplaced.IndexOf(input[i + 1]);
if (index >= 0)
{
// Then when must replace
output.Add(replacements[index]);
// Skip next item
i++;
continue;
}
}
// Won't replace value, so add current one
output.Add(currentValue);
}
return output;
}
Why not put the replacement bytes in a small array?
private static byte[] EscapeBytes = new byte[]
{
/* 0x00 */ 0xF8,
/* 0x01 */ 0xFB,
/* 0x02 */ 0xFD,
/* 0x03 */ 0xFE
};
Then you can simply index the array:
public static List<byte> RemoveEscapeSequences(List<byte> message)
{
List<byte> result = new List<byte>(message.Count);
bool escape = false;
foreach (byte value in message)
{
if (escape)
{
escape = false;
// Replace the byte. NOTE 1!
result.Add(EscapeBytes[value]);
}
else if (value == 0xF8)
{
// Started an escape sequence.
escape = true;
}
else
{
// Just add the byte.
result.Add(value);
}
}
return result;
}
By adding the bytes to a new list whose capacity is already sufficient to hold the result, you even get a little bit more performance and a lot more readability.
Note 1: When the byte after the 0xF8 escape byte is not between 0 and 3, an IndexOutOfRangeException will occur. If you care, you'll have to add a small check to see whether the byte value is within range, and decide on what to do if its not (not replacing the bytes, removing the escape, throwing an exception).

Categories

Resources