Firmware SDK
twr_rf_ook.c
1 #include <twr_rf_ook.h>
2 #include <twr_timer.h>
3 
4 void _twr_rf_ook_irq_TIM3_handler(void *param);
5 
6 static struct
7 {
8  volatile uint16_t packet_bit_position;
9  uint8_t packet_length;
10  uint8_t packet_data[128];
11  volatile bool is_busy;
12  uint32_t bit_length_us;
13  twr_gpio_channel_t gpio;
14 } _twr_rf_ook;
15 
16 static int _twr_rf_ook_char_to_int(char input)
17 {
18  if(input >= '0' && input <= '9')
19  {
20  return input - '0';
21  }
22  else if(input >= 'A' && input <= 'F')
23  {
24  return input - 'A' + 10;
25  }
26  else if(input >= 'a' && input <= 'f')
27  {
28  return input - 'a' + 10;
29  }
30  else
31  {
32  return 0;
33  }
34 }
35 
36 static uint8_t _twr_rf_ook_string_to_array(char *str, uint8_t *array)
37 {
38  uint8_t array_length = (strlen(str) + 1) / 2;
39 
40  for(int i = 0; i < array_length; i++)
41  {
42  array[i] = _twr_rf_ook_char_to_int(str[i*2]) * 16;
43 
44  if(!(i == array_length - 1 && strlen(str) % 2 == 1))
45  {
46  array[i] += _twr_rf_ook_char_to_int(str[i*2 + 1]);
47  }
48  }
49 
50  return array_length;
51 }
52 
53 static void _twr_rf_ook_tim3_configure(uint32_t resolution_us, uint32_t period_cycles)
54 {
55  // Enable TIM3 clock
56  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
57 
58  // Errata workaround
59  RCC->APB1ENR;
60 
61  // Disable counter if it is running
62  TIM3->CR1 &= ~TIM_CR1_CEN;
63 
64  // Set prescaler to 5 * 32 (5 microseconds resolution)
65  TIM3->PSC = resolution_us * 32 - 1;
66  TIM3->ARR = period_cycles - 1;
67 
68  TIM3->DIER |= TIM_DIER_UIE;
69  // Enable TIM3 interrupts
70  NVIC_EnableIRQ(TIM3_IRQn);
71 }
72 
74 {
75  memset(&_twr_rf_ook, 0, sizeof(_twr_rf_ook));
76 
77  _twr_rf_ook.gpio = gpio;
78 
79  twr_gpio_init(_twr_rf_ook.gpio);
80  twr_gpio_set_mode(_twr_rf_ook.gpio, TWR_GPIO_MODE_OUTPUT);
81 
82  // TIM3 counter stopped when core is halted
83  //DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM3_STOP;
84 
85  // Set default bitrate
87 }
88 
89 void twr_rf_ook_set_bitrate(uint32_t bitrate)
90 {
91  _twr_rf_ook.bit_length_us = 1e6 / bitrate;
92 }
93 
94 void twr_rf_ook_set_bitlength(uint32_t bit_length_us)
95 {
96  _twr_rf_ook.bit_length_us = bit_length_us;
97 }
98 
99 bool twr_rf_ook_send(uint8_t *packet, uint8_t length)
100 {
101  if ((TIM3->CR1 & TIM_CR1_CEN) != 0)
102  {
103  // TIM3 is busy
104  return false;
105  }
106 
107  if (length > sizeof(_twr_rf_ook.packet_data))
108  {
109  // Packet is too long for library's buffer
110  return false;
111  }
112 
113  twr_system_pll_enable();
114 
115  _twr_rf_ook_tim3_configure(1, _twr_rf_ook.bit_length_us);
116 
117  _twr_rf_ook.packet_length = length;
118  _twr_rf_ook.packet_bit_position = 0;
119 
120  memcpy(_twr_rf_ook.packet_data, packet, _twr_rf_ook.packet_length);
121 
122  twr_timer_set_irq_handler(TIM3, _twr_rf_ook_irq_TIM3_handler, NULL);
123 
124  _twr_rf_ook.is_busy = true;
125 
126  TIM3->CR1 |= TIM_CR1_CEN;
127 
128  return true;
129 }
130 
131 bool twr_rf_ook_send_hex_string(char *hex_string)
132 {
133  uint8_t packet_length = _twr_rf_ook_string_to_array(hex_string, _twr_rf_ook.packet_data);
134 
135  return twr_rf_ook_send(_twr_rf_ook.packet_data, packet_length);
136 }
137 
139 {
140  return _twr_rf_ook.is_busy;
141 }
142 
144 {
145  if ((TIM3->CR1 & TIM_CR1_CEN) != 0)
146  {
147  // TIM3 is busy
148  return false;
149  }
150 
151  return _twr_rf_ook.is_busy;
152 }
153 
154 void _twr_rf_ook_irq_TIM3_handler(void *param)
155 {
156  (void) param;
157  TIM3->SR = ~TIM_DIER_UIE;
158 
159  uint8_t byte_index = _twr_rf_ook.packet_bit_position / 8;
160  uint8_t bit_index = _twr_rf_ook.packet_bit_position % 8;
161 
162  if(_twr_rf_ook.packet_bit_position / 8 == _twr_rf_ook.packet_length)
163  {
164  // Disable output after last bit is sent
165  twr_gpio_set_output(_twr_rf_ook.gpio, 0);
166 
167  // end of transmission
168  TIM3->CR1 &= ~TIM_CR1_CEN;
169  _twr_rf_ook.is_busy = false;
170 
171  twr_system_pll_disable();
172 
173  return;
174  }
175 
176  twr_gpio_set_output(_twr_rf_ook.gpio, _twr_rf_ook.packet_data[byte_index] & (1 << (7 - bit_index)));
177 
178  _twr_rf_ook.packet_bit_position++;
179 }
180 
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
GPIO channel operates as output.
Definition: twr_gpio.h:108
bool twr_rf_ook_send(uint8_t *packet, uint8_t length)
Send data.
Definition: twr_rf_ook.c:99
bool twr_rf_ook_send_hex_string(char *hex_string)
Send data with data in hex string.
Definition: twr_rf_ook.c:131
bool twr_rf_ook_is_busy()
Data sending in progress.
Definition: twr_rf_ook.c:138
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
void twr_rf_ook_set_bitlength(uint32_t bit_length_us)
Configure OOK bitrate.
Definition: twr_rf_ook.c:94
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:12
bool twr_timer_set_irq_handler(TIM_TypeDef *tim, void(*irq_handler)(void *), void *irq_param)
Register timer IRQ handler.
Definition: twr_timer.c:86
bool twr_rf_ook_is_ready()
Data can be send.
Definition: twr_rf_ook.c:143
void twr_rf_ook_init(twr_gpio_channel_t gpio)
Initialize RF OOK library.
Definition: twr_rf_ook.c:73
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
void twr_rf_ook_set_bitrate(uint32_t bitrate)
Configure OOK bitrate.
Definition: twr_rf_ook.c:89