i try to write to the Linux framebuffer with c++, my problem is, that my program cant write to the whole screen, because the screensize i get is wrong. Although this code worked on an older VM, but i lost it.
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
int main() {
fb_var_screeninfo vinfo;
fb_fix_screeninfo finfo;
size_t screensize = 0;
long int location = 0;
/* Open the file for reading and writing */
int fbfd = open("/dev/fb0", O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
/* Get fixed screen information */
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
exit(2);
}
/* Get variable screen information */
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
exit(3);
}
/* Figure out the size of the screen in bytes */
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("Screen size is %ld\n", screensize);
printf("Vinfo.bpp = %d\n", vinfo.bits_per_pixel);
/* Map the device to memory */
auto fbp = static_cast<unsigned char*>(
mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0));
if(fbp == MAP_FAILED) {
perror("Error: failed to map framebuffer device to memory");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
unsigned x = 0;
unsigned y = 0; /* Where we are going to put the pixel */
/* Figure out where in memory to put the pixel */
location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) +
(y + vinfo.yoffset) * finfo.line_length;
for(uint32_t i = 0; i < vinfo.yres; i++) {
for(uint32_t count = 1; count < vinfo.xres; count++) {
fbp[location++] = 255; /* Some blue */
fbp[location++] = 0; /* A little green */
fbp[location++] = 0; /* A lot of red */
fbp[location++] = 0; /* No transparency */
}
}
munmap(fbp, screensize);
close(fbfd);
return 0;
}
I tried increasing the screensize by multiplying it by 2 and it wrote to the full screen, but then my coordinates are wrong.
Related
So I am trying to use libpng to write png's from an array of unsigned char that are a bit depth of 1. Meaning for all bits, there is only black and white, as a gray scale image. I have managed to do this successfully for 8-bit depth gray scale png, but not 1 bit depth. Here is the code i have :
extern int write_png_bwsq(const char* filename,
int dimen,
const unsigned char *buffer,
char* title)
{
int yrow;
int dim_bytes;
int code = 1;
FILE *fp = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep row = NULL;
dim_bytes = (dimen * dimen) / 8;
// Open file for writing (binary mode)
fp = fopen(filename, "wb");
if (fp == NULL) {
fprintf(stderr, "PNG ERROR: Could not open file %s for writing\n", filename);
code = 0;
goto finalise;
}
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fprintf(stderr, "PNG ERROR: Could not allocate PNG write struct\n");
code = 0;
goto finalise;
}
// Initialize info structure
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fprintf(stderr, "PNG ERROR: Could not allocate PNG info struct\n");
code = 0;
goto finalise;
}
// Setup Exception handling
if (setjmp(png_jmpbuf(png_ptr))) {
fprintf(stderr, "PNG Error: Creating the PNG output failed.\n");
code = 0;
goto finalise;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, dimen, dimen,
1, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// Sets the title
if (title != NULL) {
png_text title_text;
title_text.compression = PNG_TEXT_COMPRESSION_NONE;
title_text.key = "Title";
title_text.text = title;
png_set_text(png_ptr, info_ptr, &title_text, 1);
}
png_write_info(png_ptr, info_ptr);
row = (png_bytep) buffer;
// Write image data
for (yrow=0 ; yrow<dim_bytes ; yrow++) {
png_write_row(png_ptr, row);
++row;
}
// End write operation
png_write_end(png_ptr, NULL);
finalise:
if (fp != NULL) fclose(fp);
if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return code;
}
Then, i have a separate file where i prepare my image
#include "write_pngs.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#if CHAR_BIT != 8
# error "CHAR_BIT is not usable on this platform"
#endif
#define PIC_SIZE_DIM 1080
#define PIC_SIZE_BW ((PIC_SIZE_DIM * PIC_SIZE_DIM) / CHAR_BIT)
static unsigned char PIC_BITS[PIC_SIZE_BW] = {0};
static void __write_bits_pic(void)
{
size_t i = 1000;
for(;i < 140000;++i) {
PIC_BITS[i] = ((i + 76) >> 5) & 0xff;
}
}
int main(void) {
__write_bits_pic();
printf("Writing picture of %d bytes and %d bits\n", PIC_SIZE_BW, PIC_SIZE_BW * CHAR_BIT);
return !write_png_bwsq("bwpixs.png",
PIC_SIZE_DIM,
PIC_BITS,
"bwpixs");
}
This results in an incorrect image where its not only quite large for a png (about 5mb for only 1080 x 1080), but only the bottom right corner of the image is changed from black.
What am i doing wrong here ? Does libpng require any special steps for writing pngs that are only 1 in bit depth for gray scale i am not doing ?
You are calling png_write_row() way too many times. Your
for (yrow=0 ; yrow<dim_bytes ; yrow++) {
png_write_row(png_ptr, row);
++row;
}
should be something like:
for (yrow=0 ; yrow<dim_bytes ; yrow += dimen / 8) {
png_write_row(png_ptr, row);
row += dimen / 8;
}
in order to write a row of 1080 pixels (135 bytes). You were calling png_write_row() for every byte, as if the image is eight pixels wide. Which it isn't.
I'm completely new to C, but have a small program (interfacing with hardware on RaspberryPi) that I'd like to be able to run from Node.js. From what I can make out in the Node.js docs, I can run a C++ program by exporting the program as a NODE_MODULE http://nodejs.org/api/addons.html
I've been trying to figure out the differences between C and C++, but am unsure if I can just export the code I want to run as a C++ file (maybe by changing the file extension to .cc?) Or if there is another way to use the C code in node.js.
Also, I don't understand if I need to 'build' the C file, or if I can provide node.js with the .c file extension.
I do not want to run the C code using the Node's child process, though I know that is possible. I would much prefer to export the C code as a module, as the Node.js documents describe.
Here's the code I'm looking to run in node.js
// How to access GPIO registers from C-code on the Raspberry-Pi
// Example program
// 15-January-2012
// Dom and Gert
//
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
// WOULD I INCLUDE NODE.js HERE?? ##define BUILDING_NODE_EXTENSION
#include <node.h>
using namespace v8;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>
#define MAXTIMINGS 100
//#define DEBUG
#define DHT11 11
#define DHT22 22
#define AM2302 22
int readDHT(int type, int pin);
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
if (argc != 3) {
printf("usage: %s [11|22|2302] GPIOpin#\n", argv[0]);
printf("example: %s 2302 4 - Read from an AM2302 connected to GPIO #4\n", argv[0]);
return 2;
}
int type = 0;
if (strcmp(argv[1], "11") == 0) type = DHT11;
if (strcmp(argv[1], "22") == 0) type = DHT22;
if (strcmp(argv[1], "2302") == 0) type = AM2302;
if (type == 0) {
printf("Select 11, 22, 2302 as type!\n");
return 3;
}
int dhtpin = atoi(argv[2]);
if (dhtpin <= 0) {
printf("Please select a valid GPIO pin #\n");
return 3;
}
printf("Using pin #%d\n", dhtpin);
readDHT(type, dhtpin);
return 0;
} // main
int bits[250], data[100];
int bitidx = 0;
int readDHT(int type, int pin) {
int counter = 0;
int laststate = HIGH;
int j=0;
// Set GPIO pin to output
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(pin, HIGH);
usleep(500000); // 500 ms
bcm2835_gpio_write(pin, LOW);
usleep(20000);
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// wait for pin to drop?
while (bcm2835_gpio_lev(pin) == 1) {
usleep(1);
}
// read data!
for (int i=0; i< MAXTIMINGS; i++) {
counter = 0;
while ( bcm2835_gpio_lev(pin) == laststate) {
counter++;
//nanosleep(1); // overclocking might change this?
if (counter == 1000)
break;
}
laststate = bcm2835_gpio_lev(pin);
if (counter == 1000) break;
bits[bitidx++] = counter;
if ((i>3) && (i%2 == 0)) {
// shove each bit into the storage bytes
data[j/8] <<= 1;
if (counter > 200)
data[j/8] |= 1;
j++;
}
}
#ifdef DEBUG
for (int i=3; i<bitidx; i+=2) {
printf("bit %d: %d\n", i-3, bits[i]);
printf("bit %d: %d (%d)\n", i-2, bits[i+1], bits[i+1] > 200);
}
#endif
printf("Data (%d): 0x%x 0x%x 0x%x 0x%x 0x%x\n", j, data[0], data[1], data[2], data[3], data[4]);
if ((j >= 39) &&
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
// yay!
if (type == DHT11)
printf("Temp = %d *C, Hum = %d \%\n", data[2], data[0]);
if (type == DHT22) {
float f, h;
h = data[0] * 256 + data[1];
h /= 10;
f = (data[2] & 0x7F)* 256 + data[3];
f /= 10.0;
if (data[2] & 0x80) f *= -1;
printf("Temp = %.1f *C, Hum = %.1f \%\n", f, h);
}
return 1;
}
return 0;
}
If you're completely new to C, it might actually be less of a headache to do this all from javascript-land instead, using one of several modules on npm for interacting with GPIO (on the Pi). One such module is the onoff module.
I've been studying hashing in C/C++ and tried to replicate the md5sum command in Linux. After analysing the source code, it seems that md5sum relies on the md5 library's md5_stream. I've approximated the md5_stream function from the md5.h library into the code below, and it runs in ~13-14 seconds. I've tried to call the md5_stream function directly and got ~13-14 seconds. The md5sum runs in 4 seconds. What have the GNU people done to get the speed out of the code?
The md5.h/md5.c code is available in the CoreUtils source code.
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <iostream>
#include <iomanip>
#include <fstream>
#include "md5.h"
#define BLOCKSIZE 32784
int main()
{
FILE *fpinput, *fpoutput;
if ((fpinput = fopen("/dev/sdb", "rb")) == 0) {
throw std::runtime_error("input file doesn't exist");
}
struct md5_ctx ctx;
size_t sum;
char *buffer = (char*)malloc (BLOCKSIZE + 72);
unsigned char *resblock = (unsigned char*)malloc (16);
if (!buffer)
return 1;
md5_init_ctx (&ctx);
size_t n;
sum = 0;
while (!ferror(fpinput) && !feof(fpinput)) {
n = fread (buffer + sum, 1, BLOCKSIZE - sum, fpinput);
if (n == 0){
break;
}
sum += n;
if (sum == BLOCKSIZE) {
md5_process_block (buffer, BLOCKSIZE, &ctx);
sum = 0;
}
}
if (n == 0 && ferror (fpinput)) {
free (buffer);
return 1;
}
/* Process any remaining bytes. */
if (sum > 0){
md5_process_bytes (buffer, sum, &ctx);
}
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
free (buffer);
for (int x = 0; x < 16; ++x){
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(resblock[x]);
std::cout << " ";
}
std::cout << std::endl;
free(resblock);
return 0;
}
EDIT: Was a default mkspec problem in Fedora 19 64-bit.
fread() is convenient, but don't use fread() if you care about performance. fread() will copy from the OS to a libc buffer, then to your buffer. This extra copying cost CPU cycles and cache.
For better performance use open() then read() to avoid the extra copy. Make sure your read() calls are multiples of the block size, but lower than your CPU cache size.
For best performance use mmap() map the disk directly to RAM.
If you try something like the below code, it should go faster.
// compile gcc mmap_md5.c -lgcrypt
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gcrypt.h>
#include <linux/fs.h> // ioctl
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
unsigned char digest[16];
char digest_ascii[32+1] = {0,};
int digest_length = gcry_md_get_algo_dlen (GCRY_MD_MD5);
int i;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
if (sb.st_mode | S_IFBLK ) {
// block device. use ioctl to find length
ioctl(fd, BLKGETSIZE64, &length);
} else {
/* offset for mmap() must be page aligned */
if (offset >= sb.st_size) {
fprintf(stderr, "offset is past end of file size=%zd, offset=%d\n", sb.st_size, (int) offset);
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Canaqt display bytes past end of file */
} else { /* No length arg ==> display to end of file */
length = sb.st_size - offset;
}
}
printf("length= %zd\n", length);
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
gcry_md_hash_buffer(GCRY_MD_MD5, digest, addr + offset - pa_offset, length);
for (i=0; i < digest_length; i++) {
sprintf(digest_ascii+(i*2), "%02x", digest[i]);
}
printf("hash=%s\n", digest_ascii);
exit(EXIT_SUCCESS);
}
It turned out to be an error in the Qt mkspecs regarding an optimization flag not being set properly.
I am trying to play a wave file in RHEL6 using alsa library calls in my C Code in Qt. I am reading the wave file ("t15.wav") in a buffer(wave_buffer). The wave header has been stripped off since the alsa library requires raw PCM samples to be played. Further I have set up the PCM hardware & Software params using 'snd_pcm_hw_params(PCM, params)' & 'snd_pcm_sw_params_current(PCM, swparams)' and many other calls. I am writing the PCM samples on the PCM handle using 'snd_pcm_writei' command. For this purpose i am reading a chunk(32 or 1024 or 2048 or 4096 or 8192 bytes) of data from the wave_buffer and sending it for playing using the snd_pcm_writei command. If I choose a small chunk the audio quality falters but playback is uninterrupted. If I use a bigger chunk(greater than 4096 i.e. 8192) I get perfect audio quality but it is interrupted( When next chunk of data is required for playing ). My constraint is that I can have access to data in chunks only and not as a file or entire buffer. Can anybody help me in removing the interruptions in playing the wave data so that I can get uninterrupted audio playback. Following is my code :
The two variables buffer_time & period_time return the period size which is the size of chunk.
If buffer_time = 5000 & period_time=1000 the period_size returned by alsa library is 32 bytes //audio quality falters but no interruptions
If buffer_time = 500000 & period_time=100000 the period_size returned by alsa library is 8192 bytes //good audio quality but interrupted
Tuning these parameters seems useless as I have wasted a lot of time doing this. Please help me get through this problem-----
Stucture of Wave File :
Sample Rate : 44100
Bits per Sample : 16
Channels : 2
mainwindow.h----
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <alsa/asoundlib.h>
#define BLOCKSIZE 44100 * 2 * 2 // Sample Rate * Channels * Byte per Sample(Bits per sample / 8)
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
int init_alsa();
int play_snd();
~MainWindow();
snd_pcm_t *PCM;
snd_pcm_sframes_t delayp;
snd_pcm_sframes_t availp;
snd_pcm_sw_params_t *swparams;
snd_pcm_hw_params_t *params;
static snd_pcm_sframes_t period_size;
static snd_pcm_sframes_t buffer_size;
unsigned char wave_buffer[900000];
unsigned char play_buffer[BLOCKSIZE];
int filesize;
FILE *fp;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp---
#include "mainwindow.h"
#include "ui_mainwindow.h"
snd_pcm_sframes_t MainWindow::period_size;
snd_pcm_sframes_t MainWindow::buffer_size;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
if((fp = fopen("t15.wav","rb"))==NULL)
printf("Error Opening File");
fseek(fp,0L,SEEK_END);
filesize = ftell(fp)-44;
fseek(fp,0L,SEEK_SET);
fseek(fp,44,SEEK_SET);
fread(wave_buffer,filesize,1,fp);
fclose(fp);
delayp = 0;
init_alsa();
play_snd();
}
MainWindow::~MainWindow()
{
delete ui;
}
int MainWindow::init_alsa()
{
unsigned int rate = 44100;
int err,dir;
unsigned int rrate = 44100;
snd_pcm_uframes_t size;
static unsigned int buffer_time = 500000;
static unsigned int period_time = 100000;
static int period_event = 0;
if ((err=snd_pcm_open(&PCM,"plughw:0,0",SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf(stderr, "Can't use sound: %s\n", snd_strerror(err));
return err;
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_sw_params_alloca(&swparams);
//snd_pcm_nonblock(PCM,0);
/* choose all parameters */
err = snd_pcm_hw_params_any(PCM, params);
if (err < 0) {
printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
return err;
}
/* set hardware resampling */
err = snd_pcm_hw_params_set_rate_resample(PCM, params, 1);
if (err < 0) {
printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
return err;
}
/* set the interleaved read/write format */
err = snd_pcm_hw_params_set_access(PCM, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
printf("Access type not available for playback: %s\n", snd_strerror(err));
return err;
}
/* set the sample format */
err = snd_pcm_hw_params_set_format(PCM, params, SND_PCM_FORMAT_S16_LE);
if (err < 0) {
printf("Sample format not available for playback: %s\n", snd_strerror(err));
return err;
}
/* set the count of channels */
err = snd_pcm_hw_params_set_channels(PCM, params, 2);
if (err < 0) {
printf("Channels count (%i) not available for playbacks: %s\n", 2, snd_strerror(err));
return err;
}
/* set the stream rate */
rrate = rate;
err = snd_pcm_hw_params_set_rate_near(PCM, params, &rrate, 0);
if (err < 0) {
printf("Rate %iHz not available for playback: %s\n", 44100, snd_strerror(err));
return err;
}
if (rrate != 44100) {
printf("Rate doesn't match (requested %iHz, get %iHz)\n", rrate, err);
return -EINVAL;
}
/* set the buffer time */
err = snd_pcm_hw_params_set_buffer_time_near(PCM, params, &buffer_time, &dir);
if (err < 0) {
printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_buffer_size(params, &size);
if (err < 0) {
printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
return err;
}
buffer_size = size;
/* set the period time */
err = snd_pcm_hw_params_set_period_time_near(PCM, params, &period_time, &dir);
if (err < 0) {
printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
if (err < 0) {
printf("Unable to get period size for playback: %s\n", snd_strerror(err));
return err;
}
period_size = size;
/* write the parameters to device */
err = snd_pcm_hw_params(PCM, params);
if (err < 0) {
printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
return err;
}
printf("Size = %ld",period_size);
snd_pcm_sw_params_current(PCM, swparams); /* get the current swparams */
/* start the transfer when the buffer is almost full: */
/* (buffer_size / avail_min) * avail_min */
snd_pcm_sw_params_set_start_threshold(PCM, swparams, (buffer_size / period_size) * period_size);
/* allow the transfer when at least period_size samples can be processed */
/* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
snd_pcm_sw_params_set_avail_min(PCM, swparams, period_event ? buffer_size : period_size);
snd_pcm_sw_params(PCM, swparams);/* write the parameters to the playback device */
return 1;
}
int MainWindow::play_snd()
{
int curr_pos = 0;
int buff_size = 0;
long val = 0;
while(curr_pos < filesize)
{
if(filesize-curr_pos >= period_size)
{
memcpy(play_buffer,wave_buffer+curr_pos,period_size);
buff_size = period_size;
curr_pos += buff_size;
}
else
{
memcpy(play_buffer,wave_buffer+curr_pos,filesize-curr_pos);
buff_size = filesize - curr_pos;
curr_pos += buff_size;
}
int i=1;
unsigned char *ptr = play_buffer;
while(buff_size > 0)
{
val = snd_pcm_writei(PCM,&play_buffer,buff_size);
if (val == -EAGAIN)
continue;
ptr += val * 2;
buff_size -= val;
}
}
return 0;
}
I have a similar C Code of alsa library which generates sine wave samples at runtime and plays them using same snd_pcm_writei command and it plays perfectly without any interruptions....This is the alsa library code---
/*
* This small demo sends a simple sinusoidal wave to your speakers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include "alsa/asoundlib.h"
#include <sys/time.h>
#include <math.h>
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 44100; /* stream rate */
static unsigned int channels = 2; /* count of channels */
static unsigned int buffer_time = 5000; /* ring buffer length in us */
static unsigned int period_time = 1000; /* period time in us */
static double freq = 440; /* sinusoidal wave frequency in Hz */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
static snd_pcm_sframes_t buffer_size;
static snd_pcm_sframes_t period_size;
static snd_output_t *output = NULL;
snd_pcm_sframes_t delayp;
snd_pcm_sframes_t availp;
static void generate_sine(const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset,
int count, double *_phase)
{
static double max_phase = 2. * M_PI;
double phase = *_phase;
double step = max_phase*freq/(double)rate;
unsigned char *samples[channels];
int steps[channels];
unsigned int chn;
int format_bits = snd_pcm_format_width(format);
unsigned int maxval = (1 << (format_bits - 1)) - 1;
int bps = format_bits / 8; /* bytes per sample */
int phys_bps = snd_pcm_format_physical_width(format) / 8;
int big_endian = snd_pcm_format_big_endian(format) == 1;
int to_unsigned = snd_pcm_format_unsigned(format) == 1;
int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
format == SND_PCM_FORMAT_FLOAT_BE);
/* verify and prepare the contents of areas */
for (chn = 0; chn < channels; chn++) {
samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
steps[chn] = areas[chn].step / 8;
samples[chn] += offset * steps[chn];
}
/* fill the channel areas */
while (count-- > 0) {
union {
float f;
int i;
} fval;
int res, i;
if (is_float)
{
fval.f = sin(phase) * maxval;
res = fval.i;
}
else
res = sin(phase) * maxval;
if (to_unsigned)
res ^= 1U << (format_bits - 1);
for (chn = 0; chn < channels; chn++) {
/* Generate data in native endian format */
if (big_endian) {
for (i = 0; i < bps; i++)
*(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
} else {
for (i = 0; i < bps; i++)
*(samples[chn] + i) = (res >> i * 8) & 0xff;
}
samples[chn] += steps[chn];
}
phase += step;
if (phase >= max_phase)
phase -= max_phase;
}
*_phase = phase;
}
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access)
{
unsigned int rrate;
snd_pcm_uframes_t size;
int dir;
snd_pcm_hw_params_any(handle, params); /* choose all parameters */
snd_pcm_hw_params_set_rate_resample(handle, params, resample);/* set hardware resampling */
snd_pcm_hw_params_set_access(handle, params, access); /* set the interleaved read/write format */
snd_pcm_hw_params_set_format(handle, params, format); /* set the sample format */
snd_pcm_hw_params_set_channels(handle, params, channels); /* set the count of channels */
rrate = rate; /* set the stream rate */
snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);/* set the buffer time */
snd_pcm_hw_params_get_buffer_size(params, &size);
buffer_size = size;
snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);/* set the period time */
snd_pcm_hw_params_get_period_size(params, &size, &dir);
period_size = size;
snd_pcm_hw_params(handle, params); /* write the parameters to device */
return 0;
}
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
{
snd_pcm_sw_params_current(handle, swparams); /* get the current swparams */
/* start the transfer when the buffer is almost full: */
/* (buffer_size / avail_min) * avail_min */
snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
/* allow the transfer when at least period_size samples can be processed */
/* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
snd_pcm_sw_params(handle, swparams);/* write the parameters to the playback device */
return 0;
}
/*
* Transfer method - write only
*/
static int write_loop(snd_pcm_t *handle, signed short *samples, snd_pcm_channel_area_t *areas)
{
double phase = 0;
signed short *ptr;
int err, cptr;
int i=0;
printf("Period Size = %ld",period_size);
while (1) {
fflush(stdout);
generate_sine(areas, 0, period_size, &phase);
ptr = samples;
cptr = period_size;
i=1;
while (cptr > 0) {
err = snd_pcm_writei(handle, ptr, cptr);
snd_pcm_avail_delay(handle,&availp,&delayp);
printf("available frames =%ld delay = %ld i = %d\n",availp,delayp,i);
if (err == -EAGAIN)
continue;
ptr += err * channels;
cptr -= err;
i++;
}
}
}
/*
* Transfer method - asynchronous notification
*/
int main()
{
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
signed short *samples;
unsigned int chn;
snd_pcm_channel_area_t *areas;
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
snd_output_stdio_attach(&output, stdout, 0);
printf("Playback device is %s\n", device);
printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
printf("Sine wave rate is %.4fHz\n", freq);
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
set_swparams(handle, swparams);
samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8);
areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
for (chn = 0; chn < channels; chn++) {
areas[chn].addr = samples;
areas[chn].first = chn * snd_pcm_format_physical_width(format);
areas[chn].step = channels * snd_pcm_format_physical_width(format);
}
write_loop(handle, samples, areas);
free(areas);
free(samples);
snd_pcm_close(handle);
return 0;
}
I solved the problem by altering the length argument of snd_pcm_writei...perviously i was giving it equal to the data contained in play_buffer...now i changed it to "buff_size/4" and the audio is playing perfectly without breaks. Actually it is the size after which the system should start buffering for new pcm samples as per my understanding. Previously it was buffering after playing the entire length buff_size and that resulted in breaks in audio output...
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
int main()
{
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
char fbp = 0;
int x = 0, y = 0;
long int location = 0;
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
exit(3);
}
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE,
MAP_SHARED, fbfd, 0);
if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
for (y = 0; y < 240; y++)
{
for (x = 0; x < 320; x++)
{
x = 100; y = 100; // Where we are going to put the pixel
// Figure out where in memory to put the pixel
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/4) + (y+vinfo.yoffset) * finfo.line_length;
*(fbp + location)= 255;
}
}
munmap(fbp, screensize);
close(fbfd);
return 0;
}
ERROR:in line number 57
getting error: invalid type argument of ‘unary *' (have ‘long int')
char fbp = 0;
should have been
char *fbp;