Clicking in ALSA tone generator - c++

I'm learning to use ALSA on a Raspberry Pi 2. I've written a small test program in C++ to generate a 440 Hz test tone. It makes the tone, but there is a clicking sound about twice per second in the tone.
Does anyone have an idea why this might be happening? The code is below.
#include <cmath>
#include <climits>
#include <iostream>
#include <alsa/asoundlib.h>
#include "definitions.hpp"
using namespace std;
int main() {
int ret;
snd_pcm_t* pcm_handle; // device handle
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
snd_pcm_hw_params_t* hwparams; // hardware information
char* pcm_name = strdup("plughw:0,0"); // on-board audio jack
int rate = 48000;
const uint16 freq = 440;
long unsigned int bufferSize = 8192*4;
const uint32 len = bufferSize*100;
const float32 arg = 2 * 3.141592 * freq / rate;
sint16 vals[len];
for(int i = 0; i < len; i = i + 2) {
vals[i] = SHRT_MAX * cos(arg * i / 2);
}
snd_pcm_hw_params_alloca(&hwparams);
ret = snd_pcm_open(&pcm_handle, pcm_name, stream, 0);
cout << "Opening: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_any(pcm_handle, hwparams);
cout << "Initializing hwparams structure: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
cout << "Setting access: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams,
SND_PCM_FORMAT_S16_LE);
cout << "Setting format: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_rate(pcm_handle, hwparams,
rate, (int)0);
cout << "Setting rate: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2);
cout << "Setting channels: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, 2, 0);
cout << "Setting periods: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,
&bufferSize);
cout << "Setting buffer size: " << snd_strerror(ret) << endl;
ret = snd_pcm_hw_params(pcm_handle, hwparams);
cout << "Applying parameters: " << snd_strerror(ret) << endl;
cout << endl << endl;
const void* ptr = (const void*)&vals;
int err;
do {
ptr += bufferSize;
ret = snd_pcm_writei(pcm_handle,
ptr, len);
if(ret < 0) {
err = snd_pcm_prepare(pcm_handle);
cout << "Preparing: " << snd_strerror(err)
<< endl;
}
} while(ret < 0);
cout << "Writing data: " << ret << ", " << snd_strerror(ret)
<< endl;
}
When you run it, you get this terminal output. Of course, there's no write error, just the number of bits written.
pi#raspberrypi:~/radio $ ./bin/alsatest
Opening: Success
Initializing hwparams structure: Success
Setting access: Success
Setting format: Success
Setting rate: Success
Setting channels: Success
Setting periods: Success
Setting buffer size: Success
Applying parameters: Success
Writing data: 344110, Unknown error 344110
UPDATE - NEXT DAY
OK. I've hooked the output up to my handy-dandy oscilloscope and saw the following waveform. There seems to be a discontinuity in the signal every time there's a click. I added a few lines to count how many nearly-zero values were next to each other in my sinusoid array, and there were none. Oddly enough, the ALSA sample program /test/pcm.c makes a perfect wave. Perhaps I need to write in really small chunks? There doesn't seem to be much difference between my code and the example.

Related

SDL audio callback stops after two iterations

Given the following code:
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>
#include <chrono>
#include <thread>
static void SDLCallback(void *userData, Uint8 *data, int bytes) {
std::cerr << "SDLCallback: " << bytes / sizeof(float) << "\n";
}
int main() {
using namespace std::literals;
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioDeviceID m_deviceId{};
SDL_AudioSpec m_desired, m_obtained;
m_desired.freq = 48000;
m_desired.format = AUDIO_F32SYS;
m_desired.channels = 2;
m_desired.samples = 1024;
m_desired.callback = SDLCallback;
m_desired.userdata = nullptr;
m_deviceId = SDL_OpenAudioDevice(nullptr, 0, &m_desired, &m_obtained, 0);
std::cerr << "SDL device: " << m_deviceId << std::endl;
if (m_deviceId < 2) {
std::cerr << "SDL: Couldn't open audio: " << SDL_GetError() << std::endl;
exit(1);
}
std::cerr << "rate: " << m_obtained.freq << "\n";
std::cerr << "samples: " << m_obtained.samples << "\n";
std::cerr << "bytes: " << m_obtained.size << "\n";
std::cerr << "channels: " << (int)m_obtained.channels << "\n";
SDL_PauseAudioDevice(m_deviceId, 0);
for (int i = 0; i < 10; i++) {
std::this_thread::sleep_for(100ms);
std::cerr << (SDL_GetAudioDeviceStatus(m_deviceId) == SDL_AUDIO_PLAYING)
<< std::endl;
}
SDL_CloseAudioDevice(m_deviceId);
SDL_Quit();
}
I am seeing the following output:
$ ./a.out
SDL device: 2
rate: 48000
samples: 1024
bytes: 8192
channels:
SDLCallback: 2048
SDLCallback: 2048
1
1
1
1
1
1
1
1
1
1
<program gets stuck on SDL_CloseAudioDevice>
That is, the SDLCallback function is called only twice at the beginning then not anymore, yet the audio is still marked as running. I am using PulseAudio.
What can I do to prevent that ? Where is my program wrong ? It works if I kill PulseAudio, but PulseAudio works fine for all my other software.
And if it is not wrong, how can I make sure that my users will never encounter that issue ? How can I recover without getting the program stuck on SDL_CloseAudioDevice ? As PulseAudio is very common among Linux users.

No sound generated by SDL Audio Callback

I am trying to get a simple sinewave sound generation example working using SDL 2.0.12 on Windows 10, but no sound is being output.
I have no idea if it is a problem with the code or with the output device or the audio drivers.
I'd really appreciate suggestions of how I can debug the problem further.
#include <iostream>
#include "SDL.h"
float sine_freq = 200.0f;
float audio_volume = 4000.0f;
float audio_frequency;
void SineAudioCallback(void* userdata, Uint8* stream, int len) {
float* buf = (float*)stream;
for (int i = 0; i < len / 4; ++i) {
buf[i] = (float)(audio_volume * sin(2 * M_PI * i * audio_frequency));
}
return;
}
int main(int argc, char* argv[])
{
if (SDL_Init(SDL_INIT_AUDIO)) {
return 1;
}
std::cout << "[SDL] Audio driver: " << SDL_GetCurrentAudioDriver() << std::endl;
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = 5000;
want.format = AUDIO_F32;
want.channels = 2;
want.samples = 4096;
want.callback = SineAudioCallback;
std::cout <<"[SDL] Desired - frequency: " << want.freq
<< ", format: f " << SDL_AUDIO_ISFLOAT(want.format) << " s " << SDL_AUDIO_ISSIGNED(want.format) << " be " << SDL_AUDIO_ISBIGENDIAN(want.format) << " sz " << SDL_AUDIO_BITSIZE(want.format)
<< ", channels: " << (int)want.channels << ", samples: " << want.samples << std::endl;
SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (!dev) {
SDL_Quit();
return 1;
}
std::cout << "[SDL] Desired - frequency: " << have.freq
<< ", format: f " << SDL_AUDIO_ISFLOAT(have.format) << " s " << SDL_AUDIO_ISSIGNED(have.format) << " be " << SDL_AUDIO_ISBIGENDIAN(have.format) << " sz " << SDL_AUDIO_BITSIZE(have.format)
<< ", channels: " << (int)have.channels << ", samples: " << have.samples << std::endl;
audio_frequency = sine_freq / have.freq;
SDL_PauseAudioDevice(dev, 0);
SDL_Delay(10000);
SDL_CloseAudioDevice(dev);
SDL_Quit();
return 0;
}
The output I get is
[SDL] Audio driver: wasapi
[SDL] Desired - frequency: 5000, format: f 256 s 32768 be 0 sz 32, channels: 2, samples: 4096
[SDL] Desired - frequency: 5000, format: f 256 s 32768 be 0 sz 32, channels: 2, samples: 118
So there is a difference between SDL_AudioSpec I want and have, in the number of samples being reduced.
I also get an error message relating to the dlls although I'm not sure if it is important.
avcore\audiocore\client\audioclient\audioclientcore.cpp(1839)\AUDIOSES.DLL!00007FFC48E00F8E: (caller: 0000000070D6BE39) ReturnHr(1) tid(46dc) 80070057 The parameter is incorrect.
It turns out there were two things I needed to do to solve this problem.
For a float type the sound wave can only take values from -1 to 1, whilst I was using a much greater volume boost. I needed to change
float audio_volume = 1.0f;
For Windows, the direct sound and winmm drivers give better sample lengths than wasapi. For SDL2 on Windows, you need SDL_AUDIODRIVER=directsound or SDL_AUDIODRIVER=winmm set as an environment variable. More details here

How do i read a std::string from memory using RPM

Okay, so recently i've been working witth RPM(ReadProccesMemory). But while doing so i bumped into the issue of not being able to read a string the way i wanted it.
This is what i heard/know:
I know, when reading a std::string, i get the memory adress of the string OBJECT and not the adress that contains the actual text.I am also aware of "Small String Optimization", and what it does in theory.
I'd like to be able to read the contents of varString(DefaultString) without changing the code of my dummy program(if possible).
The dummy program im reading:
int main() {
// Variables & Pointers
int varInt = 123456;
string varString = "DefaultString";
cout << sizeof(varString);
char arrChar[128] = { "Long char array right there ->" };
int* ptr2int = &varInt;
int** ptr2ptr = &ptr2int;
int*** ptr2ptr2 = &ptr2ptr;
// Printing them out
while (true){
cout << "Process ID: " << GetCurrentProcessId() << endl << endl;
cout << "varInt (0x" << &varInt << ") = " << varInt << endl;
cout << "varString (" << reinterpret_cast<const void*>(varString.data()) << ") = " << varString << endl;
cout << "arrChar (0x" << &arrChar << ") = " << arrChar << endl << endl;
cout << "ptr2int (0x" << &ptr2int << ") = " << &varInt << endl;
cout << "ptr2ptr (0x" << &ptr2ptr << ") = " << &ptr2int << endl;
cout << "ptr2ptr2 (0x" << &ptr2ptr2 << ") = " << &ptr2ptr << endl << endl;
break;
}
cin.get();
return 0;
}
What im currently doing(wont work as intended):
void reading_string(HANDLE handle_procces) {
uintptr_t memoryAdress_2 = 0x0;
cout << "Please write down the memory adress of \"varString\" > " << flush;
cin >> hex >> memoryAdress_2;
string read_string_object;
ReadProcessMemory(handle_procces, (LPCVOID)memoryAdress_2, &read_string_object, sizeof(string), NULL);
cout << "The value of this memory adress is: " << read_string_object << endl;
}
std::string is a container, offset 0x14 is the size of the char array which it manages. If the string is less than 15 characters, the second variable (offset 0x4 or 0x8 depending on x86/x64) is the char array itself. If it's more than 15 characters, this variable turns into a pointer to the char array which is allocated dynamically
We can use this information to read the string externally, it's a hack but it works
Here some sample code which shows you how it's done:
#include <windows.h>
#include <iostream>
using namespace std;
void ReadExternalString(HANDLE hProc, uintptr_t addr, char* dstArray)
{
//Get the size of the array, offset 0x14 is the size of the array
//it's 0x14 on x86
uintptr_t sizeoffset = 0x14;
//check if x64
if (sizeof(int*) == 8)
{
//assign correct offset
sizeoffset = 0x18;
}
uintptr_t arraySize;
ReadProcessMemory(hProc, (BYTE*)(addr + sizeoffset), &arraySize, sizeof(arraySize), 0);
if (arraySize > 15)
{
uintptr_t addrOfCharArray;
//dereference the pointer in the second member variable to get the dynamic address of the array
ReadProcessMemory(hProc, (BYTE*)(addr + sizeof(void*)), &addrOfCharArray, sizeof(void*), 0);
char buffer[500];
//Read the array into buffer, +1 to get the null terminator
ReadProcessMemory(hProc, (BYTE*)(addrOfCharArray), &buffer, arraySize + 1, 0);
//copy the buffer into our ouput argument
memcpy(dstArray, &buffer, strlen(buffer) + 1);
}
else
{
ReadProcessMemory(hProc, (BYTE*)(addr + sizeof(void*)), dstArray, arraySize, 0);
}
}
std::string ourStringToRead = "Yolo";
int main()
{
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId());
if (hProcess == NULL)
{
cout << "OpenProcess failed. GetLastError = " << dec << GetLastError() << endl;
system("pause");
return EXIT_FAILURE;
}
char* cString = new char[500];
ZeroMemory(cString, 500);
ReadExternalString(hProcess, (uintptr_t)&ourStringToRead, cString);
cout << "string char array = " << cString << endl;
system("pause");
return 0;
}

Head Pose Estimation on Random Forest in G Fanelli's paper

I have been working on head pose estimation on depth data. And I have read G Fanelli's paper-"Real Time Head Pose Estimation from Consumer Depth Cameras" "Real Time Head Pose Estimation with Random Regression Forests". I test the data and the code Fanelli published on the website(http://www.vision.ee.ethz.ch/~gfanelli/head_pose/head_forest.html). However when I run the code, there is a problem. The error information is "usage: ./head_pose_estimation config_file depth_image". I think it is about file reading but I don't how to fix it.
and the code is like this:
int main(int argc, char* argv[])
{
if( argc != 3 )
{
cout << "usage: ./head_pose_estimation config_file depth_image" << endl;
exit(-1);
}
loadConfig(argv[1]);
CRForestEstimator estimator;
if( !estimator.loadForest(g_treepath.c_str(), g_ntrees) ){
cerr << "could not read forest!" << endl;
exit(-1);
}
string depth_fname(argv[2]);
//read calibration file (should be in the same directory as the depth image!)
string cal_filename = depth_fname.substr(0,depth_fname.find_last_of("/")+1);
cal_filename += "depth.cal";
ifstream is(cal_filename.c_str());
if (!is){
cerr << "depth.cal file not found in the same folder as the depth image! " << endl;
return -1;
}
//read intrinsics only
float depth_intrinsic[9]; for(int i =0; i<9; ++i) is >> depth_intrinsic[i];
is.close();
Mat depthImg;
//read depth image (compressed!)
if (!loadDepthImageCompressed( depthImg, depth_fname.c_str() ))
return -1;
Mat img3D;
img3D.create( depthImg.rows, depthImg.cols, CV_32FC3 );
//get 3D from depth
for(int y = 0; y < img3D.rows; y++)
{
Vec3f* img3Di = img3D.ptr<Vec3f>(y);
const int16_t* depthImgi = depthImg.ptr<int16_t>(y);
for(int x = 0; x < img3D.cols; x++){
float d = (float)depthImgi[x];
if ( d < g_max_z && d > 0 ){
img3Di[x][0] = d * (float(x) - depth_intrinsic[2])/depth_intrinsic[0];
img3Di[x][1] = d * (float(y) - depth_intrinsic[5])/depth_intrinsic[4];
img3Di[x][2] = d;
}
else{
img3Di[x] = 0;
}
}
}
g_means.clear();
g_votes.clear();
g_clusters.clear();
string pose_filename(depth_fname.substr(0,depth_fname.find_last_of('_')));
pose_filename += "_pose.bin";
cv::Vec<float,POSE_SIZE> gt;
bool have_gt = false;
//try to read in the ground truth from a binary file
FILE* pFile = fopen(pose_filename.c_str(), "rb");
if(pFile){
have_gt = true;
have_gt &= ( fread( &gt[0], sizeof(float),POSE_SIZE, pFile) == POSE_SIZE );
fclose(pFile);
}
//do the actual estimate
estimator.estimate( img3D,
g_means,
g_clusters,
g_votes,
g_stride,
g_maxv,
g_prob_th,
g_larger_radius_ratio,
g_smaller_radius_ratio,
false,
g_th
);
cout << "Heads found : " << g_means.size() << endl;
//assuming there's only one head in the image!
if(g_means.size()>0){
cout << "Estimated: " << g_means[0][0] << " " << g_means[0][1] << " " << g_means[0][2] << " " << g_means[0][3] << " " << g_means[0][4] << " " << g_means[0][5] <<endl;
float pt2d_est[2];
float pt2d_gt[2];
if(have_gt){
cout << "Ground T.: " << gt[0] << " " << gt[1] << " " << gt[2] << " " << gt[3] << " " << gt[4] << " " << gt[5] <<endl;
cv::Vec<float,POSE_SIZE> err = (gt-g_means[0]);
//multiply(err,err,err);
for(int n=0;n<POSE_SIZE;++n)
err[n] = err[n]*err[n];
float h_err = sqrt(err[0]+err[1]+err[2]);
float a_err = sqrt(err[3]+err[4]+err[5]);
cout << "Head error : " << h_err << " mm " << endl;
cout << "Angle error : " << a_err <<" degrees " << endl;
pt2d_gt[0] = depth_intrinsic[0]*gt[0]/gt[2] + depth_intrinsic[2];
pt2d_gt[1] = depth_intrinsic[4]*gt[1]/gt[2] + depth_intrinsic[5];
}
pt2d_est[0] = depth_intrinsic[0]*g_means[0][0]/g_means[0][2] + depth_intrinsic[2];
pt2d_est[1] = depth_intrinsic[4]*g_means[0][1]/g_means[0][2] + depth_intrinsic[5];
}
return 0;
}
can anyone could tell me how to fix the problem?Thanks so much!
You should always read the readme.txt (here attached in head_pose_estimation.tgz) before testing an application:
To run the example code, type ./head_pose_estimation config.txt
data/frame_XXXX_depth.bin. The config.txt file contains all parameters
needed for the head pose estimation, e.g., the path to the forest, the
stride, and z threshold used to segment the person from the
background.

fread hanging, C++ with pipes

I'm writing a tictactoe application which communicates between a server and client file. Currently, my program hangs when trying to read in the players move. The client is showing successful write to the pipe but the server is not reading the information. Any help would be appreciated. Heres the offending code from both portions. Edit: I just realized the formatting got completely buggered in the copy/paste, I am sorry.
client main() :
//used to define int holder for server read in
const int MAX = 2;
//used to define buffers to transfer information
const int BUFFERS = 10;
//path of the global pipe
const string PRIMARY = "/home/mking/GPipe";
int main() {
//variables
size_t result;
srand(time(NULL) );
int s = rand() % 10000;
if (s < 1000) { s += 1000; }
cout << s << endl;
string userWrite = "/temp/" + to_string(s);
s = rand() % 10000;
if (s < 1000) { s += 1000; }
cout << s << endl;
string serverWrite = "/temp/" + to_string(s);
cout << PRIMARY << endl;
cout << "User pipe is " << userWrite << endl;
cout << "Server pipe is " << serverWrite << endl;
// send personal pipe information through global pipe to server
FILE * comms = fopen(PRIMARY.c_str(), "w");
cout << "Comms open" << endl;
result = fwrite(userWrite.c_str(), 1, userWrite.length(), comms);
if (result < userWrite.length()) { cout << endl << endl << endl << endl << endl << "write error, userfifo" << endl; }
result = fwrite(serverWrite.c_str(), 1, serverWrite.length(), comms);
if (result < userWrite.length()) { cout << endl << endl << endl << endl << endl << "write error, serverfifo" << endl; }
cout << "Comms written to" << endl;
//done with comms so close it
fclose(comms);
// for some reason sending /tmp/ caused a hang also, so i improvised
userWrite.erase(2,1);
serverWrite.erase(2,1);
// make the personal pipes
cout << userWrite << " " << serverWrite << endl;
mkfifo(userWrite.c_str(), 0777);
mkfifo(serverWrite.c_str(), 0777);
// open the personal pipes with read or write privelege
cout << "fifos made" << endl;
FILE * pwrite = fopen(userWrite.c_str(), "w");
cout << "pwrite open" << endl;
FILE * pread = fopen(serverWrite.c_str(), "r");
cout << "pread open" << endl;
// if either pipe did not get made correctly, print an error
if (pwrite == NULL ) { cout << "pwrite is wrong" << endl; }
if (pread == NULL ) { cout << "pread is wrong" << endl; }
// used to transfer information between pipes
string buffer = "/temp/0000";
string catcher = "/temp/0000";
// initialize curses functions
initscr();
noecho();
keypad(stdscr,TRUE);
cbreak();
WINDOW * screen = newwin(LINES/2, COLS/2, 0, 0);
wclear(screen);
keypad(screen,TRUE);
//wait for input before playing the game
int c = getch();
displayOpening(screen);
c = getch();
//initialize the game data types
int row = 0;
int column = 0;
vector<pair<int, int> > userMoves;
vector<pair<int,int> > serverMoves;
int charInt[MAX];
bool invalid = 0;
//until game is over or user exits
while (1) {
// update the board
displayBoard(screen,userMoves,serverMoves, row, column, invalid);
// based on user input, do stuff, supports wsad or arrow keys
switch(c = getch() ) {
// if go up, move up a row or go back to bottom if at top
case KEY_UP:
case 'w':
if (row == 0) { row = 2; }
else { row--; }
break;
// if go down, move down a row or go back to the top if at bottom
case KEY_DOWN:
case 's':
if (row == 2) { row = 0; }
else { row++; }
break;
// if go left, move left a column or go back to the far right if at far left
case KEY_LEFT:
case 'a':
if (column == 0) { column = 2; }
else { column--; }
break;
// if go right, move right a column or go back to the far left if at far right
case KEY_RIGHT:
case 'd':
if (column == 2) { column = 0; }
else { column++; }
break;
// if spacebar is pressed, enter move if valid, otherwise tell invalid and get more input
case ' ':
if (checkX(row, column, userMoves, serverMoves)) {
invalid = 0;
// no longer used function, thought maybe was the issue
//addX(row,column,userMoves,buffer);
//catch information in buffer to send to server
buffer[8] = (row + '0');
buffer[9] = (column + '0');
//cout << "buffer 0 and 1 are " << int(buffer[0]) << " " << int(buffer[1]) << endl;
// add newest move to the list of user moves
userMoves.push_back(make_pair(row,column));
// check if the game is over, send a game over message to server if so and exit/clean up pipes
if (checkValid(userMoves,serverMoves) == 0 || (userMoves.size() + serverMoves.size() == 9) ) {
youwin(screen);
buffer[8] = (3 + '0');
buffer[9] = (3 + '0');
result = fwrite(buffer.c_str(), 1, buffer.length(), pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
//mvwaddch(screen, 12, 1, 'k');
//wrefresh(screen);
//cout << endl << endl << endl << endl << endl << buffer << " " << buffer.length() << endl;
// write newest move to server, currently where hangs!!!!!!
result = fwrite(buffer.c_str(),1,buffer.length(),pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
//cout << endl << "written successfully" << endl;
//mvwaddch(screen,12,1,'l');
//wrefresh(screen);
// read in server counter move
result = fread(&catcher[0],1,BUFFERS,pread);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "read error, servermove" << endl; }
// catch newest computer move
charInt[0] = (catcher[8] - '0');
charInt[1] = (catcher[9] - '0');
// if the server says it won, clean up pipes and exit
if (charInt[0] == 3 && charInt[1] == 3) {
youlose(screen);
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
// check if the server made a valid move
if (checkX(charInt[0], charInt[1], userMoves, serverMoves)) { invalid = 1; }
//addX(charInt[0],charInt[1],serverMoves,catcher);
// add newest server move to list of server moves
serverMoves.push_back(make_pair(charInt[0],charInt[1]));
// if server has won or a draw, tell the server and clean up pipes/exit
if (checkValid(userMoves,serverMoves) == 0) {
youlose(screen);
buffer[8] = (3 + '0');
buffer[9] = (3 + '0');
result = fwrite(&buffer[0],1,BUFFERS,pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
}
// if the move was invalid say so
else { invalid = 1; }
break;
// if user wants to exit, tell the server and clean up/exit
case 'q':
buffer[8] = 3 + '0';
buffer[9] = 3 + '0';
result = fwrite(&buffer[0],sizeof(char),BUFFERS,pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
break;
default:
break;
}
}
return 0;
}
server main() :
const int GRID = 9;
const int MAX_G = 10;
const int MAX_L = 10;
const string PRIMARY="/home/mking/GPipe";
int main() {
// variables to hold personal pipe input
char userWrite[MAX_L];
char serverWrite[MAX_L];
// open global pipe and prepare for input
cout << PRIMARY << endl;
FILE * comms = fopen(PRIMARY.c_str(), "r");
cout << "comms open" << endl;
pid_t pid;
bool valid = 1;
int charInt[MAX_G];
char prev[] = "/temp/0000";
size_t result;
// run until forced to close
while(1) {
// get the personal pipe names
//cout << "about to read user" << endl;
result = fread(&userWrite[0], sizeof(char),MAX_L,comms);
if (result < MAX_L && result > 0) { cout << "read error, user" << endl; }
//cout << "read user" << endl;
result = fread(&serverWrite[0], sizeof(char), MAX_L,comms);
if (result < MAX_L && result > 0) { cout << "read error, server" << endl; }
//cout << "read server" << endl;
//cout << "User pipe is " << userWrite << endl;
//cout << "Server pipe is " << serverWrite << endl;
// if a new pipe was detected, fork and play against a client
if (strcmp(prev, userWrite) != 0) { pid = fork(); }
strcpy(prev, userWrite);
// if a chiled, play against a client
if (pid == 0) {
//close comms and open personal pipes
cout << "In child" << endl;
fclose(comms);
string user(userWrite);
string server(serverWrite);
// was having issues with fread earlier also, roundabout fix
user.erase(2,1);
server.erase(2,1);
// set up pipes
cout << "opened pipes " << user << " " << server << endl;
FILE * userFifo = fopen(user.c_str(), "r");
cout << "opened user pipe" << endl;
FILE * serverFifo = fopen(server.c_str(), "w");
cout << "opened server pipe" << endl;
// set up data for server to check moves
pair<int,int> move;
vector<pair<int,int> > userMoves;
vector<pair<int,int> > serverMoves;
char buffer[MAX_G] = {'/','t','e','m','p','/','0','0' };
char filler[MAX_G];
vector<bool> untaken (GRID, 1);
// while game not over
while (valid) {
// get a new move, HANGS HERE!!!!!
cout << "waiting for user move" << endl;
result = fread(&filler[0], sizeof(char), MAX_G, userFifo);
if (result < MAX_G) { cout << "read error, usermove" << endl; }
cout << "move read in" << endl;
// catch user move
charInt[0] = filler[6] - '0';
charInt[1] = filler[7] - '0';
cout << charInt[0] << " " << charInt[1] << endl;
// if user says game over, close pipes
if (charInt[0] == 3 && charInt[1] == 3) {
fclose(userFifo);
fclose(serverFifo);
exit(0);
}
// add user move to list of moves
userMoves.push_back(make_pair(charInt[0], charInt[1]));
// mark location of taken moves
untaken[(userMoves.back().first * 3 + userMoves.back().second)] = 0;
// see if game can be ended and add a server move
valid = checkX(userMoves,serverMoves, untaken);
untaken[(serverMoves.back().first * 3 + serverMoves.back().second)] = 0;
//prepare server move for writing
buffer[6] = serverMoves.back().first + '0';
buffer[7] = serverMoves.back().second + '0';
//buffer[0] = -1;
//buffer[1] = -1;
// write servermove to client
//cout << buffer[0] << " " << buffer[1] << endl;
result = fwrite(&buffer[0],sizeof(char),MAX_G,serverFifo);
if (result < MAX_G) { cout << "write error, servermove" << endl; }
}
// close pipes if game is over
fclose(userFifo);
fclose(serverFifo);
exit(0);
}
}
fclose(comms);
return 0;
}