Where to retrieve audio file? -- Arduino - Photon project - node.js

I have just started with electronics, and doing a project using the Spark Photon, which is based on Arduino. The project website is here: http://hackster.io/middleca/sending-sound-over-the-internet
I uploaded the following two files (.ino and .js) to the Photon, which should then capture and transmit sound (directly I assume). I expected a test.wav would be created. However, where should I find this file so I can check if everything worked?
main.ino file:
#define MICROPHONE_PIN A5
#define AUDIO_BUFFER_MAX 8192
int audioStartIdx = 0, audioEndIdx = 0;
uint16_t audioBuffer[AUDIO_BUFFER_MAX];
uint16_t txBuffer[AUDIO_BUFFER_MAX];
// version without timers
unsigned long lastRead = micros();
char myIpAddress[24];
TCPClient audioClient;
TCPClient checkClient;
TCPServer audioServer = TCPServer(3443);
void setup() {
Serial.begin(115200);
pinMode(MICROPHONE_PIN, INPUT);
// so we know where to connect, try:
// particle get MY_DEVICE_NAME ipAddress
Spark.variable("ipAddress", myIpAddress, STRING);
IPAddress myIp = WiFi.localIP();
sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
// 1/8000th of a second is 125 microseconds
audioServer.begin();
lastRead = micros();
}
void loop() {
checkClient = audioServer.available();
if (checkClient.connected()) {
audioClient = checkClient;
}
//listen for 100ms, taking a sample every 125us,
//and then send that chunk over the network.
listenAndSend(100);
}
void listenAndSend(int delay) {
unsigned long startedListening = millis();
while ((millis() - startedListening) < delay) {
unsigned long time = micros();
if (lastRead > time) {
// time wrapped?
//lets just skip a beat for now, whatever.
lastRead = time;
}
//125 microseconds is 1/8000th of a second
if ((time - lastRead) > 125) {
lastRead = time;
readMic();
}
}
sendAudio();
}
// Callback for Timer 1
void readMic(void) {
uint16_t value = analogRead(MICROPHONE_PIN);
if (audioEndIdx >= AUDIO_BUFFER_MAX) {
audioEndIdx = 0;
}
audioBuffer[audioEndIdx++] = value;
}
void copyAudio(uint16_t *bufferPtr) {
//if end is after start, read from start->end
//if end is before start, then we wrapped, read from start->max, 0->end
int endSnapshotIdx = audioEndIdx;
bool wrapped = endSnapshotIdx < audioStartIdx;
int endIdx = (wrapped) ? AUDIO_BUFFER_MAX : endSnapshotIdx;
int c = 0;
for(int i=audioStartIdx;i<endIdx;i++) {
// do a thing
bufferPtr[c++] = audioBuffer[i];
}
if (wrapped) {
//we have extra
for(int i=0;i<endSnapshotIdx;i++) {
// do more of a thing.
bufferPtr[c++] = audioBuffer[i];
}
}
//and we're done.
audioStartIdx = audioEndIdx;
if (c < AUDIO_BUFFER_MAX) {
bufferPtr[c] = -1;
}
}
// Callback for Timer 1
void sendAudio(void) {
copyAudio(txBuffer);
int i=0;
uint16_t val = 0;
if (audioClient.connected()) {
write_socket(audioClient, txBuffer);
}
else {
while( (val = txBuffer[i++]) < 65535 ) {
Serial.print(val);
Serial.print(',');
}
Serial.println("DONE");
}
}
// an audio sample is 16bit, we need to convert it to bytes for sending over the network
void write_socket(TCPClient socket, uint16_t *buffer) {
int i=0;
uint16_t val = 0;
int tcpIdx = 0;
uint8_t tcpBuffer[1024];
while( (val = buffer[i++]) < 65535 ) {
if ((tcpIdx+1) >= 1024) {
socket.write(tcpBuffer, tcpIdx);
tcpIdx = 0;
}
tcpBuffer[tcpIdx] = val & 0xff;
tcpBuffer[tcpIdx+1] = (val >> 8);
tcpIdx += 2;
}
// any leftovers?
if (tcpIdx > 0) {
socket.write(tcpBuffer, tcpIdx);
}
}
and the waveRecorder.js file:
// make sure you have Node.js Installed!
// Get the IP address of your photon, and put it here:
// CLI command to get your photon's IP address
//
// particle get MY_DEVICE_NAME ipAddress
// Put your IP here!
var settings = {
ip: "192.168.0.54",
port: 3443
};
/**
* Created by middleca on 7/18/15.
*/
//based on a sample from here
// http://stackoverflow.com/questions/19548755/nodejs-write-binary-data-into-writablestream-with-buffer
var fs = require("fs");
var samplesLength = 1000;
var sampleRate = 8000;
var outStream = fs.createWriteStream("test.wav");
var writeHeader = function() {
var b = new Buffer(1024);
b.write('RIFF', 0);
/* file length */
b.writeUInt32LE(32 + samplesLength * 2, 4);
//b.writeUint32LE(0, 4);
b.write('WAVE', 8);
/* format chunk identifier */
b.write('fmt ', 12);
/* format chunk length */
b.writeUInt32LE(16, 16);
/* sample format (raw) */
b.writeUInt16LE(1, 20);
/* channel count */
b.writeUInt16LE(1, 22);
/* sample rate */
b.writeUInt32LE(sampleRate, 24);
/* byte rate (sample rate * block align) */
b.writeUInt32LE(sampleRate * 2, 28);
/* block align (channel count * bytes per sample) */
b.writeUInt16LE(2, 32);
/* bits per sample */
b.writeUInt16LE(16, 34);
/* data chunk identifier */
b.write('data', 36);
/* data chunk length */
//b.writeUInt32LE(40, samplesLength * 2);
b.writeUInt32LE(0, 40);
outStream.write(b.slice(0, 50));
};
writeHeader(outStream);
var net = require('net');
console.log("connecting...");
client = net.connect(settings.port, settings.ip, function () {
client.setNoDelay(true);
client.on("data", function (data) {
try {
console.log("GOT DATA");
outStream.write(data);
//outStream.flush();
console.log("got chunk of " + data.toString('hex'));
}
catch (ex) {
console.error("Er!" + ex);
}
});
});
setTimeout(function() {
console.log('recorded for 10 seconds');
client.end();
outStream.end();
process.exit(0);
}, 10 * 1000);

Thieme! Such a beginner's question... SO unworthy!
Anyway, I will iron my heart and tell you the answer.
First of all, you misunderstood: the .ino file should go to the Photon and the waveRecorder.js file should be stored on your computer (or server) and called whenever you want to retrieve the audio. As you can read in the code, the .ino file makes sure that every millisecond it will check if something wants to connect, and if so, it will stream the sound to the wav.file stored in the same location as your waveRecorder.js file. "Something wants to connect" happens when you launch waveRecorder.js. Make sure you have node installed.
So, to sum it up:
Download the two files (main.ino and waveRecorder.js) to your computer in a folder ../xx/folderName
Then configure the IPAddress in both files using your photon's IPAddress
Upload main.ino to the photon (type 'particle flash abcdefgh123456578 "xx/../folderName/main.ino"' in the terminal)
Then run waveRecorder.js by typing 'node "xx/../folderName/waveRecorder.js"' in your terminal.
That should do it.. Even I got it working :)

Related

Accelerometer data over BLE are not sent in synch

I am sending temperature, humidity, pressure and accelerometer data over BLE, from Arduino (peripheral) to Raspberry Pi 4 (central). I created BLE characteristic per each acceleration dimension (accX, accY, accZ), and I am subscribing to these characteristics.
However, I put counter for each characteristic and realized that data are not sent in order:
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] x = 233
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] y = 230
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] z = 236
So x is read 233 times while y 230 times vice versa. In ideal scenario, they all should be same.
I am posting my full Arduino code minus comments, hence I believe it might be needed:
#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>
#include <Arduino_LPS22HB.h>
#include <Arduino_LSM9DS1.h>
#define BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE "181A"
#define BLE_UUID_TEMPERATURE "2A6E"
#define BLE_UUID_HUMIDITY "2A6F"
#define BLE_UUID_PRESSURE "2A6D"
#define BLE_UUID_ACCELEROMETER_SERVICE "1101"
#define BLE_UUID_ACCELEROMETER_X "2101"
#define BLE_UUID_ACCELEROMETER_Y "2102"
#define BLE_UUID_ACCELEROMETER_Z "2103"
#define BLE_DEVICE_NAME "Hako"
#define BLE_LOCAL_NAME "Hako"
BLEService environmentalSensingService(BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE);
BLEService accelerometerService(BLE_UUID_ACCELEROMETER_SERVICE);
BLEShortCharacteristic temperatureCharacteristic(BLE_UUID_TEMPERATURE, BLERead | BLENotify);
BLEUnsignedShortCharacteristic humidityCharacteristic(BLE_UUID_HUMIDITY, BLERead | BLENotify);
BLEUnsignedLongCharacteristic pressureCharacteristic(BLE_UUID_PRESSURE, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_X(BLE_UUID_ACCELEROMETER_X, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_Y(BLE_UUID_ACCELEROMETER_Y, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_Z(BLE_UUID_ACCELEROMETER_Z, BLERead | BLENotify);
#define ENV_SENSOR_UPDATE_INTERVAL (1000)
#define ACC_SENSOR_UPDATE_INTERVAL (1000)
typedef struct __attribute__((packed))
{
float temperature;
float humidity;
float pressure;
bool updated = false;
} env_sensor_data_t;
env_sensor_data_t envSensorData;
typedef struct __attribute__((packed))
{
float accX;
float accY;
float accZ;
bool updated = false;
} acc_sensor_data_t;
acc_sensor_data_t accSensorData;
#define BLE_LED_PIN LED_BUILTIN
void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println( "BLE Example - Environmental Sensing Service (ESS)" );
pinMode( BLE_LED_PIN, OUTPUT );
digitalWrite( BLE_LED_PIN, LOW );
// Without Serial when using USB power bank HTS sensor seems to needs some time for setup
delay(10);
if (!HTS.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while (1);
}
if (!BARO.begin()) {
Serial.println( "Failed to initialize pressure sensor!" );
while (1);
}
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
if (!setupBleMode()) {
while (1);
}
else {
Serial.println( "BLE initialized. Waiting for clients to connect." );
}
}
void loop() {
bleTask();
if (envSensorTask()) {
envPrintTask();
}
if (accSensorTask()) {
accPrintTask();
}
}
bool envSensorTask() {
static long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis < ENV_SENSOR_UPDATE_INTERVAL) {
return false;
}
previousMillis = currentMillis;
envSensorData.temperature = HTS.readTemperature();
envSensorData.humidity = HTS.readHumidity();
envSensorData.pressure = BARO.readPressure() * 1000; // kPa -> Pa
envSensorData.updated = true;
return envSensorData.updated;
}
bool accSensorTask() {
static long previousMillis2 = 0;
unsigned long currentMillis2 = millis();
float x = 0.00, y = 0.00, z = 0.00;
if (currentMillis2 - previousMillis2 < ACC_SENSOR_UPDATE_INTERVAL) {
return false;
}
previousMillis2 = currentMillis2;
if(IMU.accelerationAvailable()){
IMU.readAcceleration(x, y, z);
accSensorData.accX = x;
accSensorData.accY = y;
accSensorData.accZ = z;
accSensorData.updated = true;
}
return accSensorData.updated;
}
bool setupBleMode() {
if (!BLE.begin()) {
return false;
}
BLE.setDeviceName(BLE_DEVICE_NAME);
BLE.setLocalName(BLE_LOCAL_NAME);
BLE.setAdvertisedService(environmentalSensingService);
BLE.setAdvertisedService(accelerometerService);
environmentalSensingService.addCharacteristic(temperatureCharacteristic);
environmentalSensingService.addCharacteristic(humidityCharacteristic);
environmentalSensingService.addCharacteristic(pressureCharacteristic);
accelerometerService.addCharacteristic(accelerometerCharacteristic_X);
accelerometerService.addCharacteristic(accelerometerCharacteristic_Y);
accelerometerService.addCharacteristic(accelerometerCharacteristic_Z);
BLE.addService(environmentalSensingService);
BLE.addService(accelerometerService);
temperatureCharacteristic.writeValue(0);
humidityCharacteristic.writeValue(0);
pressureCharacteristic.writeValue(0);
accelerometerCharacteristic_X.writeValue(0);
accelerometerCharacteristic_Y.writeValue(0);
accelerometerCharacteristic_Z.writeValue(0);
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
BLE.advertise();
return true;
}
void bleTask()
{
const uint32_t BLE_UPDATE_INTERVAL = 10;
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis();
if (currentMillis - previousMillis >= BLE_UPDATE_INTERVAL) {
previousMillis = currentMillis;
BLE.poll();
}
if (envSensorData.updated) {
// BLE defines Temperature UUID 2A6E Type sint16 ( see XML links )
// Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius
int16_t temperature = round(envSensorData.temperature * 100.0);
temperatureCharacteristic.writeValue(temperature);
// BLE defines Humidity UUID 2A6F Type uint16
// Unit is in percent with a resolution of 0.01 percent
uint16_t humidity = round(envSensorData.humidity * 100.0);
humidityCharacteristic.writeValue(humidity);
// BLE defines Pressure UUID 2A6D Type uint32
// Unit is in Pascal with a resolution of 0.1 Pa
uint32_t pressure = round(envSensorData.pressure * 10.0);
pressureCharacteristic.writeValue(pressure);
envSensorData.updated = false;
}
if (accSensorData.updated) {
// BLE does not define accelerometer UUID
// Alls units is in G
int16_t accelerometer_X = round(accSensorData.accX * 100.0);
accelerometerCharacteristic_X.writeValue(accelerometer_X);
int16_t accelerometer_Y = round(accSensorData.accY * 100.0);
accelerometerCharacteristic_Y.writeValue(accelerometer_Y);
int16_t accelerometer_Z = round(accSensorData.accZ * 100.0);
accelerometerCharacteristic_Z.writeValue(accelerometer_Z);
envSensorData.updated = false;
}
}
void envPrintTask() {
Serial.print( "Temperature = " );
Serial.print( envSensorData.temperature );
Serial.println( " °C" );
Serial.print( "Humidity = " );
Serial.print( envSensorData.humidity );
Serial.println( " %" );
Serial.print( "Pressure = " );
Serial.print( envSensorData.pressure );
Serial.println( " Pa" );
Serial.print(temperatureCharacteristic.subscribed());
Serial.print(humidityCharacteristic.subscribed());
Serial.println(pressureCharacteristic.subscribed());
}
void accPrintTask() {
Serial.print("AccX = ");
Serial.print(accSensorData.accX);
Serial.println(" G");
Serial.print("AccY = ");
Serial.print(accSensorData.accY);
Serial.println(" G");
Serial.print("AccZ = ");
Serial.print( accSensorData.accZ );
Serial.println(" G");
Serial.print(accelerometerCharacteristic_X.subscribed());
Serial.print(accelerometerCharacteristic_Y.subscribed());
Serial.println(accelerometerCharacteristic_Z.subscribed());
}
void blePeripheralConnectHandler(BLEDevice central) {
digitalWrite(BLE_LED_PIN, HIGH);
Serial.print(F( "Connected to central: " ));
Serial.println(central.address());
}
void blePeripheralDisconnectHandler( BLEDevice central ) {
digitalWrite(BLE_LED_PIN, LOW);
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
I am reading the data on Pi via in Node.js environment via #abandonware/noble library.
I will only post the related part, where I subscribe to characteristics first, then I read the data. You can see the counters at the end.
for (const [key, character] of Object.entries(ALL.characteristics)) {
// Check the notify bit, if not set, set it. //
if (character.properties.includes("notify")) {
const descriptors = await character.discoverDescriptorsAsync().catch(e => send(e));
for (const [key, descriptor] of Object.entries(descriptors)) {
node.log(descriptor);
let descriptorData = await descriptor.readValueAsync().catch(e => send(e));
if (descriptorData[0] === bufferChecker[0] || descriptorData[1] === bufferChecker [1]) {
node.log(`The ${character.name} ${character.uuid} notify bit is disabled.`);
node.log("Enabling notification bit...");
descriptor.writeValueAsync(notifySetter).catch(e => send(e));
node.log (`Notification for ${character.name} characteristic is enabled.`);
} else {
node.log(`The ${character.name} ${character.uuid} notify bit is already enabled.`);
return;
}
}
} else {
node.log(`Notification is not allowed for ${character.name} characteristic.`)
}
}
for (const [key, character] of Object.entries(ALL.characteristics)) {
character.on('data', (data) => {
if (character.uuid === '2a6d') {
data = data.readUInt32LE() * decimalSetter[1];
environmentalData.payload[character.name] = data.toFixed(2);
counterPres++;
} else if (character.uuid === '2a6e') {
data = data.readUInt16LE() * decimalSetter[0];
environmentalData.payload[character.name] = data.toFixed(2);
counterTemp++;
} else if (character.uuid === '2a6f') {
data = data.readUInt16LE() * decimalSetter[0];
environmentalData.payload[character.name] = data.toFixed(2);
counterHum++;
} else if (character.uuid === '2101') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccX++;
} else if (character.uuid === '2102') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccY++;
} else if (character.uuid === '2103') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccZ++;
}
node.log("x = " + counterAccX);
node.log("y = " + counterAccY);
node.log("z = " + counterAccZ);
// Sends Temp., Hum., and Pres. data together.
if ( (counterHum + counterPres + counterTemp) % 3 == 0 && (counterHum + counterPres + counterTemp) !== 0){
send(environmentalData);
}
});
// Character data event listener END //
}
I asked the same question at Arduino forum as well.
The peripherals GATT server only sends data if the measured value has really changed. This behaviour saves energy and bandwidth. I think your observation is therefore perfectly normal.

How to get the output with console app and display it to MFC Dialog StaticText

I am working on a MFC app that need to get the same output with the console app. The console app can display the input data from serial port. I want to get the input with the MFC dialog app and display it into edit control box. Since I am still new to C++, it seems quite challenging to me. Any suggestions for the workaround? Thanks in advance!
The console app code:
enum { EOF_Char = 27 };
int ShowError (LONG lError, LPCTSTR lptszMessage)
{
// Generate a message text
TCHAR tszMessage[256];
wsprintf(tszMessage,_T("%s\n(error code %d)"), lptszMessage, lError);
return 1;
}
int __cdecl _tmain (int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
lLastError = serial.Open(_T("COM1"), 0, 0, false);
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8,CSerial::EParNone, CSerial::EStop1);
lLastError = serial.SetupHandshaking(CSerial::EHandshakeHardware);
// ** The query command to get input data **
lLastError = serial.Write(":MEAS:FREQuency?\n");
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRLSD |
CSerial::EEventRecv);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port event mask"));
// Use 'non-blocking' reads,cuz we don't know how many bytes will be received.
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port read timeout."));
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to wait for a COM-port event."));
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle break event
if (eEvent & CSerial::EEventBreak)
{ printf("\n### BREAK received ###\n"); }
// Handle CTS event
if (eEvent & CSerial::EEventCTS)
{ printf("\n### Clear to send %s ###\n", serial.GetCTS()?"on":"off"); }
// Handle error event
if (eEvent & CSerial::EEventError)
{
printf("\n### ERROR: ");
switch (serial.GetError())
{
case CSerial::EErrorBreak: printf("Break condition"); break;
case CSerial::EErrorMode: printf("Unsupported mode"); break;
case CSerial::EErrorOverrun: printf("Buffer overrun"); break;
case CSerial::EErrorTxFull: printf("Output buffer full"); break;
default: printf("Unknown"); break;
}
printf(" ###\n");
}
// Handle RLSD/CD event
if (eEvent & CSerial::EEventRLSD)
{ printf("\n### RLSD/CD %s ###\n", serial.GetRLSD()?"on":"off"); }
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to read from COM-port."));
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// **Display the data/Need the same output for EditBox**
printf("%s", szBuffer);
// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer,EOF_Char))
fContinue = false;
}
}
while (dwBytesRead == sizeof(szBuffer)-1);
}
}
while (fContinue);
// Close the port again
serial.Close();
return 0;
}
Since my knowledge in C++ was not good enough, so I was not aware of my problems were how to break the loop in the above code & the conversion between char array and CString. This is my answer :
void Singlemode::OnBnClickedButton3()
{
CString str3;
// TODO: Add your control notification handler code here
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
lLastError = serial.Open(_T("COM1"), 0, 0, false);
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);
lLastError = serial.SetupHandshaking(CSerial::EHandshakeHardware);
lLastError = serial.Write(":MEAS:FREQuency?\n");
// Register only for the receive event
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// Display the data
str3 = CString(szBuffer); // conversion to display
show_result.SetWindowText(str3);
fContinue = false; // break the loop
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);
}

vorbis_analysis generates access violation

I'm trying to create an .ogg file, but even the example code presented generates an Access Violation when calling vorbis_analysis().
I'm using a simplified version of this encoding Example. I have tried the full example as it is, but I get the same error at the same place.
The code below is the example simplified by filling the encoding buffer with a constant instead of a wav file. The hFile is a TStreamFile instance created elsewhere.
vorbis_info vi;
vorbis_dsp_state vd;
vorbis_comment vc;
vorbis_block vb;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
int res;
int len = 0;
int eos = 0;
int loop = 0;
vorbis_info_init(&vi);
res = vorbis_encode_init_vbr(&vi,2,44100,0.4f);
res = vorbis_encode_setup_init(&vi);
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc,"TITLE","Silent noise");
res = vorbis_analysis_init(&vd,&vi);
res = vorbis_block_init(&vd,&vb);
srand(time(NULL));
res = ogg_stream_init(&os,rand());
res = vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
res = ogg_stream_packetin(&os,&header);
res = ogg_stream_packetin(&os,&header_comm);
res = ogg_stream_packetin(&os,&header_code);
/* This ensures the actual
* audio data will start on a new page, as per spec
*/
while(ogg_stream_flush(&os,&og)) {
hFile->Write(og.header,og.header_len);
hFile->Write(og.body, og.body_len );
}
while(!eos) {
float **Buffer = vorbis_analysis_buffer(&vd,1024);
if(loop<10) {
for(int n=0; n<1024; n++) {
Buffer[0][n] = 1.0f;
Buffer[1][n] = 1.0f;
}
res = vorbis_analysis_wrote(&vd,1024);
loop++;
} else {
res = vorbis_analysis_wrote(&vd,0);
eos = true;
}
// Enough data?
while(vorbis_analysis_blockout(&vd,&vb) == 1) {
res = vorbis_analysis(&vb,&op); // <---- Access Violation
res = vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)) {
/* weld the packet into the bitstream */
res = ogg_stream_packetin(&os,&op);
/* write out pages (if any) */
while(!eos){
if(ogg_stream_pageout(&os,&og) == 0) {
break;
}
hFile->Write(og.header,og.header_len);
hFile->Write(og.body, og.body_len );
/* this could be set above, but for illustrative purposes, I do
it here (to show that vorbis does know where the stream ends) */
if(ogg_page_eos(&og)) {
eos=1;
}
}
}
}
}
res = ogg_stream_clear(&os);
res = vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
The first part runs fine, the header is created and saved to the stream. Then I just fill the buffer with 1.0 floats for test purposes.
When there is enough data available the call to vorbis_analysis always generate Access Violation at x write of address x
The variable res always indicate success all the way down to the access violation.
I'm using static linked libogg v1.3.2 and libvorbis 1.3.5

Ardunio, decoding a string at postion N

I'm having this little problem with some easy code, basically what I'm doing is sending information via the serial port via a program I wrote in Java. The information is getting their for basic statements (IE, can turn on lights and stuff) but I'm having errors getting it to decode strings with number values send to it.
So for example, I'm sending strings that look like this
BS//:+000/+000/+000
and the decoding method I'm using looks like this.
After adding the string via this:
if (inputString.startsWith("BS//:")) //**fixed
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
Sends it too...
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt();
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();
baseStepperTime = baseStepper.substring(15,18).toInt();
}
Which should decode and run
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
Problem seems to be that it doesn't decode... ideas I'm sort of lost at this stage. :/
(total past of the code, I know the information is getting there, just not compiling like it should.)
#include <Stepper.h>
//#include <HardwareSerial.h>
// int intensity = 0; // led intensity this is needed just as example for this sketch
String inputString = ""; // a string to hold incoming data (this is general code you can reuse)
boolean stringComplete = false; // whether the string is complete (this is general code you can reuse)
int stepsPerRevolution = 64; //at 5.625 degrees a step
// initialize the stepper library on pins 8 through 11:
Stepper baseStepper(stepsPerRevolution, 2,3,4,5); // protocols start with //BS:
Stepper shoulderStepper(stepsPerRevolution, 6,7,8,9); // protocols start with //SS:
Stepper armStepper(stepsPerRevolution, 10,11,12,13); // protocols start with //AS:
//--------baseStepper--------//
int baseStepperRotCount = 0; //how many rotations in the for loop is needed
int baseStepperRotStepSize = 0; // how large should the steps be...
int baseStepperTime = 0; //delay time needed between each step (delay); so the stepper can do it's work.
//--------shoulderStepper--------//
int shoulderStepperRotCount =0;
void setup() {
// initialize serial: (this is general code you can reuse)
Serial.begin(115200);
}
void loop() {
// when a newline arrives:
if (stringComplete) {
//these are test if statements, they serve no purpose after the intial boot, but must be included to test the connectivity;
if (inputString.startsWith("alpha"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
inputString = "";
stringComplete = false;
}
else if (inputString.startsWith("beta"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
inputString = "";
stringComplete = false;
}
//---------------------///
//these statements set the engines and prepare for running of the program.
if (inputString.startsWith("//BS:")) // "BS//:+000/+000/+000"
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
else if (inputString.startsWith("//SS:"))
{
//inputInfoToShoulderStepper();
//outputConfirmed();
}
else if (inputString.startsWith("//AS:"))
{
//inputInfoToArmStepper();
// outputConfirmed();
}
if(inputString.startsWith("alp://")) { // OK is a message I know (this is general code you can reuse)
boolean msgRecognized = true;
if(inputString.substring(6,10) == "kprs") { // KeyPressed }
msgRecognized = false; // this sketch doesn't know other messages in this case command is ko (not ok)
// Prepare reply message if caller supply a message id (this is general code you can reuse)
int idPosition = inputString.indexOf("?id=");
if(idPosition != -1) {
String id = inputString.substring(idPosition + 4);
// print the reply
Serial.print("alp://rply/");
if(msgRecognized) { // this sketch doesn't know other messages in this case command is ko (not ok)
Serial.print("ok?id=");
} else {
Serial.print("ko?id=");
}
Serial.print(id);
Serial.write(255); // End of Message
Serial.flush();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
}
}
/*
Send listen messages
int index = 0;
for (index = 0; index < digitalPinListeningNum; index++) {
if(digitalPinListening[index] == true) {
int value = digitalRead(index);
if(value != digitalPinListenedValue[index]) {
digitalPinListenedValue[index] = value;
Serial.print("alp://dred/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255);
Serial.flush();
}
}
}
for (index = 0; index < analogPinListeningNum; index++) {
if(analogPinListening[index] == true) {
int value = analogRead(index);
if(value != analogPinListenedValue[index]) {
analogPinListenedValue[index] = value;
Serial.print("alp://ared/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255); // End of Message
Serial.flush();
}
}
}
} */
//this method decodes and stores inputs
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt(); // B S / / : + 0 0 0 / + 0 0 0 / + 0 0 0
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
baseStepperTime = baseStepper.substring(15,18).toInt();
}
//this method runs the base stepper off the decoded actions.
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
This is general code you can reuse.
*/
void serialEvent() {
while (Serial.available() && !stringComplete) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

WinCE: How can I determine the module that contains a code address?

I wrote a solution that involved OpenProcess, EnumProcessModules, GetModuleInformation and GetModuleBaseName, but apparently EnumProcessModules and GetModuleBaseName do not exist in Windows CE! What alternative is there?
I found a way to do this with CreateToolhelp32Snapshot, Module32First, Module32Next, Process32First and Process32Next. First you have to get a list of modules, then search through the list of modules to find the desired address.
#include <Tlhelp32.h>
struct MyModuleInfo
{
BYTE* Base;
HMODULE Handle;
DWORD Size;
enum { MaxNameLen = 36 };
TCHAR Name[MaxNameLen];
};
bool GetModuleList(vector<MyModuleInfo>& moduleList)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE | TH32CS_GETALLMODS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
return false;
MODULEENTRY32 moduleInfo;
moduleInfo.dwSize = sizeof(moduleInfo);
if (Module32First(hSnapshot, &moduleInfo)) do {
MyModuleInfo myInfo;
myInfo.Handle = moduleInfo.hModule;
myInfo.Base = moduleInfo.modBaseAddr;
myInfo.Size = moduleInfo.modBaseSize;
memcpy(myInfo.Name, moduleInfo.szModule, min(sizeof(myInfo.Name), sizeof(moduleInfo.szModule)));
myInfo.Name[myInfo.MaxNameLen-1] = '\0';
moduleList.push_back(myInfo);
} while (Module32Next(hSnapshot, &moduleInfo));
// The module list obtained above only contains DLLs! To get the EXE files
// also, we must call Process32First and Process32Next in a loop.
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
if (Process32First(hSnapshot, &processInfo)) do {
MyModuleInfo myInfo;
myInfo.Handle = NULL; // No handle given
myInfo.Base = (BYTE*)processInfo.th32MemoryBase;
myInfo.Size = 0x800000; // No size provided! Allow max 8 MB
memcpy(myInfo.Name, processInfo.szExeFile, min(sizeof(myInfo.Name), sizeof(processInfo.szExeFile)));
myInfo.Name[myInfo.MaxNameLen-1] = '\0';
moduleList.push_back(myInfo);
} while(Process32Next(hSnapshot, &processInfo));
// Debug output
for (int i = 0; i < (int)moduleList.size(); i++) {
MyModuleInfo& m = moduleList[i];
TRACE(_T("%-30s: 0x%08x - 0x%08x\n"), m.Name, (DWORD)m.Base, (DWORD)m.Base + m.Size);
}
CloseToolhelp32Snapshot(hSnapshot);
return true;
}
const MyModuleInfo* GetModuleForAddress(vector<MyModuleInfo>& moduleList, void* address)
{
for (int m = 0; m < (int)moduleList.size(); m++) {
const MyModuleInfo& mInfo = moduleList[m];
if (address >= mInfo.Base && address < mInfo.Base + mInfo.Size)
return &mInfo;
}
return NULL;
}

Resources