COSA
An Object-Oriented Platform for Arduino Programming
VWI.cpp
Go to the documentation of this file.
1 
23 #include "VWI.hh"
24 
26 static const uint16_t prescale[] __PROGMEM = {
27 #if defined(BOARD_ATTINYX5) || defined(BOARD_ATTINYX61)
28  0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
29 #else
30  0, 1, 8, 64, 256, 1024
31 #endif
32 };
33 
43 static uint8_t
44 timer_setting(uint16_t speed, uint8_t bits, uint16_t* nticks)
45 {
46  uint16_t max_ticks = (1 << bits) - 1;
47  uint8_t res = 0;
48  for (uint8_t i = membersof(prescale) - 1; i > 0; i--) {
49  uint16_t scale = (uint16_t) pgm_read_word(&prescale[i]);
50  uint16_t count = (F_CPU / scale) / speed;
51  if (count > res && count < max_ticks) {
52  *nticks = count;
53  res = i;
54  }
55  }
56  return (res);
57 }
58 
59 VWI::Codec::Codec(uint8_t bits_per_symbol,
60  uint16_t start_symbol,
61  uint8_t preamble_max) :
62  BITS_PER_SYMBOL(bits_per_symbol),
63  START_SYMBOL(start_symbol),
64  PREAMBLE_MAX(preamble_max),
65  SYMBOL_MASK((1 << bits_per_symbol) - 1),
66  BITS_MSB(1 << (bits_per_symbol*2 - 1))
67 {
68 }
69 
71 VWI* VWI::s_rf = NULL;
72 
73 bool
74 VWI::begin(const void* config)
75 {
76  UNUSED(config);
77 
78  // Number of prescaled ticks needed
79  uint16_t nticks = 0;
80 
81  // Bit values for prescale register: CS0[2:0]
82  uint8_t prescaler;
83 
84  // Power up the timer
86 
87 #if defined(BOARD_ATTINYX5)
88  // Figure out prescaler value and counter match value
89  prescaler = timer_setting(m_speed * SAMPLES_PER_BIT, 8, &nticks);
90  if (!prescaler) return (false);
91 
92  // Turn on CTC mode / Output Compare pins disconnected
93  TCCR1 = _BV(PWM1A) | prescaler;
94 
95  // Number of ticks to count before firing interrupt
96  OCR1A = uint8_t(nticks);
97 #elif defined(BOARD_ATTINYX61)
98  // Figure out prescaler value and counter match value
99  prescaler = timer_setting(m_speed * SAMPLES_PER_BIT, 8, &nticks);
100  if (!prescaler) return (false);
101 
102  // Turn on CTC mode / Output Compare pins disconnected
103  TCCR1A = _BV(PWM1A);
104  TCCR1A = prescaler;
105 
106  // Number of ticks to count before firing interrupt
107  OCR1A = uint8_t(nticks);
108 #else
109  // Figure out prescaler value and counter match value
110  prescaler = timer_setting(m_speed * SAMPLES_PER_BIT, 16, &nticks);
111  if (!prescaler) return (false);
112 
113  // Output Compare pins disconnected, and turn on CTC mode
114  TCCR1A = 0;
115  TCCR1B = _BV(WGM12) | prescaler;
116 
117  // Caution: special procedures for setting 16 bit regs
118  // is handled by the compiler
119  OCR1A = nticks;
120 #endif
121  // Enable the interrupt handler
122  powerup();
123 
124  return (true);
125 }
126 
127 bool
129 {
130  powerdown();
132  return (true);
133 }
134 
135 void
137 {
138  if (m_rx != NULL) m_rx->begin();
139  TIMSK1 |= _BV(OCIE1A);
140 }
141 
142 void
144 {
145  if (m_tx != NULL) {
146  while (m_tx->is_active()) yield();
147  m_tx->end();
148  }
149  if (m_rx != NULL) m_rx->end();
150  TIMSK1 &= ~_BV(OCIE1A);
151 }
152 
154 {
155  VWI::Transmitter* transmitter = VWI::s_rf->m_tx;
156  VWI::Receiver* receiver = VWI::s_rf->m_rx;
157  bool transmitting = (transmitter != NULL) && (transmitter->m_enabled);
158  bool receiving = (receiver != NULL) && (receiver->m_enabled);
159 
160  // Check if the receiver pin should be sampled
161  if (!transmitting && receiving)
162  receiver->m_sample = receiver->read();
163 
164  // Do transmitter stuff first to reduce transmitter bit jitter due
165  // to variable receiver processing
166  if (transmitting && transmitter->m_sample++ == 0) {
167  // Send next bit. Symbols are sent LSB first. Finished sending the
168  // whole message? (after waiting one bit period since the last bit)
169  if (transmitter->m_index >= transmitter->m_length) {
170  transmitter->end();
171  }
172  else {
173  transmitter->write(transmitter->m_buffer[transmitter->m_index] &
174  (1 << transmitter->m_bit++));
175  if (transmitter->m_bit >= transmitter->m_codec->BITS_PER_SYMBOL) {
176  transmitter->m_bit = 0;
177  transmitter->m_index++;
178  }
179  }
180  }
181  if (transmitter != NULL && transmitter->m_sample >= VWI::SAMPLES_PER_BIT)
182  transmitter->m_sample = 0;
183 
184  // Check if the receiver should run the phase locked loop
185  if (!transmitting && receiving)
186  receiver->PLL();
187 }
188 
static uint8_t timer_setting(uint16_t speed, uint8_t bits, uint16_t *nticks)
Definition: VWI.cpp:44
Definition: VWI.hh:64
static void timer1_disable()
Definition: Power.hh:87
#define NULL
Definition: Types.h:101
static const uint8_t SAMPLES_PER_BIT
Definition: VWI.hh:168
ISR(TIMER1_COMPA_vect)
Definition: VWI.cpp:153
const uint8_t BITS_PER_SYMBOL
Definition: VWI.hh:76
virtual bool begin(const void *config=NULL)
Definition: VWI.cpp:74
virtual void powerdown()
Definition: VWI.cpp:143
#define TIMSK1
Definition: ATtinyX5.hh:229
static const uint16_t prescale[] __PROGMEM
Definition: VWI.cpp:26
#define membersof(x)
Definition: Types.h:165
void write(int value) const
Definition: OutputPin.hh:236
void(* yield)()
friend void TIMER1_COMPA_vect(void)
bool read() const
Definition: Pin.hh:172
#define UNUSED(x)
Definition: ATmega328P.hh:31
Codec(uint8_t bits_per_symbol, uint16_t start_symbol, uint8_t preamble_max=VWI::Transmitter::PREAMBLE_MAX)
Definition: VWI.cpp:59
static void timer1_enable()
Definition: Power.hh:81
virtual bool end()
Definition: VWI.cpp:128
void end()
Definition: VWI.hh:366
virtual void powerup()
Definition: VWI.cpp:136