Skip to content

Commit

Permalink
Fixed issue #34, #23 - added DMA support
Browse files Browse the repository at this point in the history
Fixed issue #56 - added support for playlsits
  • Loading branch information
markondej committed Jan 5, 2019
1 parent ea843ab commit 11fcc4c
Show file tree
Hide file tree
Showing 16 changed files with 1,036 additions and 306 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# fm_transmitter
Use Raspberry Pi as FM transmitter. Works on any Raspberry Pi board.

This project uses the general clock output to produce frequency modulated radio communication. It is based on idea originaly posted here: [http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter](http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter), but does not use DMA controller in order to distribute samples to output (clock generator), so sound quality is worse as in PiFm project and only mono transmition is available but this makes possible to run it on all kind of boards.
This project uses the general clock output to produce frequency modulated radio communication. It is based on idea originaly presented by Oliver Mattos and Oskar Weigl on [http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter](PiFM project).

## How to use it
To use this project You will have to build it. First, clone this repository, then use "make" command as shown below:
Expand All @@ -15,9 +15,13 @@ After successful build You can start transmitting by typing:
sudo ./fm_transmitter -f 102.0 acoustic_guitar_duet.wav
```
Where:
* -f 102.0 - Specifies the frequency in MHz, if not passed default is 100.0
* -f <frequency> - Specifies the frequency in MHz, 100.0 by default if not passed
* acoustic_guitar_duet.wav - Sample WAVE file, You can use your own

Other options:
* -d <dma_channel> - Specifies the used DMA channel (0 by default), pass 255 in order to disable DMA and use CPU
* -r - Loops the playback

### Supported audio formats
You can transmitt uncompressed WAVE (.wav) files directly or read audio data from stdin, eg.:
```
Expand All @@ -28,8 +32,8 @@ Please note only uncompressed WAVE files are supported. If You expire "corrupted
sox my-audio.mp3 -r 22050 -c 1 -b 16 -t wav my-converted-audio.wav
sudo ./fm_transmitter -f 100.6 my-converted-audio.wav
```
### USB microphone
To use a USB sound card microphone input use arecord, eg.:
### USB microphone support
In order to use a USB microphone input use arecord command, eg.:
```
arecord -D hw:1,0 -c1 -d 0 -r 22050 -f S16_LE | sudo ./fm_transmitter -f 100.6 -
```
Expand All @@ -39,9 +43,9 @@ In case of performance drop down use ```plughw:1,0``` instead of ```hw:1,0```.
Please keep in mind that transmitting on certain frequencies without special permissions may be illegal in your country.

## New features
* DMA engine support
* works on any Raspberry Pi model
* reads mono and stereo files
* reads data from stdin
* based on threads

Included sample audio was created by [graham_makes](https://freesound.org/people/graham_makes/sounds/449409/) and published on [freesound.org](https://freesound.org/)
4 changes: 2 additions & 2 deletions error_reporter.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
fm_transmitter - use Raspberry Pi as FM transmitter
Copyright (c) 2018, Marcin Kondej
Copyright (c) 2019, Marcin Kondej
All rights reserved.
See https://github.com/markondej/fm_transmitter
Expand Down Expand Up @@ -42,7 +42,7 @@ ErrorReporter::~ErrorReporter() throw()
{
}

const char* ErrorReporter::what() const throw()
const char *ErrorReporter::what() const throw()
{
return errorMessage.c_str();
}
4 changes: 2 additions & 2 deletions error_reporter.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
fm_transmitter - use Raspberry Pi as FM transmitter
Copyright (c) 2018, Marcin Kondej
Copyright (c) 2019, Marcin Kondej
All rights reserved.
See https://github.com/markondej/fm_transmitter
Expand Down Expand Up @@ -46,7 +46,7 @@ class ErrorReporter : public exception
explicit ErrorReporter(string message);
virtual ~ErrorReporter() throw();

virtual const char* what() const throw();
virtual const char *what() const throw();
protected:
string errorMessage;
};
Expand Down
262 changes: 262 additions & 0 deletions mailbox.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "mailbox.h"

#define PAGE_SIZE (4*1024)

void *mapmem(unsigned base, unsigned size)
{
int mem_fd;
unsigned offset = base % PAGE_SIZE;
base = base - offset;
size = size + offset;
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n");
exit (-1);
}
void *mem = mmap(
0,
size,
PROT_READ|PROT_WRITE,
MAP_SHARED/*|MAP_FIXED*/,
mem_fd,
base);
#ifdef DEBUG
printf("base=0x%x, mem=%p\n", base, mem);
#endif
if (mem == MAP_FAILED) {
printf("mmap error %d\n", (int)mem);
exit (-1);
}
close(mem_fd);
return (char *)mem + offset;
}

void unmapmem(void *addr, unsigned size)
{
const intptr_t offset = (intptr_t)addr % PAGE_SIZE;
addr = (char *)addr - offset;
size = size + offset;
int s = munmap(addr, size);
if (s != 0) {
printf("munmap error %d\n", s);
exit (-1);
}
}

/*
* use ioctl to send mbox property message
*/

static int mbox_property(int file_desc, void *buf)
{
int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);

if (ret_val < 0) {
printf("ioctl_set_msg failed:%d\n", ret_val);
}

#ifdef DEBUG
unsigned *p = buf; int i; unsigned size = *(unsigned *)buf;
for (i=0; i<size/4; i++)
printf("%04x: 0x%08x\n", i*sizeof *p, p[i]);
#endif
return ret_val;
}

unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x3000c; // (the tag id)
p[i++] = 12; // (size of the buffer)
p[i++] = 12; // (size of the data)
p[i++] = size; // (num bytes? or pages?)
p[i++] = align; // (alignment)
p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING)

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned mem_free(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x3000f; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned mem_lock(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x3000d; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned mem_unlock(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x3000e; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x30010; // (the tag id)
p[i++] = 28; // (size of the buffer)
p[i++] = 28; // (size of the data)
p[i++] = code;
p[i++] = r0;
p[i++] = r1;
p[i++] = r2;
p[i++] = r3;
p[i++] = r4;
p[i++] = r5;

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned qpu_enable(int file_desc, unsigned enable)
{
int i=0;
unsigned p[32];

p[i++] = 0; // size
p[i++] = 0x00000000; // process request

p[i++] = 0x30012; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = enable;

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout) {
int i=0;
unsigned p[32];

p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x30011; // (the tag id)
p[i++] = 16; // (size of the buffer)
p[i++] = 16; // (size of the data)
p[i++] = num_qpus;
p[i++] = control;
p[i++] = noflush;
p[i++] = timeout; // ms

p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size

mbox_property(file_desc, p);
return p[5];
}

int mbox_open() {
int file_desc;

// open a char device file used for communicating with kernel mbox driver
file_desc = open(DEVICE_FILE_NAME, 0);
if (file_desc < 0) {
printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
exit(-1);
}
return file_desc;
}

void mbox_close(int file_desc) {
close(file_desc);
}
47 changes: 47 additions & 0 deletions mailbox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <linux/ioctl.h>

#define MAJOR_NUM 100
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
#define DEVICE_FILE_NAME "/dev/vcio"

int mbox_open();
void mbox_close(int file_desc);

unsigned get_version(int file_desc);
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags);
unsigned mem_free(int file_desc, unsigned handle);
unsigned mem_lock(int file_desc, unsigned handle);
unsigned mem_unlock(int file_desc, unsigned handle);
void *mapmem(unsigned base, unsigned size);
void unmapmem(void *addr, unsigned size);

unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5);
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout);
unsigned qpu_enable(int file_desc, unsigned enable);
Loading

0 comments on commit 11fcc4c

Please sign in to comment.