getting results from controller via usb failes - c++

Im trying to write a programm in c++ to let my computer communicate with a trinamic steprockerboard.
They already provided an example file, to get you on the way. This works perfect, but is really simplistic.
Now I want to read the results from the usb device, and they made a function for that:
//Read the result that is returned by the module
//Parameters: Handle: handle of the serial port, as returned by OpenRS232
//Address: pointer to variable to hold the reply address returned by the module
// Status: pointer to variable to hold the status returned by the module (100 means okay)
//Value: pointer to variable to hold the value returned by the module
prototype:
UCHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
Now I wrote the following:
UCHAR* adr;
UCHAR* stat;
int* val;
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -3200); // move to next position
SendCmd(RS232Handle,1, TMCL_GAP, 8, 0, 0); // tell motor to look if position is reached
GetResult(RS232Handle,adr,stat,val); //ask for the result, value must give a 1 if so
printf("results from USB device: adr=%d, stat=%d, val=%d\n", adr, stat, val);
But when I run the program, and try this option, the program chrashes.
Has anybody got an idea what might cause the problem? (the code I supplied is only a part of my program, the whole code can be find below.
It is not my intention that you read the whole code, the problem should be above, but only for who is interested I also put the rest down here)
// TMCLTest.cpp : Show how to communicate with a TMCM module in TMCL
//
#include "stdafx.h"
#include <iostream>
//Opcodes of all TMCL commands that can be used in direct mode
#define TMCL_ROR 1
#define TMCL_ROL 2
#define TMCL_MST 3
#define TMCL_MVP 4
#define TMCL_SAP 5
#define TMCL_GAP 6
#define TMCL_STAP 7
enter code here#define TMCL_RSAP 8
enter code here#define TMCL_SGP 9
#define TMCL_GGP 10
#define TMCL_STGP 11
#define TMCL_RSGP 12
#define TMCL_RFS 13
#define TMCL_SIO 14
#define TMCL_GIO 15
#define TMCL_SCO 30
#define TMCL_GCO 31
#define TMCL_CCO 32
//Opcodes of TMCL control functions (to be used to run or abort a TMCL program in the module)
#define TMCL_APPL_STOP 128
#define TMCL_APPL_RUN 129
#define TMCL_APPL_RESET 131
//Options for MVP commandds
#define MVP_ABS 0
#define MVP_REL 1
#define MVP_COORD 2
//Options for RFS command
#define RFS_START 0
#define RFS_STOP 1
#define RFS_STATUS 2
#define FALSE 0
#define TRUE 1
//Result codes for GetResult
#define TMCL_RESULT_OK 0
#define TMCL_RESULT_NOT_READY 1
#define TMCL_RESULT_CHECKSUM_ERROR 2
//Open serial interface
//Usage: ComHandle=OpenRS232("COM1", CBR_9600)
HANDLE OpenRS232(const char* ComName, DWORD BaudRate)
{
HANDLE ComHandle;
DCB CommDCB;
COMMTIMEOUTS CommTimeouts;
ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(GetLastError()!=ERROR_SUCCESS) return INVALID_HANDLE_VALUE;
else
{
GetCommState(ComHandle, &CommDCB);
CommDCB.BaudRate=BaudRate;
CommDCB.Parity=NOPARITY;
CommDCB.StopBits=ONESTOPBIT;
CommDCB.ByteSize=8;
CommDCB.fBinary=1; //Binary Mode only
CommDCB.fParity=0;
CommDCB.fOutxCtsFlow=0;
CommDCB.fOutxDsrFlow=0;
CommDCB.fDtrControl=0;
CommDCB.fDsrSensitivity=0;
CommDCB.fTXContinueOnXoff=0;
CommDCB.fOutX=0;
CommDCB.fInX=0;
CommDCB.fErrorChar=0;
CommDCB.fNull=0;
CommDCB.fRtsControl=RTS_CONTROL_TOGGLE;
CommDCB.fAbortOnError=0;
SetCommState(ComHandle, &CommDCB);
//Set buffer size
SetupComm(ComHandle, 100, 100);
//Set up timeout values (very important, as otherwise the program will be very slow)
GetCommTimeouts(ComHandle, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout=MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier=0;
CommTimeouts.ReadTotalTimeoutConstant=0;
SetCommTimeouts(ComHandle, &CommTimeouts);
return ComHandle;
}
}
//Close the serial port
//Usage: CloseRS232(ComHandle);
void CloseRS232(HANDLE Handle)
{
CloseHandle(Handle);
}
//Send a binary TMCL command
//e.g. SendCmd(ComHandle, 1, TMCL_MVP, MVP_ABS, 1, 50000); will be MVP ABS, 1, 50000 for module with address 1
//Parameters: Handle: Handle of the serial port (returned by OpenRS232).
// Address: address of the module (factory default is 1).
// Command: the TMCL command (see the constants at the begiining of this file)
// Type: the "Type" parameter of the TMCL command (set to 0 if unused)
// Motor: the motor number (set to 0 if unused)
// Value: the "Value" parameter (depending on the command, set to 0 if unused)
void SendCmd(HANDLE Handle, UCHAR Address, UCHAR Command, UCHAR Type, UCHAR Motor, INT Value)
{
UCHAR TxBuffer[9];
DWORD BytesWritten;
int i;
TxBuffer[0]=Address;
TxBuffer[1]=Command;
TxBuffer[2]=Type;
TxBuffer[3]=Motor;
TxBuffer[4]=Value >> 24;
TxBuffer[5]=Value >> 16;
TxBuffer[6]=Value >> 8;
TxBuffer[7]=Value & 0xff;
TxBuffer[8]=0;
for(i=0; i<8; i++)
TxBuffer[8]+=TxBuffer[i];
//Send the datagram
WriteFile(Handle, TxBuffer, 9, &BytesWritten, NULL);
}
//Read the result that is returned by the module
//Parameters: Handle: handle of the serial port, as returned by OpenRS232
// Address: pointer to variable to hold the reply address returned by the module
// Status: pointer to variable to hold the status returned by the module (100 means okay)
// Value: pointer to variable to hold the value returned by the module
//Return value: TMCL_RESULT_OK: result has been read without errors
// TMCL_RESULT_NOT_READY: not enough bytes read so far (try again)
// TMCL_RESULT_CHECKSUM_ERROR: checksum of reply packet wrong
UCHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
{
UCHAR RxBuffer[9], Checksum;
DWORD Errors, BytesRead;
COMSTAT ComStat;
int i;
//Check if enough bytes can be read
ClearCommError(Handle, &Errors, &ComStat);
if(ComStat.cbInQue>8)
{
//Receive
ReadFile(Handle, RxBuffer, 9, &BytesRead, NULL);
Checksum=0;
for(i=0; i<8; i++)
Checksum+=RxBuffer[i];
if(Checksum!=RxBuffer[8]) return TMCL_RESULT_CHECKSUM_ERROR;
*Address=RxBuffer[0];
*Status=RxBuffer[2];
*Value=(RxBuffer[4] << 24) | (RxBuffer[5] << 16) | (RxBuffer[6] << 8) | RxBuffer[7];
} else return TMCL_RESULT_NOT_READY;
return TMCL_RESULT_OK;
}
int main(int argc, char* argv[])
{
int i;
int Type, Motor, Velocity, Position,ref1;
UCHAR Address, Status;
int Value, Timeout;
HANDLE RS232Handle;
RS232Handle=OpenRS232("COM3", 9600);
// set parameters
SendCmd(RS232Handle, 1, TMCL_SAP, 140, 0, 5); //SAP 140, 0, 5 // set microsteps to 32 (32 additional steps per step of 1.8 degr.)
//SAP 4, 0, 500 //set max vel.
//SAP 5, 0, 100 //set max acc.
//SAP 6, 0, 255 //set abs. max current to 2.8 ampere
//SAP 7, 0, 50 //set standby current ((50/250)*2.8A)
printf("VPI Test Setup\n \n" );
do
{
printf("1 - Rotate clockwise (10 rotations)\n");
printf("2 - Rotate counter-clockwise (10 rotations)\n");
printf("3 - Stop motor\n");
printf("4 - Start test (First 100 rotations clockwise, \n then 100 rotations counter clockwise)\n");
printf("\n99 - End\n");
scanf("%d", &i);
switch(i)
{
case 1:
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, 32000); //ABS(4th parameter) = 0
break;
case 2:
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -32000); //ABS(4th parameter) = 0
break;
case 3:
SendCmd(RS232Handle, 1, TMCL_MST, 0, 0, 0);
break;
case 4:
//SendCmd(RS232Handle, 1, TMCL_RFS,0,0,0);
printf("Test started \n" );
//UCHAR done;
UCHAR* adr;
UCHAR* stat;
int* val;
//SendCmd(RS232Handle, 1, TMCL_SAP, 193, 1, 2); //SAP 193,1,2
SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, -3200); //ABS(4th parameter) = 0
SendCmd(RS232Handle,1, TMCL_GAP, 8, 0, 0);
GetResult(RS232Handle,adr,stat,val);
printf("results from USB device: adr=%d, stat=%d, val=%d\n", adr, stat, val);
//CHAR GetResult(HANDLE Handle, UCHAR *Address, UCHAR *Status, int *Value)
// if(done != 2)
// {
// printf("rotation backwards started \n");
// SendCmd(RS232Handle, 1, TMCL_MVP, 0, 0, 3200);
// }
// }
break;
}
SendCmd(RS232Handle, 1, TMCL_ROL, 0, Motor, Velocity);
SendCmd(RS232Handle, 1, TMCL_ROL, 0, Motor, Velocity);
if(i==1 || i==2 || i==3 || i==4)
{
Address=0;
Status=0;
Value=0;
Timeout=GetTickCount();
while(GetResult(RS232Handle, &Address, &Status, &Value) ==TMCL_RESULT_NOT_READY && abs(GetTickCount()-Timeout)<1000);
printf("Result: Address=%d, Status=%d, Value=%d\n", Address, Status, Value);
}
}
while(i!=99);
CloseRS232(RS232Handle);
return 0;
}

Address, Status and Value should point to valid variables. So, your code should look something like:
UCHAR adr;
UCHAR stat;
int val;
GetResult(RS232Handle,&adr,&stat,&val);
What is happening now is that your variables (adr, stat and val) are not initialized, so, they point to random locations in memory. When you pass these variables to GetResult, it tries to write to those random locations.

Related

MPU6050 stuck in sleepmode (C/C++)/No raw data being transmitted

I have a MPU6050 hooked up to a raspberry pi pico, I am trying to read the data using the i2c protocol. But it only gives 0's, I assume this is due to the fact that its in sleep mode because from what I can tell everything is connected as it should be.
`
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
//mpu address
const static uint8_t MPU_ADDRESS = 0x68;
static void mpu6050_reset() {
// Two byte reset. First byte register, second byte data
// There are a load more options to set up the device in different ways that could be added here
//uint8_t buffer [] = {(uint8_t)65, (uint8_t)66};
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
//printf("b1: %d b2: %d \n", buffer[0], buffer[1]);
uint8_t buf[] = {0x6B, 0x00};
i2c_write_blocking(i2c_default, MPU_ADDRESS, buf, 1, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
//i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
}
static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
// For this particular device, we send the device the register we want to read
// first, then subsequently read from the device. The register is auto incrementing
// so we don't need to keep sending the register we want, just the first.
uint8_t buffer[6];
// Start reading acceleration registers from register 0x3B for 6 bytes
uint8_t val = 0x3B;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true); // true to keep master control of bus
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false);
printf("buffer accel, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
for (int i = 0; i < 3; i++) {
accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
}
// Now gyro data from reg 0x43 for 6 bytes
// The register is auto incrementing on each read
val = 0x43;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false); // False - finished with bus
for (int i = 0; i < 3; i++) {
gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
}
printf("buffer gyro, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
val = 0x41;
i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 2, false); // False - finished with bus
*temp = buffer[0] << 8 | buffer[1];
}
int main() {
//check that pico is powered and running
const uint LED = PICO_DEFAULT_LED_PIN;
gpio_init(LED);
gpio_set_dir(LED, GPIO_OUT);
gpio_put(LED, 1);
//check that pico can use serial output
stdio_init_all();
printf("hello world \n");
//setup i2c buffer address stuff
uint8_t MPU_ACCELRATION_BUFFER = 0x3B;
uint8_t MPU_GRYOSCOPE_BUFFER = 0x43;
//turn on MPU power
const uint MPU_POWER = 1;
gpio_init(MPU_POWER);
gpio_set_dir(MPU_POWER, GPIO_OUT);
gpio_put(MPU_POWER, 1);
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
//while (1){
mpu6050_reset();
//}
int16_t acceleration[3], gyro[3], temp;
while (1) {
mpu6050_reset();
mpu6050_read_raw(acceleration, gyro, &temp);
// These are the raw numbers from the chip, so will need tweaking to be really useful.
// See the datasheet for more information
printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
printf("Temp. = %f\n", (temp / 340.0) + 36.53);
sleep_ms(100);
}
return 0;
}
`
This is the code, using the raspberry pi c/cpp sdk. A large chunk of it is simply the example for the mpu6050 which all seems to be valid, and there is code included meant to wake up the mpu6050. So are there any other methods of waking the MPU6050 up or does the issue appear to be something else within the code?

How to implement message class with configurable bit as either 0 or 1 in C++?

I am trying to create a message class with configurable as either 0 or 1 such as this
1 Byte, unit 8
Bit 0: Port A, 1 connected, 0 disconnected
Bit 1: Port A, 1 connected, 0 disconnected
Bit 2: Port A, 1 connected, 0 disconnected
Bit 3, 4, 5, 6, 7: Reserved
This I have been able to implement using union and type punning in C++ but this is seen as undefined behavior in C++.
union Msg{
uint8_t bitfield;
struct {
uint8_t PORTA : 1;
uint8_t PORTB : 1;
uint8_t PORTC : 1;
uint8_t : 5;
} msg;
};
How can I do this in C++?
And is it possible to create a function to pack data into this structure?
You can use bitwise operations. First, define helper functions for getting/setting a bit:
bool get_bit(uint8_t bits, uint8_t index) {
return bool((bits >> index) & 1U);
}
uint8_t set_bit(uint8_t bits, uint8_t index, bool value) {
return (bits & ~(1U << index)) | (uint8_t(value) << index);
}
Then, you can use uint8_t instead of Msg or define Msg as an alias for uint8_t.
// Msg is an alias for uint8_t
using Msg = uint8_t;
Msg message = 0;
message = set_bit(message, 0, true); // Setting the PORT A on
message = set_bit(message, 1, true); // Setting the PORT B on
message = set_bit(message, 2, false); // Setting the PORT C off
// You can use 1 or 0 instead of true or false
message = set_bit(message, 0, 0); // Setting the PORT A off
bool port_b = get_bit(message, 1);
Alternatively, you can use std::bitset (docs) which does the bit manipulation for you:
// You choose the number of bits at compile-time
std::bitset<3> ports;
ports[0] = true;
ports[1] = false;
ports[2] = ports[1];

serial read changes input & doesn't read whole line

Large strings sent over serial are not correctly read using an Arduino Uno and the Arduino IDE. When the typed command is too long, not the whole data is returned and sometimes is is even random numbers.
99,3,0,1,0,0,0 Results correctly in (not sure why there is an ending , tho):
receivedValues are: 99,3,0,1,0,0,0,
99,3,0,0,0,0,0 Results correctly in: receivedValues are: 99,3,0,0,0,0,0,
Where is starts to go wrong:
99,3,0,100,200,300,400 Results in: receivedValues are: 99,3,0,100,200,44,144,
99,123456789 Results in: receivedValues are: 99,21,0,1,200,200,244,
99,3,0,1,200,200,2000 Results in: receivedValues are: 99,3,0,1,200,200,208,
Here is the part of my code that is relevant:
uint8_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
#define HEADER 0 // 99
#define CMD 1 // LICHT (2) || GEUR (3)
#define DATA0 2 // KLEUR INDEX || GEUR INDEX
#define DATA1 3 // H || ON / OFF
#define DATA2 4 // S
#define DATA3 5 // V
#define DATA4 6 // BlendTime
#define CHECK 99
#define ON 1
#define OFF 0
bool messageReceived = false;
bool startBlending = false;
void setup()
{
Serial.begin(9600);
}
void loop()
{
ParseSerial();
if (messageReceived)
{
printMessage();
// CheckCommand();
messageReceived = false;
}
}
void ParseSerial()
{
int serialIndex = 0;
if (Serial.available() > 8)
{
while (0 < Serial.available())
{
String bufferString;
int bufferInt;
bufferString = Serial.readStringUntil(',');
bufferInt = bufferString.toInt();
receivedValues[serialIndex] = bufferInt;
serialIndex++;
}
if (receivedValues[HEADER] == CHECK)
{
Serial.print("receivedValues[0]: ");
Serial.println(receivedValues[0]);
messageReceived = true;
}
if (receivedValues[HEADER] != CHECK)
{
Serial.println("not a good package");
}
Serial.flush();
}
else
{
Serial.flush();
}
}
void printMessage()
{
Serial.print("receivedValues are: ");
for (int i = 0; i < 7; i++)
{
Serial.print(receivedValues[i]);
Serial.print(",");
}
Serial.println();
}
If the header of the message does not start with 99 it will write not a good package. What is noticeable it that when I do enter a command with 99 at the beginning ONCE, it will write not a good package twice most of the time.
receivedValues is declared as uint8_t receivedValues[7]. The maximum value for uint8_t is 255. If you try to store a larger number, it will be truncated.
If you want to store larger numbers, you need to pick a wider integer type for your array, e.g.
uint32_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
Which will work up to UINT32_MAX, which is 0xFFFFFFFF (4294967295)
I found the solution to this problem. Changing uint8_t was not the answer.
A byte of 8 binary bits can represent 28 = 256 numbers: 0 - 255. The
serial connection sends data byte by byte, so if you want to send a
number larger than 255, you'll have to send multiple bytes
Link to source:
https://forum.arduino.cc/index.php?topic=492055.0
I ended up sending a smaller number (minutes) than 255, and then in the Arduino code multiply it again (to seconds).

RtAudio - Playing samples from wav file

I am currently trying to learn audio programming. My goal is to open a wav file, extract everything and play the samples with RtAudio.
I made a WaveLoader class which let's me extract the samples and meta data. I used this guide to do that and I checked that everything is correct with 010 editor. Here is a snapshot of 010 editor showing the structure and data.
And this is how i store the raw samples inside WaveLoader class:
data = new short[wave_data.payloadSize]; // - Allocates memory size of chunk size
if (!fread(data, 1, wave_data.payloadSize, sound_file))
{
throw ("Could not read wav data");
}
If i print out each sample I get : 1, -3, 4, -5 ... which seems ok.
The problem is that I am not sure how I can play them. This is what I've done:
/*
* Using PortAudio to play samples
*/
bool Player::Play()
{
ShowDevices();
rt.showWarnings(true);
RtAudio::StreamParameters oParameters; //, iParameters;
oParameters.deviceId = rt.getDefaultOutputDevice();
oParameters.firstChannel = 0;
oParameters.nChannels = mAudio.channels;
//iParameters.deviceId = rt.getDefaultInputDevice();
//iParameters.nChannels = 2;
unsigned int sampleRate = mAudio.sampleRate;
// Use a buffer of 512, we need to feed callback with 512 bytes everytime!
unsigned int nBufferFrames = 512;
RtAudio::StreamOptions options;
options.flags = RTAUDIO_SCHEDULE_REALTIME;
options.flags = RTAUDIO_NONINTERLEAVED;
//&parameters, NULL, RTAUDIO_FLOAT64,sampleRate, &bufferFrames, &mCallback, (void *)&rawData
try {
rt.openStream(&oParameters, NULL, RTAUDIO_SINT16, sampleRate, &nBufferFrames, &mCallback, (void*) &mAudio);
rt.startStream();
}
catch (RtAudioError& e) {
std::cout << e.getMessage() << std::endl;
return false;
}
return true;
}
/*
* RtAudio Callback
*
*/
int mCallback(void * outputBuffer, void * inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void * userData)
{
unsigned int i = 0;
short *out = static_cast<short*>(outputBuffer);
auto *data = static_cast<Player::AUDIO_DATA*>(userData);
// if i is more than our data size, we are done!
if (i > data->dataSize) return 1;
// First time callback is called data->ptr is 0, this means that the offset is 0
// Second time data->ptr is 1, this means offset = nBufferFrames (512) * 1 = 512
unsigned int offset = nBufferFrames * data->ptr++;
printf("Offset: %i\n", offset);
// First time callback is called offset is 0, we are starting from 0 and looping nBufferFrames (512) times, this gives us 512 bytes
// Second time, the offset is 1, we are starting from 512 bytes and looping to 512 + 512 = 1024
for (i = offset; i < offset + nBufferFrames; ++i)
{
short sample = data->rawData[i]; // Get raw sample from our struct
*out++ = sample; // Pass to output buffer for playback
printf("Current sample value: %i\n", sample); // this is showing 1, -3, 4, -5 check 010 editor
}
printf("Current time: %f\n", streamTime);
return 0;
}
Inside callback function, when I print out sample values I get exactly like 010 editor? Why isnt rtaudio playing them. What is wrong here? Do I need to normalize sample values to between -1 and 1?
Edit:
The wav file I am trying to play:
Chunksize: 16
Format: 1
Channel: 1
SampleRate: 48000
ByteRate: 96000
BlockAlign: 2
BitPerSample: 16
Size of raw samples total: 2217044 bytes
For some reason it works when I pass input parameters to the openStream()
RtAudio::StreamParameters oParameters, iParameters;
oParameters.deviceId = rt.getDefaultOutputDevice();
oParameters.firstChannel = 0;
//oParameters.nChannels = mAudio.channels;
oParameters.nChannels = mAudio.channels;
iParameters.deviceId = rt.getDefaultInputDevice();
iParameters.nChannels = 1;
unsigned int sampleRate = mAudio.sampleRate;
// Use a buffer of 512, we need to feed callback with 512 bytes everytime!
unsigned int nBufferFrames = 512;
RtAudio::StreamOptions options;
options.flags = RTAUDIO_SCHEDULE_REALTIME;
options.flags = RTAUDIO_NONINTERLEAVED;
//&parameters, NULL, RTAUDIO_FLOAT64,sampleRate, &bufferFrames, &mCallback, (void *)&rawData
try {
rt.openStream(&oParameters, &iParameters, RTAUDIO_SINT16, sampleRate, &nBufferFrames, &mCallback, (void*) &mAudio);
rt.startStream();
}
catch (RtAudioError& e) {
std::cout << e.getMessage() << std::endl;
return false;
}
return true;
It was so random when I was trying to playback my mic. I left input parameters and my wav file was suddenly playing. Is this is a bug?

blowfish.h usage in a simple client/server application

I am trying to write an application which amongst other things uses the openssl blowfish implementation (blowfish.h) to transport files over a simple server/client pair.
However, whilst some files are encrypted, transported, received and decrypted correctly, some end up being corrupted, after the final decryption stage. This leads me to think that the encryption routines are not being called correctly (since I have also tried with equivalent DES library calls, with the same 'intermittent corruption' results).
The relevant code is pasted below.
Basically, it starts with the function send_file (called by a connected client). This splits the file into chunks. Each 1024 byte chunk is encrypted separately and then sent. Each chunk is then received by the server in the receive_file function, decrypted and saved to disc.
Any idea what the problem could be? (Note if necessary, I will add the code for the whole application).
Cheers,
Ben.
void encryptHelper(const char*,int);
void decryptHelper(const char*,int);
inline void blowfish(unsigned char *data, int data_len, char* key, int enc)
{
// hash the key first!
unsigned char obuf[20];
bzero(obuf,20);
SHA1((const unsigned char*)key, strlen(key), obuf);
BF_KEY bfkey;
int keySize = strlen(key);
BF_set_key(&bfkey, 16, (const unsigned char*)obuf);
unsigned char ivec[8];
memset(ivec, 0, 8);
unsigned char out[1024];// = (unsigned char*) malloc(1024);
bzero(out,1024);
int num = 0;
BF_cfb64_encrypt(data, out, data_len, &bfkey, ivec, &num, enc);
data=out;
//memcpy(data, out, data_len);
//free(out);
}
void MyFrame::encryptHelper(char* orig, int inlength)
{
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_ENCRYPT);
}
void MyFrame::decryptHelper(char* orig, int inlength)
{
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_DECRYPT);
}
int MyFrame::send_file(int fd)
{
char rec[10];
struct stat stat_buf;
fstat (fd, &stat_buf);
int size=stat_buf.st_size;
int remSize=size;
int value=0;
while(size > 0)
{
char buffer[1030];
bzero(buffer,1030);
bzero(rec,10);
int n;
if(size>=1024)
{
value+=1024;
n=read(fd, buffer, 1024);
// encrypt is necessary
if(encButtonOn->GetValue()) encryptHelper(buffer,1024);
// Send a chunk of data
n=send(sockFile_, buffer, 1024, 0 );
// Wait for an acknowledgement
n = recv(sockFile_, rec, 10, 0 );
}
else // reamining file bytes
{
value+=size;
n=read(fd, buffer, size);
if(encButtonOn->GetValue()) encryptHelper(buffer,size);
buffer[size]='\0';
n=send(sockFile_,buffer, size, 0 );
n=recv(sockFile_, rec, 10, 0 );
}
MyFooEvent event( 0, 992 );
double firstBit = (double)value/remSize;
firstBit=firstBit*100.0;
event.adouble=firstBit;
wxPostEvent (this, event);
size -= 1024;
}
// Send a completion string
int n = send(sockFile_, "COMP",strlen("COMP"), 0 );
char buf[10];
bzero(buf,10);
// Receive an acknowledgemnt
n = recv(sockFile_, buf, 10, 0 );
return(0);
}
int MyFrame::receive_file()
{
// receive file size and send ack
char sizeBuffer[50];
bzero(sizeBuffer,50);
int n;
//read(This->sockpw,buffer,bufferSize);
n=read(sockFile_, sizeBuffer, 50);
n=send(sockFile_,"OK", strlen("OK"), 0 );
int size = atoi(sizeBuffer);
//std::cout<<size<<std::endl;
// receive file name and send ack
char saveName[256];
bzero(saveName,256);
n=read(sockFile_, saveName, 256);
n=send(sockFile_,"OK",strlen("OK"), 0 );
//std::cout<<saveName_<<std::endl;
// start file writing process to local disk
// decrypt first if necessary
std::cout<<arraySize(saveName)<<std::endl;
std::cout<<strlen(saveName)<<std::endl;
if(encButtonOn->GetValue()) decryptHelper(saveName,strlen(saveName));
ofstream outFile(saveName,ios::out|ios::binary|ios::app);
// vars for status gauge
int remSize=size;
int value=0;
while(size > 0)
{
// buffer for storing incoming data
char buf[1030];
bzero(buf,1030);
if(size>=1024)
{
value+=1024; // for status gauge
// receive chunk of data
n=recv(sockFile_, buf, 1024, 0 );
// decrypt if necessary
if(encButtonOn->GetValue()) decryptHelper(buf,1024);
// write chunk of data to disk
outFile.write(buf,1024);
// send acknowledgement
n = send(sockFile_, "OK", strlen("OK"), 0 );
}
else
{
value+=size;
n=recv(sockFile_, buf, size, 0 );
if(encButtonOn->GetValue()) decryptHelper(buf,size);
buf[size]='\0';
outFile.write(buf,size);
n = send(sockFile_, "OK", strlen("OK"), 0 );
}
// Update status gauge
MyFooEvent event( 0, 992 );
double firstBit = (double)value/remSize;
firstBit=firstBit*100.0;
event.adouble=firstBit;
wxPostEvent (this, event);
size -= 1024;
}
outFile.close();
// Receive 'COMP' and send acknowledgement
// ---------------------------------------
char buf[10];
bzero(buf,10);
n = recv(sockFile_, buf, 10, 0 );
n = send(sockFile_, "OK", strlen("OK"), 0 );
std::cout<<"File received..."<<std::endl;
// Display image event
MyFooEvent eventF( 0, 995 );
eventF.SetText(wxString(saveName, wxConvUTF8));
wxPostEvent (this, eventF);
return(0);
}
I'm assuming that:
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_DECRYPT);
decrypts into pb, which is actually the buffer of a temporary string. You simply cannot use std::string like this. The fact that you had to use so many casrs to do this shouldhave been a warning - good C and C++ code does not normally require casts at all. Basically, you need to rethink what you are doing.
not sure, could be a buffer overrun somewhere or memory corruption...
you could use valgrind to detect the issue or perhaps try simplifying the conversions/...
Having fixed a few bugs by asking a few other questions, I have gotten the file encryption process working, but only when the client and server are both on the same localhost machine. When they reside on different machines, the file still ends up being corrupted. I think it is due to the fact that send_file and receive file are called from threads as follows:
void
*MyFrame::send_fileT(void* tid)
{
accessHelper* ah = static_cast<accessHelper*>(tid);
MyFrame* This = ah->This;
This->send_file(fileSendID);
pthread_exit(NULL);
}
void
*MyFrame::receive_fileT(void* tid)
{
accessHelper* ah = static_cast<accessHelper*>(tid);
MyFrame* This = ah->This;
This->receive_file();
pthread_exit(NULL);
}
....and then the receive_file or send_file functions are calling the blowfish function to carry out the encryption. Now if a function is called within a pthread (i.e. send_file and receive_file), then if that function calls another function (i.e. encryptHelper -- blowfish), is it possible that the calling function will not 'properly' wait for the called function to finish correctly?
Fixed:
n=read(fd, buffer, 2048);
if(enc)encryptHelper(buffer,n);
n=send(sockFile_, buffer, n, 0 );
[called in a loop]
The problem was, was that it cannot be ensured that all n bytes of the encrypted buffer are transferred. Thus only some of the encrypted bytes are sent leading to inconsistent decryption on the receiving end.