I'm trying to implement the new linux gpio api. Using the v1 api, I was able to confirm that this code works:
// req is part of larger code
struct gpiohandle_request lreq;
memset(lreq.default_values, 0, sizeof(lreq.default_values));
strcpy(lreq.consumer_label, "TESTIO");
lreq.lines = req.bank_count[bank];
lreq.flags = GPIOHANDLE_REQUEST_OUTPUT;
for (int line = 0; line < lreq.lines; line++)
lreq.lineoffsets[line] = req.pins[bank][line];
if (ioctl(bank_fd[bank], GPIO_GET_LINEHANDLE_IOCTL, &lreq) < 0) {
std::cerr << "Error on chip io\n";
return -1;
}
However, when I try to switch to v2:
struct gpio_v2_line_request lreq;
lreq.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
lreq.config.num_attrs = 0;
strcpy(lreq.consumer, "TESTIO");
lreq.num_lines = req.bank_count[bank];
for (int line = 0; line < lreq.num_lines; line++) {
lreq.offsets[line] = req.pins[bank][line];
}
if (ioctl(bank_fd[bank], GPIO_V2_GET_LINE_IOCTL, &lreq) < 0) {
std::cerr << "Error on chip io\n";
return -1;
}
my ioctl always fails with errno 22
I'm not sure what the equivalent of memset(lreq.default_values, 0, sizeof(lreq.default_values)) is
Solution was to simply do this first:
memset(&lreq, 0, sizeof(lreq));
I guess that is the equivalent of the default values. Found in the master branch of libgpiod here
Related
I'm currently working on a (plain) C project, on Windows 7, and I need help.
The program is supposed to start playing a sound of given frequency when I press a key, and then stop it when I press another key.
Once it starts playing, it shouldn't stop until the user presses the second key, so I can't specify a duration.
Is there a way to do it with WinApi? I'm searching for a function like:
sound(frequency);
that would start playing a sound at frequency frequency.
If frequency is 0, then all sounds should stop.
I searched all over Stackoverflow, but I couldn't find any solution except Beep(); that needs a duration, and PlaySound(); that needs a wav file. I'd like to keep it simple. I don't want a big program that generates wav files, only a built-in function.
Ah, I did found such a function on Stack a few days ago, but I can't find it again.
(P.S: this question has no answer with WAV file synthesis from scratch. It's another question. So please do not tell me the close question has not been answered, because it's FALSE.)
Here is a program I wrote that uses waveOutOpen and waveOutWrite to generate 48 kHz stereo audio in real time. It is possible to generate the audio using the main thread, but this program launches a separate thread so that it can provide the nice kind of API you wanted.
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#define BUFFER_COUNT 4
#define BUFFER_SAMPLE_COUNT 1000
#define SAMPLES_PER_SECOND 48000
HWAVEOUT waveOut;
HANDLE waveEvent;
WAVEHDR headers[BUFFER_COUNT];
int16_t buffers[BUFFER_COUNT][BUFFER_SAMPLE_COUNT * 2];
WAVEHDR * currentHeader;
double volume = 6000;
double phase;
double phase_increment;
double audio_value;
void sound(double frequency) {
if (frequency == 0) {
phase_increment = 0;
return;
}
phase_increment = 2 * M_PI / SAMPLES_PER_SECOND * frequency;
}
void fill_buffer(int16_t * buffer) {
for (size_t i = 0; i < BUFFER_SAMPLE_COUNT * 2; i += 2) {
if (phase_increment == 0) {
phase = 0;
audio_value *= 0.9;
}
else {
phase += phase_increment;
if (phase > 0) { phase -= 2 * M_PI; }
audio_value = sin(phase) * volume;
}
buffer[i + 0] = audio_value; // Left channel
buffer[i + 1] = audio_value; // Right channel
}
}
__stdcall DWORD audio_thread(LPVOID param) {
while (1) {
DWORD waitResult = WaitForSingleObject(waveEvent, INFINITE);
if (waitResult) {
fprintf(stderr, "Failed to wait for event.\n");
return 1;
}
BOOL success = ResetEvent(waveEvent);
if (!success) {
fprintf(stderr, "Failed to reset event.\n");
return 1;
}
while (currentHeader->dwFlags & WHDR_DONE) {
fill_buffer((int16_t *)currentHeader->lpData);
MMRESULT result = waveOutWrite(waveOut, currentHeader, sizeof(WAVEHDR));
if (result) {
fprintf(stderr, "Failed to write wave data. Error code %u.\n", result);
return 1;
}
currentHeader++;
if (currentHeader == headers + BUFFER_COUNT) { currentHeader = headers; }
}
}
}
int audio_init() {
WAVEFORMATEX format = { 0 };
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2;
format.nSamplesPerSec = SAMPLES_PER_SECOND;
format.wBitsPerSample = 16;
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec;
waveEvent = CreateEvent(NULL, true, false, NULL);
if (waveEvent == NULL) {
fprintf(stderr, "Failed to create event.");
return 1;
}
MMRESULT result = waveOutOpen(&waveOut, WAVE_MAPPER, &format,
(DWORD_PTR)waveEvent, 0, CALLBACK_EVENT);
if (result) {
fprintf(stderr, "Failed to start audio output. Error code %u.\n", result);
return 1;
}
for (size_t i = 0; i < BUFFER_COUNT; i++) {
headers[i] = (WAVEHDR) {
.lpData = (char *)buffers[i],
.dwBufferLength = BUFFER_SAMPLE_COUNT * 4,
};
result = waveOutPrepareHeader(waveOut, &headers[i], sizeof(WAVEHDR));
if (result) {
fprintf(stderr, "Failed to prepare header. Error code %u.\n", result);
return 1;
}
headers[i].dwFlags |= WHDR_DONE;
}
currentHeader = headers;
HANDLE thread = CreateThread(NULL, 0, audio_thread, NULL, 0, NULL);
if (thread == NULL) {
fprintf(stderr, "Failed to start thread");
return 1;
}
return 0;
}
int main() {
if (audio_init()) { return 1; }
sound(400); Sleep(500);
sound(300); Sleep(500);
sound(600); Sleep(500);
for (int i = 0; i < 3; i++) {
sound(200); Sleep(50);
sound(0); Sleep(200);
sound(300); Sleep(50);
sound(0); Sleep(200);
sound(400); Sleep(50);
sound(0); Sleep(200);
sound(500); Sleep(50);
sound(0); Sleep(200);
sound(600); Sleep(50);
sound(0); Sleep(200);
}
}
I compiled in the MinGW 64-bit environment of MSYS2 using this command:
gcc -g -O2 -Wall -Wextra -Wno-unused-parameter wave.c -lwinmm -owave
Note the extra library I linked in: -lwinmm.
This code uses 4 buffers with 1000 samples each, so at any given time there will be no more than 83 ms worth of sound queued up to be played. This works fine on my system, but perhaps on other systems you might need to increase these parameters to ensure smooth playback. The buffer count is probably the first one I would try increasing if there are problems.
There might be some multithreading things I am getting wrong in the code. The phase_increment variable is written in the main thread and read in the audio thread. Perhaps I should explicitly make that be an atomic variable, and insert a memory barrier after I write to it.
sendmmsg/recvmmsg provide the option to send and receive multiple packets on socket in a single system call. Are these operations supported for TUN adaptor on Linux using C socket API.
Here is the sample code I tried but get errno=Socket operation on non-socket
struct mmsghdr hdrs[ARRAY_SIZE];
unsigned char data[ARRAY_SIZE][BUFF_SIZE];
struct iovec iovecs[ARRAY_SIZE];
memset(hdrs, 0, sizeof(hdrs));
for (int i = 0; i < ARRAY_SIZE; i++)
{
iovecs[i].iov_base = data[i];
iovecs[i].iov_len = BUFF_SIZE;
hdrs[i].msg_hdr.msg_iov = &iovecs[i];
hdrs[i].msg_hdr.msg_iovlen = 1;
}
while (true)
{
LOG_DEBUG(log__) << "blocking to read on fd=" << fd;
int retVal = recvmmsg(fd, hdrs, ARRAY_SIZE, 0, NULL);
LOG_DEBUG(log__) << "retVal=" << retVal;
if (retVal < 0)
{
LOG_ERROR(log__) << "failed in recvmmsg, retVal=" << retVal << ", errno=" << strerror(errno);
continue;
}
LOG_DEBUG(log__) << "read " << retVal << " messages";
for (int i = 0; i < retVal; i++)
{
LOG_DEBUG(log__) << "read data of length " << hdrs[i].msg_len;
}
}
Well I've been at this program for maybe four hours. I've been trying to create a little program to read what my arduino Uno is spitting out through the serial port.
What I find odd is that the program works only AFTER I've launched the arduino IDE's built in serial monitor. Perhaps this is an issue with initializing the port correctly?
If someone could help me out it'd be much appreciated. The program seems to hang during ReadFile, so maybe there's an issue with permissions...
#include Windows.h>
#include stdio.h>
#include tchar.h>//Removed to allow for stackoverflow format
void printCommState(DCB d);
int main() {
DCB dcb = { 0 };
HANDLE hPort;
BOOL success;
TCHAR *commPort = TEXT("COM3");
char buffer[40] = { 0 };
DWORD dwBytesRead = 0;
DWORD dwBytesWrite = 0;
int l;
/*COMMTIMEOUTS cTimeOut;
cTimeOut.ReadIntervalTimeout = 50;
cTimeOut.ReadTotalTimeoutConstant = 50;
cTimeOut.ReadTotalTimeoutMultiplier = 10;
cTimeOut.WriteTotalTimeoutConstant = 50;
cTimeOut.WriteTotalTimeoutMultiplier = 10;*/
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = CBR_9600;//Found on microsofts website
dcb.ByteSize = DATABITS_8;// standardized number?
dcb.Parity = NOPARITY;// found in comp management
dcb.StopBits = 1;
/*dcb.fBinary = 1;
dcb.fDtrControl = 1;
dcb.fTXContinueOnXoff = 1;
dcb.fRtsControl = 1;
dcb.XonLim = 2048;
dcb.XoffLim = 512;
dcb.XoffChar = 2;*/
//dcb.fDtrControl = DTR_CONTROL_DISABLE;//maybe unnecessary?
printCommState(dcb);
hPort = CreateFile(commPort, // This comm port is defined by TCHAR so that we can use TEXT() LPFILENAME
GENERIC_READ | GENERIC_WRITE,//DesiredAccess
0,//dwShareMode
NULL,//LPSecurity
CREATE_NEW| OPEN_EXISTING,//dwCreationDisposition
0,//Flags and attributes
NULL);//hTemplateFile
if (hPort == INVALID_HANDLE_VALUE) {
printf("CreateFile failed with the error %d.\n", GetLastError());
scanf_s("%d", &l);
return 1;
}
success = GetCommState(hPort, &dcb);
if (!success) {
printf("GetCommState failed with the error %d.\n ", GetLastError());
scanf_s("%d", &l);
return 2;
}
success = SetCommState(hPort, &dcb);
if (!success) {
printf("SetCommState failed with error %d.\n", GetLastError());
scanf_s("%d", &l);
return 3;
}
/*TIME TO READ STUFF*/
while (GetCommState(hPort, &dcb)) {
printf("We're in the while statement\n");
//+=+=+=+=+=+POSSIBLE PROBLEM?
if (ReadFile(hPort, buffer, 39, &dwBytesRead, NULL)) {
//hFile,lpBuffer,NumberofBytesToRead,LPnumberofbytestoread,lpOverlapped
printf("We're in the ifReadFile Statement!\n");
for (int j = 0; j < sizeof(buffer); j++) {
printf("in the for loop!\n");
printf("%c", buffer[j]);
}
printf("\n");
}
if (!ReadFile(hPort, &buffer, 39, &dwBytesRead, NULL)) {
printf("Error with ReadFile %d\n.", GetLastError());
}
}
scanf_s("%d", &l);
CloseHandle(hPort);
return 0;
}
void printCommState(DCB d) {
printf("\nBaudRate: %d\tByteSize: %d\tParity: %d\tStopBits: %d\n",
d.BaudRate,
d.ByteSize,
d.Parity,
d.StopBits);
}
The issue lies in the GetCommState line of the code
GetCommState code function
Here we have it setting the DCB to the settings returned by that function, so by adding another DCB (dcbRecieving, for instance as an example ) just as an error-catching device and having GetCommState point to that other DCB, we can keep our error catching DCB and set our original to the other one, or set the new parameters after the if statement.
Anyways, thanks a ton!
Hi I have written a program in c to communicate with /dev/ttyS0 to a device . when i do write i am able to do that but i get ERROR: Resource temporarily unavailable, -1 as return from read(). can you please check what i am doing wrong . the port is supposed to be a half duplex ,9600bps,8N1 , and a inter byte delay of 4ms . also can anyone tell me how to set inter byte delay in milliseconds. Below is my code.
#include<stdio.h>
#include<termios.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#define BAUDRATE B9600
#define PORT "/dev/ttyS0"
int main()
{
struct termios new_tio,old_new_tio;
int fd;
unsigned char msgS[5]="",msgR[10]="";
fd = open(PORT,O_RDWR|O_NOCTTY|O_NDELAY);
if(fd == -1)
printf("Failed to open PORT: %s \n\n",PORT);
perror("Error:");
tcgetattr(fd,&old_new_tio);
memset(&new_tio,0,sizeof(new_tio));
new_tio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD|CSIZE|PARENB;
new_tio.c_oflag = 0;
new_tio.c_iflag = 0;
new_tio.c_cc[VMIN] = 10;
new_tio.c_cc[VTIME] = 0.004;
cfsetispeed(&new_tio,BAUDRATE);
cfsetospeed(&new_tio,BAUDRATE);
new_tio.c_cc[VINTR] = 0;
new_tio.c_cc[VQUIT] = 0;
new_tio.c_cc[VERASE] = 0;
new_tio.c_cc[VKILL] = 0;
new_tio.c_cc[VEOF] = 4;
new_tio.c_cc[VSWTC] = 0; /* '\0' */
new_tio.c_cc[VSTART] = 0; /* Ctrl-q */
new_tio.c_cc[VSTOP] = 0; /* Ctrl-s */
new_tio.c_cc[VSUSP] = 0; /* Ctrl-z */
new_tio.c_cc[VEOL] = 0; /* '\0' */
new_tio.c_cc[VREPRINT] = 0; /* Ctrl-r */
new_tio.c_cc[VDISCARD] = 0; /* Ctrl-u */
new_tio.c_cc[VWERASE] = 0; /* Ctrl-w */
new_tio.c_cc[VLNEXT] = 0; /* Ctrl-v */
new_tio.c_cc[VEOL2] = 0;
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOW,&new_tio);
msgS[0] = '*';
msgS[1] = 'G';
msgS[2] = 'U';
msgS[3] = 'S';
msgS[4] = '\r';
printf("Message to be sent : %s \n\n",msgS);
int i = write(fd,&msgS,5);
if(i != 5)
printf("error while writing to the port\n\n");
int j = read(fd,&msgR,10);
if(j != 10)
printf("error while reading from port\n\n");
printf("Message Recieved : %s\n\n",msgR);
return 0;
}
You open the port in non-blocking mode (using O_NDELAY). Therefore your read would never block and only read what's already arrived. You should either use select to wait for the data first, or use a blocking mode.
I doubt you can fine-tune inter-byte delay. To increase it, you can enable using two stop bits instead of one (CSTOPB).
I'm debugging in VS2010. BIO_do_connect() fails in the following code. What am I doing wrong?
(pBio is properly set up before use)
static const uint32_t kuSleepIntervalInMs = 50;
...
uint32_t uTimeTaken = 0;
...
BIO_set_nbio(pBio, 1);
for (;;)
{
if (uTimeTaken > 10000)
return ERR_CONNECTION_TIMED_OUT;
if (BIO_do_connect(pBio) > 0)
break;
if (BIO_should_retry(pBio))
{
Sleep(kuSleepIntervalInMs);
uTimeTaken += kuSleepIntervalInMs;
continue;
}
BIO_free_all(pBio);
return ERR_FAILED_TO_ESTABLISH_CONNECTION;
}
It appears that if I increase the sleep interval (for example to 500), BIO_do_connect works fine but I'd like to know why it fails with shorter interval values.
Since posting my original question, I've switched to use select() so the problem is no longer valid.
Instead of doing
uTimeTaken += kuSleepIntervalInMs;
I'm now doing:
int nRet;
int fdSocket;
fd_set connectionfds;
struct timeval timeout;
BIO_set_nbio(pBio, 1);
nRet = BIO_do_connect(pBio);
if ((nRet <= 0) && !BIO_should_retry(pBio))
// failed to establish connection.
if (BIO_get_fd(pBio, &fdSocket) <= 0)
// failed to get fd.
if (nRet <= 0)
{
FD_ZERO(&connectionfds);
FD_SET(fdSocket, &connectionfds);
timeout.tv_usec = 0;
timeout.tv_sec = 10;
nRet = select(fdSocket + 1, NULL, &connectionfds, NULL, &timeout);
if (nRet == 0)
// timeout has occurred.
}
See my other post.