-
Notifications
You must be signed in to change notification settings - Fork 6
/
modem.c
95 lines (81 loc) · 2.3 KB
/
modem.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* Name: modem.c
*
* Audio modem for Attiny85 & other AVR chips with modifications
*
* Author: Jari Tulilahti
* Copyright: 2014 Rakettitiede Oy
* License: LGPLv3, see COPYING, and COPYING.LESSER -files for more info
*/
#include "modem.h"
/* Ring buffer global variables */
static volatile uint8_t modem_buffer_head = 0, modem_buffer_tail = 0;
static volatile uint8_t modem_buffer[MODEM_BUFFER_SIZE];
/*
* Returns number of available bytes in ringbuffer or 0 if empty
*/
uint8_t modem_buffer_available() {
return modem_buffer_head - modem_buffer_tail;
}
/*
* Store 1 byte in ringbuffer
*/
static inline void modem_buffer_put(const uint8_t c) {
if (modem_buffer_available() != MODEM_BUFFER_SIZE) {
modem_buffer[modem_buffer_head++ % MODEM_BUFFER_SIZE] = c;
}
}
/*
* Fetch 1 byte from ringbuffer
*/
uint8_t modem_buffer_get() {
uint8_t b = 0;
if (modem_buffer_available() != 0) {
b = modem_buffer[modem_buffer_tail++ % MODEM_BUFFER_SIZE];
}
return b;
}
/*
* Pin Change Interrupt Vector. This is The Modem.
*/
ISR(PCINT0_vect) {
/* Static variables instead of globals to keep scope inside ISR */
static uint8_t modem_bit = 0;
static uint8_t modem_bitlen = 0;
static uint8_t modem_byte = 0;
/* Read & Zero Timer/Counter 1 value */
uint8_t modem_pulselen = MODEM_TIMER;
MODEM_TIMER = 0;
/*
* Check if we received Start/Sync -pulse.
* Calculate bit signal length middle point from pulse.
* Return from ISR immediately.
*/
if (modem_pulselen > MODEM_SYNC_LEN) {
modem_bitlen = (modem_pulselen >> 2);
modem_bit = 0;
return;
}
/*
* Shift byte and set high bit according to the pulse length.
* Long pulse = 1, Short pulse = 0
*/
modem_byte = (modem_byte >> 1) | (modem_pulselen < modem_bitlen ? 0x00 : 0x80);
/* Check if we received complete byte and store it in ring buffer */
if (!(++modem_bit % 0x08)) {
modem_buffer_put(modem_byte);
}
}
/*
* Start the modem by enabling Pin Change Interrupts & Timer
*/
void modem_init() {
/* Modem pin as input */
MODEM_DDR &= ~(1 << MODEM_PIN);
/* Enable Pin Change Interrupts and PCINT for MODEM_PIN */
GIMSK |= (1 << PCIE);
PCMSK |= (1 << MODEM_PIN);
/* Timer: TCCR1: CS10, CS11 and CS12 bits: 8MHz clock with Prescaler 64 = 125kHz timer clock */
TCCR1 = (1 << CS10) | (1 << CS11) | (1 << CS12);
/* Enable interrupts */
sei();
}