+#include <aversive.h>
+#include <aversive/wait.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#ifdef HOST_VERSION
+#if defined(WAV_NOISE)
+#include "noise.wav.c"
+#elif defined(WAV_TONE_HIGHNOISE)
+#include "tone-highnoise.wav.c"
+#elif defined(WAV_TONE_LOWNOISE)
+#include "tone-lownoise.wav.c"
+#elif defined(WAV_TONE)
+#include "tone.wav.c"
+#endif
+#endif
+
+/* port B */
+#define BUZ_BIT 0
+#define RADIO_BIT 2
+#define LED_BIT 4
+
+static uint32_t bitfield;
+
+#ifdef HOST_VERSION
+static int32_t fil_fond = 0;
+static int32_t fil_harm1 = 0;
+static int32_t fil_other = 0;
+#else
+static int16_t fil_fond = 0;
+static int16_t fil_harm1 = 0;
+static int16_t fil_other = 0;
+#endif
+static int16_t pow_fond = 0;
+static int16_t pow_harm1 = 0;
+static int16_t pow_other = 0;
+static int16_t cpt_filter = 0;
+
+#ifdef HOST_VERSION
+/* when compiled for host, we check that there is no saturation when
+ * applying the filter. This should not happen as the gain of the
+ * filter is 1. */
+int32_t saturate16(int32_t in)
+{
+ if (in > 32767L) {
+ in = 32767;
+ printf("saturation\n");
+ }
+ if (fil_fond < -32768L) {
+ in = -32768;
+ printf("saturation\n");
+ }
+ return in;
+}
+#endif
+
+/* Apply the 3 filters on the bitfield. The results are stored in
+ * fil_fond, fil_harm1 and fil_other. */
+static void apply_filters(void)
+{
+ fil_fond = 0;
+ fil_harm1 = 0;
+ fil_other = 0;
+
+ if (bitfield & (1UL << 0)) {
+ fil_fond += -1781;
+ fil_harm1 += -1217;
+ fil_other += -1308;
+ }
+
+ if (bitfield & (1UL << 1)) {
+ fil_fond += -1737;
+ fil_harm1 += -1135;
+ fil_other += -1830;
+ }
+
+ if (bitfield & (1UL << 2)) {
+ fil_fond += -1024;
+ fil_harm1 += 1922;
+ fil_other += -446;
+ }
+
+ if (bitfield & (1UL << 3)) {
+ fil_fond += 84;
+ fil_harm1 += -60;
+ fil_other += 1404;
+ }
+
+ if (bitfield & (1UL << 4)) {
+ fil_fond += 1162;
+ fil_harm1 += -1885;
+ fil_other += 1790;
+ }
+
+ if (bitfield & (1UL << 5)) {
+ fil_fond += 1791;
+ fil_harm1 += 1235;
+ fil_other += 306;
+ }
+
+ if (bitfield & (1UL << 6)) {
+ fil_fond += 1725;
+ fil_harm1 += 1113;
+ fil_other += -1500;
+ }
+
+ if (bitfield & (1UL << 7)) {
+ fil_fond += 986;
+ fil_harm1 += -1933;
+ fil_other += -1736;
+ }
+
+ if (bitfield & (1UL << 8)) {
+ fil_fond += -141;
+ fil_harm1 += 100;
+ fil_other += -144;
+ }
+
+ if (bitfield & (1UL << 9)) {
+ fil_fond += -1219;
+ fil_harm1 += 1869;
+ fil_other += 1605;
+ }
+
+ if (bitfield & (1UL << 10)) {
+ fil_fond += -1819;
+ fil_harm1 += -1288;
+ fil_other += 1654;
+ }
+
+ if (bitfield & (1UL << 11)) {
+ fil_fond += -1686;
+ fil_harm1 += -1042;
+ fil_other += -76;
+ }
+
+ if (bitfield & (1UL << 12)) {
+ fil_fond += -842;
+ fil_harm1 += 1972;
+ fil_other += -1751;
+ }
+
+ if (bitfield & (1UL << 13)) {
+ fil_fond += 424;
+ fil_harm1 += -302;
+ fil_other += -1478;
+ }
+
+ if (bitfield & (1UL << 14)) {
+ fil_fond += 1660;
+ fil_harm1 += -1750;
+ fil_other += 708;
+ }
+
+ if (bitfield & (1UL << 15)) {
+ fil_fond += 2416;
+ fil_harm1 += 2399;
+ fil_other += 2803;
+ }
+
+ if (bitfield & (1UL << 16)) {
+ fil_fond += 2416;
+ fil_harm1 += 2399;
+ fil_other += 2803;
+ }
+
+ if (bitfield & (1UL << 17)) {
+ fil_fond += 1660;
+ fil_harm1 += -1750;
+ fil_other += 708;
+ }
+
+ if (bitfield & (1UL << 18)) {
+ fil_fond += 424;
+ fil_harm1 += -302;
+ fil_other += -1478;
+ }
+
+ if (bitfield & (1UL << 19)) {
+ fil_fond += -842;
+ fil_harm1 += 1972;
+ fil_other += -1751;
+ }
+
+ if (bitfield & (1UL << 20)) {
+ fil_fond += -1686;
+ fil_harm1 += -1042;
+ fil_other += -76;
+ }
+
+ if (bitfield & (1UL << 21)) {
+ fil_fond += -1819;
+ fil_harm1 += -1288;
+ fil_other += 1654;
+ }
+
+ if (bitfield & (1UL << 22)) {
+ fil_fond += -1219;
+ fil_harm1 += 1869;
+ fil_other += 1605;
+ }
+
+ if (bitfield & (1UL << 23)) {
+ fil_fond += -141;
+ fil_harm1 += 100;
+ fil_other += -144;
+ }
+
+ if (bitfield & (1UL << 24)) {
+ fil_fond += 986;
+ fil_harm1 += -1933;
+ fil_other += -1736;
+ }
+
+ if (bitfield & (1UL << 25)) {
+ fil_fond += 1725;
+ fil_harm1 += 1113;
+ fil_other += -1500;
+ }
+
+ if (bitfield & (1UL << 26)) {
+ fil_fond += 1791;
+ fil_harm1 += 1235;
+ fil_other += 306;
+ }
+
+ if (bitfield & (1UL << 27)) {
+ fil_fond += 1162;
+ fil_harm1 += -1885;
+ fil_other += 1790;
+ }
+
+ if (bitfield & (1UL << 28)) {
+ fil_fond += 84;
+ fil_harm1 += -60;
+ fil_other += 1404;
+ }
+
+ if (bitfield & (1UL << 29)) {
+ fil_fond += -1024;
+ fil_harm1 += 1922;
+ fil_other += -446;
+ }
+
+ if (bitfield & (1UL << 30)) {
+ fil_fond += -1737;
+ fil_harm1 += -1135;
+ fil_other += -1830;
+ }
+
+ if (bitfield & (1UL << 31)) {
+ fil_fond += -1781;
+ fil_harm1 += -1217;
+ fil_other += -1308;
+ }
+
+#ifdef HOST_VERSION
+ fil_fond = saturate16(fil_fond);
+ fil_harm1 = saturate16(fil_harm1);
+ fil_other = saturate16(fil_other);
+#endif
+}
+
+/* Return abs(val) * 0.03125 + prev_out * 0.96875
+ * This is a simple "mean" filter. */
+static inline void mean_pow(int16_t *state, int16_t val)
+{
+ uint16_t new;
+
+ if (val > 0)
+ new = val;
+ else
+ new = -val;
+
+ new >>= 5;
+
+ /* new += prev_out * 0.96875 */
+ *state >>= 1;
+ new += *state;
+ *state >>= 1;
+ new += *state;
+ *state >>= 1;
+ new += *state;
+ *state >>= 1;
+ new += *state;
+ *state >>= 1;
+ new += *state;
+ *state >>= 1;
+ new += *state;
+
+ /* update state */
+ *state = new;
+}
+
+#define MAX_CPT_FILTER 500
+
+/* init timer (only on real hw, not on simulator which simulates an
+ * ATmega128) */
+static void init_timer(void)
+{
+#if defined(__AVR_ATtiny45__)
+ TCCR0A = 0;
+ TCCR0B = (1 << CS01); /* clk/8 = 1Mhz */
+#endif
+}
+
+/* wait new ech period (only on real hw, not on simulator which
+ * simulates an ATmega128). period=200 -> 5 khz */
+static void wait_period(void)
+{
+#if defined(__AVR_ATtiny45__)
+ static uint8_t prev = 0;
+ uint8_t cur, diff;
+
+ do {
+ cur = TCNT0;
+ diff = cur - prev;
+ } while (diff < 200);
+ prev = cur;
+#endif
+}
+
+/* return the input: on host, we use the table generated from the wav
+ * file, on the attiny, we use the real PIN input */
+static uint8_t get_input(int i)
+{
+#ifdef HOST_VERSION
+ return !!x[i];
+#else
+ return !!(PINB & RADIO_BIT);
+#endif
+}
+
+static void set_output(int16_t i)
+{
+ int8_t detected = 0;
+
+ if (cpt_filter > 250)
+ detected = 1;
+
+#ifdef HOST_VERSION
+ printf("%d fil_fond=%d fil_harm1=%d fil_other=%d\n",
+ i, fil_fond, fil_harm1, fil_other);
+ printf("%d pow_fond=%d pow_harm1=%d pow_other=%d cpt_filter=%d detected=%d\n",
+ i, pow_fond, pow_harm1, pow_other, cpt_filter, detected);
+#else
+ /* when we receive, output a square signal at 625 hz */
+ if ((detected == 1) && (i & 4))
+ PORTB |= (1 << BUZ_BIT);
+ else
+ PORTB &= ~(1 << BUZ_BIT);
+#endif
+}
+
+/*
+ The CPU runs at 8Mhz.
+ Fe = 5Khz
+ Ffond = 500 hz
+ Fharm1 = 1500 hz
+ Fother = 1000 hz
+ */
+int main(void)
+{
+ int16_t i;
+
+ /* led and buzzer are outputs */
+#if defined(__AVR_ATtiny45__)
+ DDRB |= (1 << LED_BIT) | (1 << BUZ_BIT);
+#endif
+
+ while (1) {
+ PORTB |= (1 << LED_BIT);
+ wait_ms(500);
+ PORTB &= ~(1 << LED_BIT);
+ wait_ms(500);
+ }
+
+ i = 0;
+ init_timer();
+
+ while (1) {
+
+ wait_period();
+
+ /* push one bit in bitfield */
+ bitfield <<= 1UL;
+ bitfield |= (uint32_t)get_input(i);
+
+ apply_filters();
+ mean_pow(&pow_fond, fil_fond);
+ mean_pow(&pow_harm1, fil_harm1);
+ mean_pow(&pow_other, fil_other);
+
+ /* cpt_filter is increased when we consider that we are
+ * receiving the signal */
+ if ((pow_fond/3) > (pow_harm1/2) &&
+ (pow_fond/2) > pow_other &&
+ cpt_filter < MAX_CPT_FILTER)
+ cpt_filter += 2;
+ else if (cpt_filter > 0)
+ cpt_filter--;
+
+ set_output(i);
+
+#ifdef HOST_VERSION
+ i ++;
+ if (i >= sizeof(x))
+ break;
+#endif
+ }
+
+ return 0;
+}