APDU Write block commands on mifare card - c++

I have been trying to writing some data to my mifare classic cards. first I send these two commands which returns 90 00:
Load Mifare Keys:
FF 82 20 01 06 FF FF FF FF FF FF
Authenticate:
FF 86 00 03 05 01 00 05 60 00
now I'm write commands to sector 0 and block 3 and block 4 by this commands
APDU_WRITE_data_1 : FF D 00 03 16
APDU_WRITE_data_1 : FF D 00 04 16
// writedata1 in block 3 ...
//
if (nres == SM_SUCCESS)// &&
//bAPDURes )
{
nlenrcv = sizeof(btRcv);
nlencmd = 0;
btCmd[nlencmd++] = 0xFF; // CLA
btCmd[nlencmd++] = 0xD6; // INS
btCmd[nlencmd++] = 0x00; // P1, Mifare Block Number MSB
btCmd[nlencmd++] = 0x03; // P2, Mifare Block Number LSB
btCmd[nlencmd++] = 16; // Lc, Data Length
memcpy(btCmd + nlencmd, btWrite_1, 16);
nlencmd += 16;
nres = m_Smart.RFTransmit(DEV_INTERNALRF, nlencmd, btCmd, (DWORD*)&nlenrcv, btRcv_1);
// writedata2 in block 4 ...
if (nres == SM_SUCCESS)// &&
//bAPDURes )
{
nlenrcv = sizeof(btRcv);
nlencmd = 0;
btCmd[nlencmd++] = 0xFF; // CLA
btCmd[nlencmd++] = 0xD6; // INS
btCmd[nlencmd++] = 0x00; // P1, Mifare Block Number MSB
btCmd[nlencmd++] = 0x04; // P2, Mifare Block Number LSB
btCmd[nlencmd++] = 16; // Lc, Data Length
memcpy(btCmd + nlencmd, btWrite_2, 16);
nlencmd += 16;
nres = m_Smart.RFTransmit(DEV_INTERNALRF, nlencmd, btCmd, (DWORD*)&nlenrcv, btRcv_2);
But it doesn't work
is it the APDU for writing wrong?

Related

Fastest way for wrapping a value in an interval

I am curious about the ways to wrap a floating-point value x in a semi-closed interval [0; a[.
For instance, I could have an arbitrary real number, say x = 354638.515, that I wish to fold into [0; 2π[ because I have a good sin approximation for that range.
The fmod standard C functions show up quite high in my benchmarks, and by checking the source code of various libc implementations, I can understand why: the thing is fairly branch-ey, likely in order to handle a lot of IEEE754-specific issues:
glibc: https://github.com/bminor/glibc/blob/master/sysdeps/ieee754/flt-32/e_fmodf.c
Apple: https://opensource.apple.com/source/Libm/Libm-315/Source/ARM/fmod.c.auto.html
musl: https://git.musl-libc.org/cgit/musl/tree/src/math/fmod.c
Running with -ffast-math causes GCC to generate code that goes through the x87 FPU on x86/x86_64 which comes with its own set of problems (such as 80-bit doubles, FP state, and other fun things). I would like the implementation to vectorize at least semi-correctly, and if possible to not go through the x87 FPU but through vector registers at least as the rest of my code ends up vectorized, even if not necessarily an optimal way, by the compiler.
This one looks much simpler: https://github.com/KnightOS/libc/blob/master/src/fmod.c
In my case, I am only concerned about usual real values, not NaNs, not infinity. My range is also known at compile-time and sane (a common occurence being π/2), thus the checks for "special cases" such as range == 0 are unnecessary.
Thus, what would be good implementations of fmod for that specific use case ?
Assuming that the range is constant and positive you can compute its reciprocal to avoid costly division.
void fast_fmod(float * restrict dst, const float * restrict src, size_t n, float divisor) {
float reciprocal = 1.0f / divisor;
for (size_t i = 0; i < n; ++i)
dst[i] = src[i] - divisor * (int)(src[i] * reciprocal);
}
The final code with a simple demo is:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
void fast_fmod(float * restrict dst, const float * restrict src, size_t n, float divisor) {
float reciprocal = 1.0f / divisor;
for (size_t i = 0; i < n; ++i)
dst[i] = src[i] - divisor * (int)(src[i] * reciprocal);
}
int main() {
float src[9] = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
float dst[9];
float div = 3;
fast_fmod(dst, src, 9, div);
for (int i = 0; i < 9; ++i) {
printf("fmod(%g, %g) = %g vs %g\n", src[i], div, dst[i], fmod(src[i], div));
}
}
produces an expected output:
fmod(-4, 3) = -1 vs -1
fmod(-3, 3) = 0 vs -0
fmod(-2, 3) = -2 vs -2
fmod(-1, 3) = -1 vs -1
fmod(0, 3) = 0 vs 0
fmod(1, 3) = 1 vs 1
fmod(2, 3) = 2 vs 2
fmod(3, 3) = 0 vs 0
fmod(4, 3) = 1 vs 1
Compilation with GCC with command:
$ gcc prog.c -o prog -O3 -march=haswell -lm -fopt-info-vec
prog.c:8:4: optimized: loop vectorized using 32 byte vectors
prog.c:8:4: optimized: loop vectorized using 32 byte vectors
prog.c:8:30: optimized: basic block part vectorized using 32 byte vectors
Thus the code was nicely vectorized.
EDIT
It looks that CLANG does even a better job vectorizing this code:
401170: c5 fc 10 24 8e vmovups (%rsi,%rcx,4),%ymm4
401175: c5 fc 10 6c 8e 20 vmovups 0x20(%rsi,%rcx,4),%ymm5
40117b: c5 fc 10 74 8e 40 vmovups 0x40(%rsi,%rcx,4),%ymm6
401181: c5 fc 10 7c 8e 60 vmovups 0x60(%rsi,%rcx,4),%ymm7
401187: c5 6c 59 c4 vmulps %ymm4,%ymm2,%ymm8
40118b: c5 6c 59 cd vmulps %ymm5,%ymm2,%ymm9
40118f: c5 6c 59 d6 vmulps %ymm6,%ymm2,%ymm10
401193: c5 6c 59 df vmulps %ymm7,%ymm2,%ymm11
401197: c4 41 7e 5b c0 vcvttps2dq %ymm8,%ymm8
40119c: c4 41 7e 5b c9 vcvttps2dq %ymm9,%ymm9
4011a1: c4 41 7e 5b d2 vcvttps2dq %ymm10,%ymm10
4011a6: c4 41 7e 5b db vcvttps2dq %ymm11,%ymm11
4011ab: c4 41 7c 5b c0 vcvtdq2ps %ymm8,%ymm8
4011b0: c4 41 7c 5b c9 vcvtdq2ps %ymm9,%ymm9
4011b5: c4 41 7c 5b d2 vcvtdq2ps %ymm10,%ymm10
4011ba: c4 41 7c 5b db vcvtdq2ps %ymm11,%ymm11
4011bf: c5 3c 59 c3 vmulps %ymm3,%ymm8,%ymm8
4011c3: c5 34 59 cb vmulps %ymm3,%ymm9,%ymm9
4011c7: c5 2c 59 d3 vmulps %ymm3,%ymm10,%ymm10
4011cb: c5 24 59 db vmulps %ymm3,%ymm11,%ymm11
4011cf: c4 c1 5c 5c e0 vsubps %ymm8,%ymm4,%ymm4
4011d4: c4 c1 54 5c e9 vsubps %ymm9,%ymm5,%ymm5
4011d9: c4 c1 4c 5c f2 vsubps %ymm10,%ymm6,%ymm6
4011de: c4 c1 44 5c fb vsubps %ymm11,%ymm7,%ymm7
4011e3: c5 fc 11 24 8f vmovups %ymm4,(%rdi,%rcx,4)
4011e8: c5 fc 11 6c 8f 20 vmovups %ymm5,0x20(%rdi,%rcx,4)
4011ee: c5 fc 11 74 8f 40 vmovups %ymm6,0x40(%rdi,%rcx,4)
4011f4: c5 fc 11 7c 8f 60 vmovups %ymm7,0x60(%rdi,%rcx,4)
4011fa: 48 83 c1 20 add $0x20,%rcx
4011fe: 48 39 c8 cmp %rcx,%rax
401201: 0f 85 69 ff ff ff jne 401170 <fast_fmod+0x40>
This is a fmod()-alternative without precision loss I wrote.
The computation can take very long if the counter has a very high exponent and the denominator has a very low exponent, but it is still faster than the current Gnu C libary implementation:
#include <stdint.h>
#include <string.h>
#include <fenv.h>
#if defined(_MSC_VER)
#include <intrin.h>
#endif
#if defined(__GNUC__) || defined(__clang__)
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#define MAX_EXP (0x7FF)
#define SIGN_BIT ((uint64_t)1 << 63)
#define EXP_MASK ((uint64_t)MAX_EXP << 52)
#define IMPLCIT_BIT ((uint64_t)1 << 52)
#define MANT_MASK (IMPLCIT_BIT - 1)
#define QNAN_BIT (IMPLCIT_BIT >> 1)
inline uint64_t bin( double d )
{
uint64_t u;
memcpy( &u, &d, sizeof d );
return u;
}
inline double dbl( uint64_t u )
{
double d;
memcpy( &d, &u, sizeof u );
return d;
}
inline double NaN()
{
feraiseexcept( FE_INVALID );
return dbl( SIGN_BIT | EXP_MASK | QNAN_BIT );
}
inline void normalize( uint64_t *mant, int *exp )
{
#if defined(__GNUC__) || defined(__clang__)
unsigned bits = __builtin_clz( *mant ) - 11;
*mant <<= bits;
#elif defined(_MSC_VER)
unsigned long bits;
_BitScanReverse64( &bits, *mant );
bits = (bits ^ 63) - 11;
*mant <<= bits;
#else
unsigned bits = 0;
for( ; !(*mant & IMPLCIT_BIT); *mant <<= 1, ++bits );
#endif
*exp -= bits;
}
double myFmodC( double counter, double denominator )
{
uint64_t const
bCounter = bin( counter ),
bDenom = bin( denominator );
uint64_t const sign = bCounter & SIGN_BIT;
if( unlikely((bCounter & EXP_MASK) == EXP_MASK) )
// +/-[Inf|QNaN|SNaN] % ... = -QNaN
return NaN();
if( unlikely((bDenom & EXP_MASK) == EXP_MASK) )
// +/-x % +/-[Inf|QNan|SNaN]
if( likely(!(bDenom & MANT_MASK)) )
// +/-x % +/-Inf = -/+x
return dbl( sign | bCounter & ~SIGN_BIT );
else
// +/-x % +/-[QNaN|SNaN] = -NaN
return NaN();
int
counterExp = bCounter >> 52 & MAX_EXP,
denomExp = bDenom >> 52 & MAX_EXP;
uint64_t
counterMant = (uint64_t)!!counterExp << 52 | bCounter & MANT_MASK,
denomMant = (uint64_t)!!denomExp << 52 | bDenom & MANT_MASK;
if( unlikely(!counterExp) )
// counter is denormal
if( likely(!counterMant) )
// counter == +/-0.0
if( likely(denomMant) )
// +/-0.0 % +/-x = -/+0.0
return dbl( sign );
else
// +/-0.0 % +/-0.0 = -QNaN
return NaN();
else
// normalize counter
normalize( &counterMant, &counterExp ),
++counterExp;
if( unlikely(!denomExp) )
// denominator is denormal
if( likely(!denomMant) )
// +/-x % +/-0.0 = -/+QNaN
return NaN();
else
// normalize denominator
normalize( &denomMant, &denomExp ),
++denomExp;
int remExp = counterExp;
uint64_t remMant = counterMant;
for( ; ; )
{
int below = remMant < denomMant;
if( unlikely(remExp - below < denomExp) )
break;
remExp -= below;
remMant <<= below;
if( unlikely(!(remMant -= denomMant)) )
{
remExp = 0;
break;
}
normalize( &remMant, &remExp );
};
if( unlikely(remExp <= 0) )
// denormal result
remMant >>= -remExp + 1,
remExp = 0;
return dbl( sign | (uint64_t)remExp << 52 | remMant & MANT_MASK );
}

Values of padding bytes in C

I've spotted a strange behavior in this small C program. I have 2 structures, both with padding bytes, but in different places.
The first structure has padding bytes with indices [1:3], and the output is expected: static variables are zeroed-out, so padding values are all 0, local variables on stack are left with garbage values in padding bytes. Example output:
Char is first, then int:
aa 60 8e ef ff ff ff ff
aa 00 00 00 ff ff ff ff
But in the second structure, something strange happens. Padding bytes in this structure are with indices [5:7], so I expected some garbage values in non-static variable, but every time the output is:
Int is first, then char:
ff ff ff ff aa 7f 00 00
ff ff ff ff aa 00 00 00
Why the padding is always 7f 00 00?
The complete program:
#include "stdio.h"
#include "stdint.h"
#include "stddef.h"
// 0 1 2 3 4 5 6 7
// |a|#|#|#|b|b|b|b|
typedef struct
{
uint8_t a;
uint32_t b;
} S1;
// 0 1 2 3 4 5 6 7
// |a|a|a|a|b|#|#|#|
typedef struct
{
uint32_t a;
uint8_t b;
} S2;
void print_bytes(void* mem, size_t num_bytes)
{
for (size_t i = 0; i < num_bytes; i++)
printf("%02x ", *((unsigned char*)mem + i));
putc('\n', stdout);
}
int main()
{
S1 var1 = { .a = 0xAA, .b = 0xFFFFFFFF };
static S1 var1_s = { .a = 0xAA, .b = 0xFFFFFFFF };
printf("Char is first, then int:\n");
print_bytes(&var1, sizeof(S1));
print_bytes(&var1_s, sizeof(S1));
S2 var2 = { .a = 0xFFFFFFFF, .b = 0xAA };
static S2 var2_s = { .a = 0xFFFFFFFF, .b = 0xAA };
printf("\nInt is first, then char:\n");
print_bytes(&var2, sizeof(S2));
print_bytes(&var2_s, sizeof(S2));
}
There's no problem if I run your program. Last bytes are random. It likely depends on your system.

How to send an array of bytes between nucleo f446re with mbed through USB with UARTSerial class?

I have to send an array of data between a nucleo f446re and a pc with ubuntu using the UARTSerial class.
The code that I'm using on the mbed is the following:
int main() {
UARTSerial pc(USBTX, USBRX, 921600);
uint8_t buff[256] = {
5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4
};
pc.sync();
while(true) {
pc.write(buff, 23);
pc.sync();
wait(1);
}
return 0;
}
The code that I'm running on the pc is:
int main() {
struct termios tattr{0};
// open the device in read/write sync
int com = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_SYNC );
if (com == -1)
throw std::runtime_error("ERROR: can't open the serial");
tcgetattr(com, &tattr);
tattr.c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON);
tattr.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
tattr.c_cflag = CS8 | CREAD | CLOCAL;
tattr.c_lflag &= ~(ICANON|ECHO);
tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0;
tattr.c_ispeed = 921600;
tattr.c_ospeed = 921600;
tcsetattr (com, TCSAFLUSH, &tattr);
while (true) {
usleep(1000);
tcflush(com, TCIOFLUSH);
uint8_t buff[24];
::read(com, buff, 23);
printf("reading frame... ");
for (auto b : buff) {
printf("%02X ", b);
}
puts("\n");
}
}
The output that I receive on the pc is:
[...]
reading frame... 00 00 8D 9C 1E 7F 00 00 00 00 00 00 00 00 00 00 70 5B C7 01 AD 55 00 00
reading frame... 00 00 8D 9C 1E 7F 00 00 00 00 00 00 00 00 00 00 70 5B C7 01 AD 55 00 00
[...]
As you can see the result is not the same that I'm expecting.
I've already tried to send one byte at a time with a loop, but the result is the same.
I cannot understand why I can't read the USB I've tried to flush the usb both on the pc and on the nucleo board.
you have to use a decoder to decode the bytes from the serial port
see the link below:
https://codereview.stackexchange.com/questions/200846/a-simple-and-efficient-packet-frame-encoder-decoder
I found the problem. It was the setting of the baudrate, I have to use this lines:
// receive speed
cfsetispeed (&tattr, B921600);
// transmit speed
cfsetospeed (&tattr, B921600);
instead of this:
// receive speed
tattr.c_ispeed = 921600;
tattr.c_ospeed = 921600;

vector or array value insertion

I have a variable
long long int alpha;
This alpha is basically 8 bytes
but I wish the byte size can be decided dynamically by input to the function.
So that it could be inserted to char* array.
If there is a function
int putInput(int sizeOfAlpha){
long long int alpha;
char* beta = (char*)malloc(128);
for(int i = 0 ; i < 128 ; i++){
... alpha calculation ...
beta[i*sizeOfAlpha] = alpha; // This is also wrong
}
}
Then the size of alpha has to be modified by sizeOfAlpha
For instance if sizeOfAlpha is 2 in decimal,
and if alpha is 0x00 00 00 00 00 00 04 20 in hex,
and if i is 0 ,
then beta[0] should be 04 and beta[1] should be 20 in hex
if alpha is 0x00 00 00 00 00 00 42 AB in hex,
and if i is 1 ,
then beta[2] should be 42 and beta[3] should be AB in hex
Can anyone help me with this?
Assuming alpha is unsigned :
std::vector<std::uint8_t> vec(8);
for(std::size_t j = (i + 1u) * sizeOfAlpha - 1u; sizeOfAlpha; --j, --sizeOfAlpha) {
vec[j] = alpha & 0xff;
alpha >>= 8;
}
Live on Coliru

Encoding WAV file cuts off early

In my previous question here, I managed to get a working .wav file as the output. However, when I throw this .wav file into my encoder (tested with other .wav files and works perfectly), my encoder throws back an error back at me right before it finishes.
Here is my output:
$ ./capture 2
Capture device is plughw:1,0
Finished writing to /tmp/filevXDDX6.wav
Starting encode to /tmp/filevXDDX6.flac
Wrote 3641 bytes, 4096/88200 samples, 2/22 frames
Wrote 6132 bytes, 8192/88200 samples, 2/22 frames
Wrote 8748 bytes, 12288/88200 samples, 3/22 frames
Wrote 11253 bytes, 16384/88200 samples, 4/22 frames
Wrote 13697 bytes, 20480/88200 samples, 5/22 frames
Wrote 16222 bytes, 24576/88200 samples, 6/22 frames
Wrote 18811 bytes, 28672/88200 samples, 7/22 frames
Wrote 21900 bytes, 32768/88200 samples, 8/22 frames
Wrote 24681 bytes, 36864/88200 samples, 9/22 frames
Wrote 27408 bytes, 40960/88200 samples, 10/22 frames
Wrote 30494 bytes, 45056/88200 samples, 11/22 frames
Wrote 34107 bytes, 49152/88200 samples, 12/22 frames
Wrote 37447 bytes, 53248/88200 samples, 13/22 frames
Wrote 40719 bytes, 57344/88200 samples, 14/22 frames
Wrote 45257 bytes, 61440/88200 samples, 15/22 frames
Wrote 48735 bytes, 65536/88200 samples, 16/22 frames
Wrote 52842 bytes, 69632/88200 samples, 17/22 frames
Wrote 56529 bytes, 73728/88200 samples, 18/22 frames
Wrote 60185 bytes, 77824/88200 samples, 19/22 frames
Wrote 63906 bytes, 81920/88200 samples, 20/22 frames
ERROR: reading from WAVE file
Wrote 67687 bytes, 86016/88200 samples, 21/22 frames
Encoding: FAILED
State: FLAC__STREAM_ENCODER_UNINITIALIZED
I'm not sure why it's cutting off early, though I'm pretty sure it has to do with how I'm trying to record my own .wav file (since my encoder worked fine with other files).
Here is my code (sorry it's a bit long, I cut down as much as possible):
// Compile with "g++ test.ccp -o test -lasound"
// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
struct WaveHeader
{
char RIFF_marker[4];
uint32_t file_size;
char filetype_header[4];
char format_marker[4];
uint32_t data_header_length;
uint16_t format_type;
uint16_t number_of_channels;
uint32_t sample_rate;
uint32_t bytes_per_second;
uint16_t bytes_per_frame;
uint16_t bits_per_sample;
};
struct WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels)
{
struct WaveHeader *hdr;
hdr = (WaveHeader*) malloc(sizeof(*hdr));
if (!hdr)
return NULL;
memcpy(&hdr->RIFF_marker, "RIFF", 4);
memcpy(&hdr->filetype_header, "WAVE", 4);
memcpy(&hdr->format_marker, "fmt ", 4);
hdr->data_header_length = 16;
hdr->format_type = 1;
hdr->number_of_channels = channels;
hdr->sample_rate = sample_rate;
hdr->bytes_per_second = sample_rate * channels * bit_depth / 8;
hdr->bytes_per_frame = channels * bit_depth / 8;
hdr->bits_per_sample = bit_depth;
return hdr;
}
int writeWAVHeader(int fd, struct WaveHeader *hdr)
{
if (!hdr)
return -1;
write(fd, &hdr->RIFF_marker, 4);
write(fd, &hdr->file_size, 4);
write(fd, &hdr->filetype_header, 4);
write(fd, &hdr->format_marker, 4);
write(fd, &hdr->data_header_length, 4);
write(fd, &hdr->format_type, 2);
write(fd, &hdr->number_of_channels, 2);
write(fd, &hdr->sample_rate, 4);
write(fd, &hdr->bytes_per_second, 4);
write(fd, &hdr->bytes_per_frame, 2);
write(fd, &hdr->bits_per_sample, 2);
write(fd, "data", 4);
uint32_t data_size = hdr->file_size + 8 - 44;
write(fd, &data_size, 4);
return 0;
}
int recordWAV(const char *fileName, struct WaveHeader *hdr, uint32_t duration)
{
int err;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int sampleRate = hdr->sample_rate;
int dir;
snd_pcm_uframes_t frames = 32;
char *device = (char*) "plughw:1,0";
char *buffer;
int filedesc;
printf("Capture device is %s\n", device);
/* Open PCM device for recording (capture). */
err = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0);
if (err)
{
fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(err));
return err;
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* ### Set the desired hardware parameters. ### */
/* Interleaved mode */
err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err)
{
fprintf(stderr, "Error setting interleaved mode: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
/* Signed 16-bit little-endian format */
if (hdr->bits_per_sample == 16) err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
else err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
if (err)
{
fprintf(stderr, "Error setting format: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
/* Two channels (stereo) */
err = snd_pcm_hw_params_set_channels(handle, params, hdr->number_of_channels);
if (err)
{
fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
/* 44100 bits/second sampling rate (CD quality) */
sampleRate = hdr->sample_rate;
err = snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, &dir);
if (err)
{
fprintf(stderr, "Error setting sampling rate (%d): %s\n", sampleRate, snd_strerror(err));
snd_pcm_close(handle);
return err;
}
hdr->sample_rate = sampleRate;
/* Set period size*/
err = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
if (err)
{
fprintf(stderr, "Error setting period size: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
/* Write the parameters to the driver */
err = snd_pcm_hw_params(handle, params);
if (err < 0)
{
fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
/* Use a buffer large enough to hold one period */
err = snd_pcm_hw_params_get_period_size(params, &frames, &dir);
if (err)
{
fprintf(stderr, "Error retrieving period size: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return err;
}
size = frames * hdr->bits_per_sample / 8 * hdr->number_of_channels; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
if (!buffer)
{
fprintf(stdout, "Buffer error.\n");
snd_pcm_close(handle);
return -1;
}
err = snd_pcm_hw_params_get_period_time(params, &sampleRate, &dir);
if (err)
{
fprintf(stderr, "Error retrieving period time: %s\n", snd_strerror(err));
snd_pcm_close(handle);
free(buffer);
return err;
}
uint32_t pcm_data_size = hdr->sample_rate * hdr->bytes_per_frame * duration / 1000;
hdr->file_size = pcm_data_size + 44 - 8;
filedesc = open(fileName, O_WRONLY | O_CREAT, 0644);
err = writeWAVHeader(filedesc, hdr);
if (err)
{
fprintf(stderr, "Error writing .wav header.");
snd_pcm_close(handle);
free(buffer);
close(filedesc);
return err;
}
fprintf(stdout, "Channels: %d\n", hdr->number_of_channels);
for(int i = duration * 1000 / sampleRate; i > 0; i--)
{
err = snd_pcm_readi(handle, buffer, frames);
if (err == -EPIPE) fprintf(stderr, "Overrun occurred: %d\n", err);
if (err < 0) err = snd_pcm_recover(handle, err, 0);
// Still an error, need to exit.
if (err < 0)
{
fprintf(stderr, "Error occured while recording: %s\n", snd_strerror(err));
snd_pcm_close(handle);
free(buffer);
close(filedesc);
return err;
}
write(filedesc, buffer, size);
}
close(filedesc);
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
printf("Finished writing to %s\n", fileName);
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
fprintf(stderr, "Usage: %s (record duration)\n", argv[0]);
return -1;
}
int err;
struct WaveHeader *hdr;
// Creates a temporary file in /tmp
char wavFile[L_tmpnam + 5];
char *tempFilenameStub = tmpnam(NULL);
sprintf(wavFile, "%s.wav", tempFilenameStub);
hdr = genericWAVHeader(44000, 16, 2);
if (!hdr)
{
fprintf(stderr, "Error allocating WAV header.\n");
return -1;
}
err = recordWAV(wavFile, hdr, 1000 * strtod(argv[1], NULL));
if (err)
{
fprintf(stderr, "Error recording WAV file: %d\n", err);
return err;
}
free(hdr);
return 0;
}
Any suggestions?
Edit - I was told to compare the headers of my .wav file to that of one generated by arecord. Here are the results:
$ stat -c %s arecord.wav
352844
$ stat -c %s /tmp/filevXDDX6.wav
345004
$ xxd -g1 arecord.wav | head
0000000: 52 49 46 46 44 62 05 00 57 41 56 45 66 6d 74 20 RIFFDb..WAVEfmt
0000010: 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 ........D.......
0000020: 04 00 10 00 64 61 74 61 20 62 05 00 08 00 08 00 ....data b......
0000030: 08 00 08 00 07 00 07 00 fe ff fe ff f7 ff f7 ff ................
0000040: f6 ff f6 ff ee ff ee ff ee ff ee ff f6 ff f6 ff ................
0000050: f0 ff f0 ff e7 ff e7 ff ee ff ee ff f4 ff f4 ff ................
0000060: f4 ff f4 ff f7 ff f7 ff fe ff fe ff fc ff fc ff ................
0000070: fa ff fa ff f5 ff f5 ff ed ff ed ff ee ff ee ff ................
0000080: f8 ff f8 ff f4 ff f4 ff ed ff ed ff ee ff ee ff ................
0000090: f8 ff f8 ff f6 ff f6 ff f0 ff f0 ff ee ff ee ff ................
$ xxd -g1 /tmp/filevXDDX6.wav | head
0000000: 52 49 46 46 44 62 05 00 57 41 56 45 66 6d 74 20 RIFFDb..WAVEfmt
0000010: 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 ........D.......
0000020: 04 00 10 00 64 61 74 61 20 62 05 00 71 00 71 00 ....data b..q.q.
0000030: 6f 00 6f 00 79 00 79 00 75 00 75 00 63 00 63 00 o.o.y.y.u.u.c.c.
0000040: 3e 00 3e 00 1b 00 1b 00 07 00 07 00 fb ff fb ff >.>.............
0000050: 00 00 00 00 0c 00 0c 00 0f 00 0f 00 1c 00 1c 00 ................
0000060: 30 00 30 00 31 00 31 00 24 00 24 00 1e 00 1e 00 0.0.1.1.$.$.....
0000070: 24 00 24 00 31 00 31 00 2c 00 2c 00 28 00 28 00 $.$.1.1.,.,.(.(.
0000080: 31 00 31 00 3c 00 3c 00 36 00 36 00 31 00 31 00 1.1.<.<.6.6.1.1.
0000090: 39 00 39 00 40 00 40 00 3d 00 3d 00 30 00 30 00 9.9.#.#.=.=.0.0.
$ file arecord.wav
test.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz
$ file /tmp/filevXDDX6.wav
/tmp/filevXDDX6.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz
Your program does not write the correct number of samples to the .wav file.
snd_pcm_readi returns the number of frames that was actually read.
You can only write that many frames to the output.
The integer division in duration * 1000 / sampleRate might be rounded.
It is likely that duration * 1000 / sampleRate * frames is not exactly the same as the number of frames you actually want to read.
You should restructure your loop to count the total number of frames.