Skip to content

Commit

Permalink
Merge pull request #12 from achilikin/master
Browse files Browse the repository at this point in the history
New commands to control volume and audio gain
  • Loading branch information
Manawyrm committed Dec 6, 2014
2 parents bcd78c7 + a43605c commit 0b498f0
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 43 deletions.
3 changes: 3 additions & 0 deletions ctlfmberry
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ else
echo " ctlfmberry stereo off - Disables stereo signal"
echo " ctlfmberry muteon - Mute audio"
echo " ctlfmberry muteoff - Unmute audio"
echo " ctlfmberry gainlow - Audio gain -9dB"
echo " ctlfmberry gainoff - Audio gain 0dB"
echo " ctlfmberry set volume 0-6 Audio volume level 0 to 6, equal -9dB to +9db, 3dB step"
echo " ctlfmberry status - Print current status"
echo " ctlfmberry stop - Stop FMBerry daemon"
else
Expand Down
7 changes: 7 additions & 0 deletions fmberry.conf
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ tcpport = 42516
# 3 - 2.0 mW Outputpower (Default.)
txpower = 3

# Audio signal gain -9dB
gain = false

# Audio signal volume
# range 0-6 or -9dB to +9db, 3dB step
volume = 3

# RDS interrupt pin number
rdspin = 17

Expand Down
62 changes: 46 additions & 16 deletions fmberryd.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
FMBerry - an cheap and easy way of transmitting music with your Pi.
Copyright (C) 2011-2013 by Tobias Mädel (t.maedel@alfeld.de)
Copyright (C) 2013 by Andrey Chilikin (achilikin@gmail.com)
Copyright (C) 2013 by Andrey Chilikin (https://github.com/achilikin)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
Expand Down Expand Up @@ -107,7 +107,9 @@ int main(int argc, char **argv)
CFG_BOOL("poweron", 1, CFGF_NONE),
CFG_BOOL("tcpbindlocal", 1, CFGF_NONE),
CFG_INT("tcpport", 42516, CFGF_NONE),
CFG_INT("txpower", 3, CFGF_NONE),
CFG_INT("txpower", 3, CFGF_NONE),
CFG_BOOL("gain", 0, CFGF_NONE),
CFG_INT("volume", 3, CFGF_NONE),
CFG_INT("rdspin", 17, CFGF_NONE),
CFG_STR("rdsid", "", CFGF_NONE),
CFG_STR("rdstext", "", CFGF_NONE),
Expand All @@ -124,8 +126,8 @@ int main(int argc, char **argv)
ledpin = cfg_getint(cfg, "ledpin");
rdsint = cfg_getint(cfg, "rdspin");

// Init I2C bus and transmitter
if (ns741_init(cfg_getint(cfg, "i2cbus")) == -1)
// Init I2C bus and transmitter with initial frequency and state
if (ns741_init(cfg_getint(cfg, "i2cbus"), cfg_getint(cfg, "frequency")) == -1)
{
syslog(LOG_ERR, "Init failed! Double-check hardware and try again!\n");
exit(EXIT_FAILURE);
Expand All @@ -147,23 +149,18 @@ int main(int argc, char **argv)
mmr70.power = cfg_getbool(cfg, "poweron");
mmr70.txpower = cfg_getint(cfg, "txpower");
mmr70.mute = 0;
mmr70.gain = cfg_getbool(cfg, "gain");
mmr70.volume = cfg_getint(cfg, "volume");
mmr70.stereo = cfg_getbool(cfg, "stereo");
mmr70.rds = cfg_getbool(cfg, "rdsenable");
strncpy(mmr70.rdsid, cfg_getstr(cfg, "rdsid"), 8);
strncpy(mmr70.rdstext, cfg_getstr(cfg, "rdstext"), 64);

// Set initial frequency and state.
ns741_set_frequency(mmr70.frequency);
// apply configuration parameters
ns741_txpwr(mmr70.txpower);

if (mmr70.power)
{
ns741_power(1);
}

if (!mmr70.stereo)
ns741_stereo(0);

ns741_mute(mmr70.mute);
ns741_power(mmr70.power);
ns741_stereo(mmr70.stereo);
ns741_rds_set_progname(mmr70.rdsid);
ns741_rds_set_radiotext(mmr70.rdstext);

Expand Down Expand Up @@ -352,6 +349,37 @@ int ProcessTCP(int sock, mmr70_data_t *pdata)
break;
}

if (str_is(buffer, "gainlow"))
{
ns741_input_gain(1);
pdata->gain = 1;
break;
}

if (str_is(buffer, "gainoff"))
{
ns741_input_gain(0);
pdata->gain = 0;
break;
}

if (str_is_arg(buffer, "set volume", &arg))
{
int volume = atoi(arg);

if ((volume >= 0) && (volume <= 6))
{
syslog(LOG_NOTICE, "Changing volume level...\n");
ns741_volume(volume);
pdata->volume = volume;
}
else
{
syslog(LOG_NOTICE, "Bad volume level. Range 0-6\n");
}
break;
}

if (str_is_arg(buffer, "set stereo", &arg))
{
if (str_is(arg, "on"))
Expand Down Expand Up @@ -413,11 +441,13 @@ int ProcessTCP(int sock, mmr70_data_t *pdata)
if (str_is(buffer, "status"))
{
bzero(buffer, sizeof(buffer));
sprintf(buffer, "freq: %dKHz txpwr: %.2fmW power: '%s' mute: '%s' stereo: '%s' rds: '%s' rdsid: '%s' rdstext: '%s'\n",
sprintf(buffer, "freq: %dKHz txpwr: %.2fmW power: '%s' mute: '%s' gain: '%s' volume: '%d' stereo: '%s' rds: '%s' rdsid: '%s' rdstext: '%s'\n",
pdata->frequency,
txpower[pdata->txpower],
pdata->power ? "on" : "off",
pdata->mute ? "on" : "off",
pdata->gain ? "on" : "off",
pdata->volume,
pdata->stereo ? "on" : "off",
pdata->rds ? "on" : "off",
pdata->rdsid, pdata->rdstext);
Expand Down
2 changes: 2 additions & 0 deletions fmberryd.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ typedef struct _mmr70_data
int frequency;
int power;
int mute;
int gain;
int volume;
int txpower;
int stereo;
int rds;
Expand Down
6 changes: 3 additions & 3 deletions i2c.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
FMBerry - an cheap and easy way of transmitting music with your Pi.
Copyright (C) 2011-2013 by Tobias Mädel (t.maedel@alfeld.de)
Copyright (C) 2013 by Andrey Chilikin (achilikin@gmail.com)
Copyright (C) 2013 by Andrey Chilikin (https://github.com/achilikin)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
Expand Down Expand Up @@ -49,7 +49,7 @@ int i2c_select(int dev, uint8_t address)
return ioctl(dev, I2C_SLAVE, address);
}

int i2c_writeData(int dev, uint8_t *data, uint32_t len)
int i2c_send_data(int dev, uint8_t *data, uint32_t len)
{
if (write(dev, data, len) != len) {
return -1;
Expand Down Expand Up @@ -78,4 +78,4 @@ int i2c_send_word(int dev, uint8_t addr, uint8_t data0, uint8_t data1)
return -1;
}
return 0;
}
}
4 changes: 2 additions & 2 deletions i2c.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
FMBerry - an cheap and easy way of transmitting music with your Pi.
Copyright (C) 2011-2013 by Tobias Mädel (t.maedel@alfeld.de)
Copyright (C) 2013 by Andrey Chilikin (achilikin@gmail.com)
Copyright (C) 2013 by Andrey Chilikin (https://github.com/achilikin)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
Expand All @@ -24,6 +24,6 @@ int i2c_init(uint8_t bus, uint8_t address);
int i2c_select(int dev, uint8_t address);
int i2c_send_word(int dev, uint8_t addr, uint8_t data0, uint8_t data1);
int i2c_send(int dev, uint8_t addr, uint8_t data);
int i2c_writeData(int dev, uint8_t *data, uint32_t len);
int i2c_send_data(int dev, uint8_t *data, uint32_t len);

#endif
83 changes: 62 additions & 21 deletions ns741.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
static const int address = 0x66;
static int i2cbus = -1;

#define NS741_DEFAULT_F 99800 // default F=99.80MHz

// Calculates value of P for 0A/0B registers
#define NS741_FREQ(F) ((uint16_t)((uint32_t)F*1000ULL/8192ULL))

// "----------------------------64----------------------------------"
char radiotext_text[64] = " ";
// *hrr hrr* "Twilight Sparkle is best Pony. "
Expand Down Expand Up @@ -110,39 +115,48 @@ void ns741_power(uint8_t on)
*
* Thanks to Silvan König for init-sequence
*************************************************************************/
// Initial register state, some change applied to
// recommended values from TSMZ1-603 spec
static uint8_t init_data[] =
{
0x00, // start address 0
0x00, // start address for i2c_send_data()
// default map for all 22 RW registers
0x02, 0x83, 0x0A, 0x00,
0x00, 0x00, 0x00, 0x7E,
0x0E, 0x08, 0x3F, 0x2A,
0x0C, 0xE6, 0x3F, 0x70,
0x0A, 0xE4, 0x00, 0x42,
0xC0, 0x41, 0xF4
0x02, // 00h: Power OFF, Crystal ON
0xE1, // 01h: PE switch ON, PE selection 50us (Europe), Subcarrier ON, Pilot Level 1.6
0x0A, // 02h: RFG 0.5 mW, Mute ON
0x00, 0x00, 0x00, 0x00, // 03h-06h: RDS registers
0x7E, 0x0E, // 07h-08h: recommended default
0x08, // 09h: recommended default
(NS741_FREQ(NS741_DEFAULT_F) & 0xFF), // 0Ah-0Bh, frequency
((NS741_FREQ(NS741_DEFAULT_F) & 0xFF00) >> 8),
0x0C, // 0Ch: recommended default
0xE0, // 0Dh: ALC (Auto Level Control) OFF, AG (Audio Gain) -9dB
0x30, // 0Eh: recommended default
0x40, // 0Fh: input Audio Gain -9dB
0xA0, // 10h: RDS with checkword, RDS disabled
0xE4, // 11h: recommended default
0x00, // 12h: recommended default
0x42, // 13h: recommended default
0xC0, // 14h: recommended default
0x41, // 15h: recommended default
0xF4 // 16h: recommended default
};

int ns741_init(uint8_t bus)
int ns741_init(uint8_t bus, uint32_t f_khz)
{
i2cbus = i2c_init(bus, address);
if ((i2cbus == -1) || (i2c_send(i2cbus, 0x00, 0x00) == -1))
{
return -1;
}

// set specified frequency
init_data[11] = NS741_FREQ(f_khz) & 0x00FF;
init_data[12] = (NS741_FREQ(f_khz) & 0xFF00) >> 8;

// reset registers to default values
i2c_writeData(i2cbus, init_data, sizeof(init_data));

i2c_send(i2cbus, 0x02, 0x0B);
i2c_send(i2cbus, 0x15, 0x11);
// i2c_send(i2cbus, 0x10, 0xE0); // we will turn on RDS signal depending on config file

// Configuration
i2c_send(i2cbus, 0x07, 0x7E);
i2c_send(i2cbus, 0x08, 0x0E);
i2c_send(i2cbus, 0x02, 0xCA); // unmute and set txpwr to 2.0 mW
i2c_send(i2cbus, 0x01, 0x81);

i2c_send_data(i2cbus, init_data, sizeof(init_data));

return 0;
}

Expand Down Expand Up @@ -205,7 +219,7 @@ void ns741_txpwr(uint8_t strength)
void ns741_set_frequency(uint32_t f_khz)
{
/* calculate frequency in 8.192kHz steps*/
uint16_t val = (uint16_t)((uint32_t)f_khz*1000ULL/8192ULL);
uint16_t val = NS741_FREQ(f_khz);

// it is recommended to mute transmitter before changing frequency
i2c_send(i2cbus, 0x02, reg02h | 0x01);
Expand All @@ -220,6 +234,33 @@ void ns741_set_frequency(uint32_t f_khz)
return;
}

// output gain 0-6, or -9dB to +9db, 3dB step
void ns741_volume(uint8_t gain)
{
uint8_t reg = init_data[0x0D];
if (gain > 6)
gain = 6;
reg &= ~0x0E;
reg |= gain << 1;
init_data[0x0D] = reg;

i2c_send(i2cbus, 0x0D, reg);
}

// set input gain -9dB on/off
void ns741_input_gain(uint8_t on)
{
uint8_t reg = init_data[0x0F];

if (on)
reg |= 0x40;
else
reg &= ~0x40;
init_data[0x0F] = reg;

i2c_send(i2cbus, 0x0F, reg);
}

// register 0x10 controls RDS:
// reserved bits 0-5, with bit 5 set
// bit 6: 0 - RDS off, 1 - RDS on
Expand Down
4 changes: 3 additions & 1 deletion ns741.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@

#include <stdint.h>

int ns741_init(uint8_t i2c_bus);
int ns741_init(uint8_t i2c_bus, uint32_t f_khz);
void ns741_set_frequency(uint32_t f_khz);
void ns741_power(uint8_t on);
void ns741_mute(uint8_t on);
void ns741_txpwr(uint8_t strength);
void ns741_stereo(uint8_t on);
void ns741_volume(uint8_t gain);
void ns741_input_gain(uint8_t on);

void ns741_rds(uint8_t on);
int ns741_rds_start(void);
Expand Down

0 comments on commit 0b498f0

Please sign in to comment.