c# SerialPort - not reading all data send - c#

I have recently created an app that is recieving data send through UART from my STM device. The data I try to send is an array of floats - float[512].
The data is send as pure binary - not string. Generally idea is 4xbyte = float.
I am sure that data that I'm sending is good. Checked it with program called "Terminal" and then IEEE 754 Converter.
My program
In program I choose COMport from available and other parameters.
(by default they are my COM adapter parameters). I open connection and then when by STM finishes sending data I'm clicking on "Odebrane" button so it will display data in TextBox
The problem is that I'm not recieving all data.
And I have no idea what is the cause.
private List<float> lista = new List<float>();
private float[] fDane = new float[1024];
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
getAvailablePorts();
tb_Rx.Text = "Wprowadź parametry transmisji";
cb_BaudRate.Text = "9600";
cb_DataBits.Text = "8";
cb_Handshake.Text = "None";
cb_Parity.Text = "None";
cb_StopBits.Text = "One";
}
private void SerialP_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
int size = sp.BytesToRead;
byte[] bArray = new byte[size];
float[] fArray = new float[size / 4];
sp.Read(bArray, 0, size);
for (uint i = 0; i < size / 4; i++)
{
fArray[i] = ByteToFloat(bArray, i); // change 4 bytes to float
lista.Add(fArray[i]);
}
}
private float ByteToFloat(byte[] input, UInt32 i)
{
byte[] Array = new[] { input[4 * i], input[4 * i + 1], input[4 * i + 2], input[4 * i + 3] };
return BitConverter.ToSingle(Array, 0);
}
private void bt_transform_Click(object sender, EventArgs e)
{
float[] fDane = lista.ToArray();
for(UInt32 i = 0; i < fDane.Length; i++)
{
RxPisz(fDane[i]);
}
}
------------------------- SOLVED ---------------------
changed dataRecieved interrupt handler
private void SerialP_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] bArray = new byte[4*numberOfSamples];
float[] fArray = new float[numberOfSamples];
int previouse = counterOfRecBytes;
counterOfRecBytes += sp.BytesToRead;
sp.Read(bArray, previouse, (counterOfRecBytes - previouse));
if (counterOfRecBytes == 4*numberOfSamples)
{
for (uint i = 0; i < numberOfSamples; i++)
{
fArray[i] = ByteToFloat(bArray, i); // change 4 bytes to float
lista.Add(fArray[i]);
}
counterOfRecBytes = 0;
}
}

I think you are not reading data at the good speed, try to change BaudRate from 9600 to 19200.

Related

Reading Real time data from serial port

I am trying to read real time data from an accelerometer. Sampling frequency of the accelerometer is 2650Hz. I am getting proper data from serial port, but unable to match with the sampling frequency. The sampling frequency is varying from 2100Hz to 2400Hz and it is not stable. I am using a stop watch for timing reference.
Here is my code for receiving serial data.
private void toolStripButton12_Click(object sender, EventArgs e)
{
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(115200);
if (!serialPort1.IsOpen)
{
serialPort1.Open();
}
sw.Start();
serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(SerialPort1_DataReceived);
}
}
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
{
byteCount = serialPort1.BytesToRead;
if (byteCount > 4000)
byteCount = 4000;
if (e.EventType == SerialData.Eof)
return;
byte[] buffer = new byte[byteCount];
int readBytes = serialPort1.Read(buffer, 0, buffer.Length);
// FIFO Implementation
buffer.ToList().ForEach(b => newrecievedData1.Enqueue(b));
if (newrecievedData1.Count < 4000) return;
processdata3();
int i = 0;
{
while (i <= packet3.Length-4)
{
while (packet3[i++] != 69) ;
data = packet3[i++];
a = data << 8;
b = a + packet3[i++];
c = b << 8;
d = c + packet3[i++];
Port1data.Add(d);
countbyte[0]++;
tick = (double)countbyte[0];
}
}
t = (double)sw.Elapsed.TotalSeconds;
Sampling frequency = tick / t;
}
try
{
this.Invoke(new EventHandler(DisplayText));
}
catch
{
}
}
Int32[] packet3;
private Int32[] processdata3()
{
if (newrecievedData1.Count >= 4000)
{
packet3 = Enumerable.Range(0, 4000).Select(h => newrecievedData1.Dequeue()).ToArray();
}
return packet3;
}
I want to exactly get 2650 Hz sampling frequency all the time.Any help is highly appreciated.
That is 0.337 ms per sample. That is really pushing the upper limits of how much code can be done per sample.
Without some major optimization to your algorithms (possibly using custom collections designed specifically for your workload) I don't think your requirements are reachable using managed code.

Fft in real time - AsioOut+SampleAggregator

I am currently working on my thesis project, this is an application that writes tablature by ASIO drivers. In short, write what you play. I'm new in all regards Naudio and I'm having poblemas to transform sound into FFT. I am capturing the sound with a device called "GuitarLink" which runs through ASIO4ALL.
So I need to compare frequencies for the chord in real time.
Currently, the program gives me two values, X and Y.
(I am using "SampleAggregator" Class and AsioOut)
MAIN
private SampleAggregator sampleAggregator = new(fftLength);
public MainWindow()
{
InitializeComponent();
dispatcherTimer.Tick += new EventHandler(SoClose);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
dispatcherTimer.Start();
}
void SoClose(object sender, EventArgs e)
{
try
{
if (PBass)
{
sampleAggregator.PerformFFT = true;
sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated);
AsioOut asioOut = new();
BufferedWaveProvider wavprov = new(new WaveFormat(48000, 1));
asioOut.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs>(asio_DataAvailable);
asioOut.InitRecordAndPlayback(wavprov, 1, 25);
asioOut.Play();
I1E.Text = frecuencia.ToString();
}
}
catch
{
MessageBox.Show("Error de bajo presupuesto", "Obviamente algo anda mal");
}
}
private void FftCalculated(object sender, FftEventArgs e)
{
for (int i = 0; i < e.Result.Length; ++i)
{
A = e.Result[i].X;
B = e.Result[i].Y;
frecuencia = B;
Debug.WriteLine($"FFT: X={e.Result[i].X} Y={e.Result[i].Y}");
}
}
void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
byte[] buf = new byte[e.SamplesPerBuffer * 4];
for (int i = 0; i < e.InputBuffers.Length; i++)
{
Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer * 4);
Marshal.Copy(buf, 0, e.OutputBuffers[i], e.SamplesPerBuffer * 4);
}
for (int i = 0; i < buf.Length; i = i + 4)
{
float sample = Convert.ToSingle(buf[i] + buf[i + 1] + buf[i + 2] + buf[i + 3]);
sampleAggregator.Add(sample);
}
e.WrittenToOutputBuffers = true;
}
SampleAggregator class
public class SampleAggregator
{
// FFT
public event EventHandler<FftEventArgs> FftCalculated;
public bool PerformFFT { get; set; }
// This Complex is NAudio's own!
private Complex[] fftBuffer;
private FftEventArgs fftArgs;
private int fftPos;
private int fftLength;
private int m;
public SampleAggregator(int fftLength)
{
if (!IsPowerOfTwo(fftLength))
throw new ArgumentException("FFT Length must be a power of two");
this.m = (int)Math.Log(fftLength, 2.0);
this.fftLength = fftLength;
this.fftBuffer = new Complex[fftLength];
this.fftArgs = new FftEventArgs(fftBuffer);
}
public void Add(float value)
{
if (PerformFFT && FftCalculated != null)
{
fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftLength));
fftBuffer[fftPos].Y = 0; // This is always zero with audio.
fftPos++;
if (fftPos >= fftLength)
{
fftPos = 0;
FastFourierTransform.FFT(true, m, fftBuffer);
FftCalculated(this, fftArgs);
}
}
}
static bool IsPowerOfTwo(int x) => (x & (x - 1)) == 0;
}
public class FftEventArgs : EventArgs
{
public Complex[] Result { get; private set; }
public string resultado = "";
[DebuggerStepThrough]
public FftEventArgs(Complex[] result) => Result = result;
void FftCalculated(object sender, FftEventArgs e)
{
}
}
Well the problem is that when I play a note, the values that are delivered are not affected.

need help to send int array from C# to arduino

I have the following integer array [1,2,3,4,5,6,7,8,9]
I need to send it to Arduino UNO.
I've tried to send it as array of byte but it doesn't work.
C# code:
using System.IO.Ports;
private void Form1_Load(object sender, EventArgs e)
{serialPort1.Open();}
byte[] OUT = { 1,2,3,4,5,6,7,8,9 };
serialPort1.Write(OUT, 0, 12);
arduino code
void setup() {
Serial.begin(9600);
for (byte aPin = start; aPin <= 13 ; aPin++) {
pinMode(aPin, OUTPUT);}
for (byte apin = start; apin <= 13 ; apin++) {
digitalWrite(apin,HIGH);}
}
void loop(){
//Serial communication step
//Serial.write("6564456464646");
if(Serial.available()){
for(char j=0;j<Serial.available();j++)
{input[j]=Serial.read();}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace AGAING
{
public partial class Form1 : Form
{
// int[] OUT = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // The array must be send by AUNO the resend to it.
byte[] OUT = new byte[12];
byte lamp = 0; // The index of lamp type array, and the indecation of the lamp type in the OUT array ti the AUNO.
string[] lampType = { "ENERGY SAVER", "TUNGSTEN", "FLUORESCENT", "METAL HALIDE" }; // Array for lamp type identification.
int sample; // The index of the report matrix, and giving number of test we did.
int[] endsample = new int [12]; //index array for saving the ended sample date.
int reportlenth = 3; // lenth of reporting arrays
string[] smplNo = new string[3]; //Array for sample number reporting.
string[] smpltype = new string[3]; // Array for sample lamp type reporting.
string[] startdate = new string[3]; // Array for sample starting date reporting.
string[] enddate = new string[3]; // Array for sample ending date reporting.
public Form1()
{
InitializeComponent();
// getportnames();
//serialPort1.Open();
}
// void getportnames()
//{
// string[] port = SerialPort.GetPortNames();
//PortcomboBox1.Items.AddRange(port);
// }
void warning(string warning) // Worning message properties.
{
MessageBox.Show(warning, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1.Open();
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
serialPort1.Close();
}
private void lamptype_SelectedIndexChanged(object sender, EventArgs e) // Projection the combo box of lamp type to the OUT Array
{
if (lamptype.SelectedIndex == 0)
{ lamp = 1; }
else if (lamptype.SelectedIndex == 1)
{ lamp = 2; }
else if (lamptype.SelectedIndex == 2)
{ lamp = 3; }
else if (lamptype.SelectedIndex == 3)
{ lamp = 4; }
else if (lamptype.SelectedIndex == -1)
{ lamp = 0; }
}
private void out1_CheckedChanged_1(object sender, EventArgs e)
{
if (out1.Checked)
{// If check box selected change its properties
out1.Font = new Font(out1.Font, FontStyle.Bold);
//Change text box properties.
sampleno1.Clear();
sampleno1.Enabled = true;
//Change text box properties.
enddate1.Clear();
datetime1.Clear();
lamptype1.Clear();
}
else {// unless reset the check box
out1.Font = new Font(out1.Font, FontStyle.Regular);
//Change text box properties.
sampleno1.Enabled = false;
// Reset the lamp type selection.
lamptype.SelectedIndex = -1;
lamptype.Text = "__Select lamp type__";
}
//
serialPort1.Write(OUT, 0, 12);
}
private void run1_Click_1(object sender, EventArgs e)
{//Check if any data are not marked give wornings.
if (out1.Checked == false) { warning("Select output"); }
else if (lamptype.SelectedIndex < 0) { warning("Select Lamp Type"); }
else if (String.IsNullOrEmpty(sampleno1.Text)) { warning("Enter sample number"); }
else if (sampleno1.TextLength != 10) { warning("Enter sample number correctly"); }
else
{// If yes change check box properties
out1.Enabled = false;
// Change run button properties
run1.Text = "In Use";
run1.Enabled = false;
run1.BackColor = Color.LightGreen;
run1.Font = new Font(run1.Font, FontStyle.Bold);
// Change text box properties
sampleno1.Enabled = false;
// Change stop button properties
stop1.Enabled = true;
stop1.BackColor = Color.OrangeRed;
stop1.Font = new Font(stop1.Font, FontStyle.Bold);
// Marking lamp type na d aoth data in text bos and reset lamp type combo box
lamptype1.Text = lampType[lamp - 1];
lamptype.Text = "__Select lamp type__";
// Show the starting date.
datetime1.Text = DateTime.Now.ToString("dd/mm/yyyy, hh:mm:ss");
// Save the sample data.
smplNo[sample] = sampleno1.Text; // Save the sample number.
smpltype[sample] = lamptype1.Text; // Save the lamp type date.
startdate[sample] = datetime1.Text; // Save the starting date.
// Save the reporting index for the ending date.
endsample[0] = sample;
// Increase the reporting index to give the sample counter and show it.
sample++;
MessageBox.Show("This is test no. " + sample);
// Worning to reset the saving data arraies. the reset it.
if (sample == reportlenth - 1)
{ warning("Only 1 more sample and the reporting system will reset, please inform the responsible"); }
else if (sample == reportlenth)
{ warning("The reporting system will reset, please inform the responsible");
sample = 0; }
//******************************************************************************//
// Set the output lamp type in the OUT array for AUNO.
OUT[0] = lamp;
}
//
//serialPort1.WriteLine("$");
serialPort1.Write(OUT, 0, 12);
}
You can use this part for c# part:
Connect();
if (serialPort1.IsOpen)
{
int MyInt = ToInt32(lblFirstNumber.Text);
byte[] b = GetBytes(MyInt);
serialPort1.Write(b, 0, 1);
int MyInt2 = ToInt32(txtFirstNumber.Text);
byte[] z = GetBytes(MyInt2);
serialPort1.Write(z, 0, 1);
int MyInt3 = ToInt32(txtSecondNumber.Text);
byte[] p = GetBytes(MyInt3);
serialPort1.Write(p, 0, 1);
serialPort1.Close();
}
else
{
MessageBox.Show("Please control your connection");
}

How to get array data in correct sequence from serial port in C#

My purpose in below program is getting 16 bytes of data from microcontroller and processing data for appropriate instructions. There are a lot of related questions and answers here but I couldnt find anything about in below issue. I can get 16 bytes from MCU. Values of bytes are correct and I can see them in dataGridView but the sequence of bytes is changing . For example at first MCUData[0] = 0x01 , MCUData[1] = 0xFE , MCUData[2] = 0xCC then it changes to MCUData[0] = 0xFE , MCUData[1] = 0xCC , MCUData[2] = 0x01. İt is like some problem shifting my datas in byte array. I am sure my MCU is sending data correctly because I checked in one of serial terminal program. My code is in below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace SerialCommunicationMCU
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
dataGridView1.Columns.Add("MCUData", "Byte Name");
dataGridView1.Columns.Add("MCUData", "Byte Value");
}
public System.IO.Ports.SerialPort SerialPc;
#region Variables
public string AvailablePort;
public string[] Ports = SerialPort.GetPortNames();
byte[] MCUData = new byte[16];
#endregion
private void Connect_Click(object sender, EventArgs e)
{
DataGreedByteNameShow();
SerialConnectandRead();
ConnectButton.Enabled = false;
DisconnectButton.Enabled = true;
}
private void Disconnect_Click(object sender, EventArgs e)
{
SerialPc.Close();
ConnectButton.Enabled = true;
DisconnectButton.Enabled = false;
}
public void SerialConnectandRead()
{
SerialPc = new SerialPort(AvailablePort, 115200, Parity.None, 8, StopBits.One);
try
{
SerialPc.Open();
SerialPc.DataReceived += new SerialDataReceivedEventHandler(SerialPc_DataReceived);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Serial Port Error");
}
}
private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPc.DiscardNull = false;
SerialPc.Read(MCUData, 0, 16);
SerialPc.ReceivedBytesThreshold = 16;
DataGreedByteValueShow();
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (string port in Ports)
{
comboBox1.Items.Add(port);
}
DisconnectButton.Enabled = false;
}
public void DataGreedByteNameShow()
{
dataGridView1.Rows.Add("MCUData[0]");
dataGridView1.Rows.Add("MCUData[1]");
dataGridView1.Rows.Add("MCUData[2]");
dataGridView1.Rows.Add("MCUData[3]");
dataGridView1.Rows.Add("MCUData[4]");
dataGridView1.Rows.Add("MCUData[5]");
dataGridView1.Rows.Add("MCUData[6]");
dataGridView1.Rows.Add("MCUData[7]");
dataGridView1.Rows.Add("MCUData[8]");
dataGridView1.Rows.Add("MCUData[9]");
dataGridView1.Rows.Add("MCUData[10]");
dataGridView1.Rows.Add("MCUData[11]");
dataGridView1.Rows.Add("MCUData[12]");
dataGridView1.Rows.Add("MCUData[13]");
dataGridView1.Rows.Add("MCUData[14]");
dataGridView1.Rows.Add("MCUData[15]");
}
private void DataGreedByteValueShow()
{
dataGridView1.Rows[0].Cells[1].Value = MCUData[0];
dataGridView1.Rows[1].Cells[1].Value = MCUData[1];
dataGridView1.Rows[2].Cells[1].Value = MCUData[2];
dataGridView1.Rows[3].Cells[1].Value = MCUData[3];
dataGridView1.Rows[4].Cells[1].Value = MCUData[4];
dataGridView1.Rows[5].Cells[1].Value = MCUData[5];
dataGridView1.Rows[6].Cells[1].Value = MCUData[6];
dataGridView1.Rows[7].Cells[1].Value = MCUData[7];
dataGridView1.Rows[8].Cells[1].Value = MCUData[8];
dataGridView1.Rows[9].Cells[1].Value = MCUData[9];
dataGridView1.Rows[10].Cells[1].Value = MCUData[10];
dataGridView1.Rows[11].Cells[1].Value = MCUData[11];
dataGridView1.Rows[12].Cells[1].Value = MCUData[12];
dataGridView1.Rows[13].Cells[1].Value = MCUData[13];
dataGridView1.Rows[14].Cells[1].Value = MCUData[14];
dataGridView1.Rows[15].Cells[1].Value = MCUData[15];
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
AvailablePort = comboBox1.SelectedItem.ToString();
}
}
}
According to the MSDN documentation: http://msdn.microsoft.com/en-us/library/ms143549(v=vs.110).aspx
Reads a number of bytes from the SerialPort input buffer and writes
those bytes into a byte array at the specified offset.
public int Read(
byte[] buffer,
int offset,
int count
)
Here's how your current code uses the function:
SerialPc.Read(MCUData, 0, 16);
Your buffer is a global variable defined as:
byte[] MCUData = new byte[16];
This is one way that you can use to solve your problem:
List<byte> MCUDataOverTime = new List<byte>();
private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPc.DiscardNull = false;
SerialPc.Read(MCUData, 0, 16);
MCUDataOverTime.AddRange(MCUData);
SerialPc.ReceivedBytesThreshold = 16;
DataGreedByteValueShow();
}
private void DataGreedByteValueShow()
{
if (MCUDataOverTime.Count >= 16)
{
dataGridView1.Rows[0].Cells[1].Value = MCUDataOverTime[0];
dataGridView1.Rows[1].Cells[1].Value = MCUDataOverTime[1];
dataGridView1.Rows[2].Cells[1].Value = MCUDataOverTime[2];
dataGridView1.Rows[3].Cells[1].Value = MCUDataOverTime[3];
dataGridView1.Rows[4].Cells[1].Value = MCUDataOverTime[4];
dataGridView1.Rows[5].Cells[1].Value = MCUDataOverTime[5];
dataGridView1.Rows[6].Cells[1].Value = MCUDataOverTime[6];
dataGridView1.Rows[7].Cells[1].Value = MCUDataOverTime[7];
dataGridView1.Rows[8].Cells[1].Value = MCUDataOverTime[8];
dataGridView1.Rows[9].Cells[1].Value = MCUDataOverTime[9];
dataGridView1.Rows[10].Cells[1].Value = MCUDataOverTime[10];
dataGridView1.Rows[11].Cells[1].Value = MCUDataOverTime[11];
dataGridView1.Rows[12].Cells[1].Value = MCUDataOverTime[12];
dataGridView1.Rows[13].Cells[1].Value = MCUDataOverTime[13];
dataGridView1.Rows[14].Cells[1].Value = MCUDataOverTime[14];
dataGridView1.Rows[15].Cells[1].Value = MCUDataOverTime[15];
}
}
The code above would solve the problem where your values change over time. It's happening in the first place because every time SerialPc_DataReceived() is called, you've set it so that every "Read" will store its result in your MCUData byte array. Consequently, it will end up overwriting your MCUData array since you've hardcoded the start-from offset to 0.
That's why it looks like your data is being shifted. You have to understand, fundamentally, these streams don't conveniently store data for you in the way where an index of 0 means the beginning of time (when the stream first opened and started). If you want it to work that way, you'll have to store it yourself.
Please note that the code above does not attempt to empty the serial input buffer. You're pulling 16 bytes every time you do a read when the DataReceived is called, but I wonder if the MCU is sending a lot more than that with every DataReceived message.
Edit:
List<byte> MCUDataOverTime = new List<byte>();
private void SerialPc_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPc.DiscardNull = false;
int readcount = 0;
byte [] temp;
do
{
readcount = SerialPc.Read(MCUData, 0, 16);
if (readcount > 0)
{
temp = new byte[readcount];
Array.Copy(MCUData, 0, temp, 0, readcount);
MCUDataOverTime.AddRange(temp);
SerialPc.ReceivedBytesThreshold = 16;
DataGreedByteValueShow();
}
} while (readcount > 0);
}
private void DataGreedByteValueShow()
{
if (MCUDataOverTime.Count >= 16)
{
dataGridView1.Rows[0].Cells[1].Value = MCUDataOverTime[0];
dataGridView1.Rows[1].Cells[1].Value = MCUDataOverTime[1];
dataGridView1.Rows[2].Cells[1].Value = MCUDataOverTime[2];
dataGridView1.Rows[3].Cells[1].Value = MCUDataOverTime[3];
dataGridView1.Rows[4].Cells[1].Value = MCUDataOverTime[4];
dataGridView1.Rows[5].Cells[1].Value = MCUDataOverTime[5];
dataGridView1.Rows[6].Cells[1].Value = MCUDataOverTime[6];
dataGridView1.Rows[7].Cells[1].Value = MCUDataOverTime[7];
dataGridView1.Rows[8].Cells[1].Value = MCUDataOverTime[8];
dataGridView1.Rows[9].Cells[1].Value = MCUDataOverTime[9];
dataGridView1.Rows[10].Cells[1].Value = MCUDataOverTime[10];
dataGridView1.Rows[11].Cells[1].Value = MCUDataOverTime[11];
dataGridView1.Rows[12].Cells[1].Value = MCUDataOverTime[12];
dataGridView1.Rows[13].Cells[1].Value = MCUDataOverTime[13];
dataGridView1.Rows[14].Cells[1].Value = MCUDataOverTime[14];
dataGridView1.Rows[15].Cells[1].Value = MCUDataOverTime[15];
}
}
I'd increase the size of MCUData to 1024 bytes or more since 16 bytes seems kind of small. The next thing that you'd need to do is keep track of the start and end points of each frame. I'm guessing that it'll always be 16 in the case of your microcontroller but in general you should have the microcontroller throwing out null values or a special string of symbols to indicate the end of a message.

Recording with AudioQueue and Monotouch static sound

I have written a small program in MonoTouch to record sound from the mic of my iPhone 4s using an InputAudioQueue.
I save the recorded data in an array and feed this buffer to the my audio player for playback (using OutputAudioQueue).
When playing back it's just some stuttering garbage / static sound. I have tried filling the buffer with sin waves before playback and then it sounds good, so I guess the problem is in the recording, not the playback. Can anyone help me see what is wrong? (Code below)
public class AQRecorder
{
private const int CountAudioBuffers = 3;
private const int AudioBufferLength = 22050;
private const int SampleRate = 44100;
private const int BitsPerChannel = 16;
private const int Channels = 1;
private const int MaxRecordingTime = 5;
private AudioStreamBasicDescription audioStreamDescription;
private InputAudioQueue inputQueue;
private short[] rawData;
private int indexNextRawData;
public AQRecorder ()
{
this.audioStreamDescription.Format = AudioFormatType.LinearPCM;
this.audioStreamDescription.FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger |
AudioFormatFlags.LinearPCMIsPacked;
this.audioStreamDescription.SampleRate = AQRecorder.SampleRate;
this.audioStreamDescription.BitsPerChannel = AQRecorder.BitsPerChannel;
this.audioStreamDescription.ChannelsPerFrame = AQRecorder.Channels;
this.audioStreamDescription.BytesPerFrame = (AQRecorder.BitsPerChannel / 8) * AQRecorder.Channels;
this.audioStreamDescription.FramesPerPacket = 1;
this.audioStreamDescription.BytesPerPacket = audioStreamDescription.BytesPerFrame * audioStreamDescription.FramesPerPacket;
this.audioStreamDescription.Reserved = 0;
}
public void Start ()
{
int totalBytesToRecord = this.audioStreamDescription.BytesPerFrame * AQRecorder.SampleRate * AQRecorder.MaxRecordingTime;
this.rawData = new short[totalBytesToRecord / sizeof(short)];
this.indexNextRawData = 0;
this.inputQueue = SetupInputQueue (this.audioStreamDescription);
this.inputQueue.Start ();
}
public void Stop ()
{
if (this.inputQueue.IsRunning)
{
this.inputQueue.Stop (true);
}
}
public short[] GetData ()
{
return this.rawData;;
}
private InputAudioQueue SetupInputQueue (AudioStreamBasicDescription audioStreamDescription)
{
InputAudioQueue inputQueue = new InputAudioQueue (audioStreamDescription);
for (int count = 0; count < AQRecorder.CountAudioBuffers; count++)
{
IntPtr bufferPointer;
inputQueue.AllocateBuffer(AQRecorder.AudioBufferLength, out bufferPointer);
inputQueue.EnqueueBuffer(bufferPointer, AQRecorder.AudioBufferLength, null);
}
inputQueue.InputCompleted += HandleInputCompleted;
return inputQueue;
}
private void HandleInputCompleted (object sender, InputCompletedEventArgs e)
{
unsafe
{
short* shortPtr = (short*)e.IntPtrBuffer;
for (int count = 0; count < AQRecorder.AudioBufferLength; count += sizeof(short))
{
if (indexNextRawData >= this.rawData.Length)
{
this.inputQueue.Stop (true);
return;
}
this.rawData [indexNextRawData] = *shortPtr;
indexNextRawData++;
shortPtr++;
}
}
this.inputQueue.EnqueueBuffer(e.IntPtrBuffer, AQRecorder.AudioBufferLength, null);
}
}
ok, this might be too late, but I had the same problem with hearing garbage sound only and found the solution.
You cannot read the audio data directly from e.IntPtrBuffer. This pointer is a pointer to a AudioQueueBuffer object and not to the audio data itself. So to read the audio data you can make use of the e.UnsafeBuffer which gives you the access to this object and use its AudioData pointer. This is a IntPtr which you can cast (in unsafe context) to a byte* or short* and you have your audio data.
Best regards
Alex

Categories