dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_fskdac.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, write to the Free Software Foundation, Inc.,
29  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */
31 
32 /* Project Includes */
33 #include <pios.h>
34 
35 #if defined(PIOS_INCLUDE_DAC_FSK)
36 #include <pios_fskdac.h>
37 
38 #include <misc_math.h>
39 
40 /* Provide a COM driver */
41 static void PIOS_FSKDAC_RegisterTxCallback(uintptr_t fskdac_id, pios_com_callback tx_out_cb, uintptr_t context);
42 static void PIOS_FSKDAC_TxStart(uintptr_t fskdac_id, uint16_t tx_bytes_avail);
43 
44 #define SAMPLES_PER_BIT 20
45 
47  .tx_start = PIOS_FSKDAC_TxStart,
48  .bind_tx_cb = PIOS_FSKDAC_RegisterTxCallback,
49 };
50 
51 struct fskdac_dev_s {
52  uint32_t magic;
53 #define FSKDAC_DEV_MAGIC 0x674b5346 // 'FSKg'
54 
55  dac_dev_t dac;
56 
57  // Right now assumes we are at the start of a bit -- that there are an
58  // integral number of bits per sample buffer. at 24KHz, 20 samples
59  // per bit.
60 
61  uint16_t send_state;
62  uint16_t phase_accum;
63 
64  pios_com_callback tx_out_cb;
65  uintptr_t tx_out_context;
66 
67  bool tx_running;
68 };
69 
70 static bool PIOS_FSKDAC_cb(void *ctx, uint16_t *buf, int len);
71 
72 static bool PIOS_FSKDAC_validate(fskdac_dev_t fskdac_dev)
73 {
74  return (fskdac_dev->magic == FSKDAC_DEV_MAGIC);
75 }
76 
80 int32_t PIOS_FSKDAC_Init(fskdac_dev_t *fskdac_id, dac_dev_t dac)
81 {
82  PIOS_DEBUG_Assert(fskdac_id);
84 
85  fskdac_dev_t fskdac_dev = PIOS_malloc(sizeof(*fskdac_dev));
86 
87  if (!fskdac_dev) return -1;
88 
89  *fskdac_dev = (struct fskdac_dev_s) {
90  .magic = FSKDAC_DEV_MAGIC,
91  .dac = dac,
92  };
93 
94  *fskdac_id = fskdac_dev;
95 
96  return 0;
97 }
98 
99 static void PIOS_FSKDAC_RegisterTxCallback(uintptr_t fskdac_id, pios_com_callback tx_out_cb, uintptr_t context)
100 {
101  fskdac_dev_t fskdac_dev = (fskdac_dev_t) fskdac_id;
102 
103  bool valid = PIOS_FSKDAC_validate(fskdac_dev);
104  PIOS_Assert(valid);
105 
106  /*
107  * Order is important in these assignments since ISR uses _cb
108  * field to determine if it's ok to dereference _cb and _context
109  */
110  /* XXX this is not safe */
111  fskdac_dev->tx_out_context = context;
112  fskdac_dev->tx_out_cb = tx_out_cb;
113 }
114 
115 static void PIOS_FSKDAC_TxStart(uintptr_t fskdac_id, uint16_t tx_bytes_avail)
116 {
117  fskdac_dev_t fskdac_dev = (fskdac_dev_t)fskdac_id;
118 
119  bool valid = PIOS_FSKDAC_validate(fskdac_dev);
120  PIOS_Assert(valid);
121 
122  if (fskdac_dev->tx_running) {
123  return;
124  }
125 
126  fskdac_dev->tx_running = true;
127 
128  PIOS_DAC_install_callback(fskdac_dev->dac, 100,
129  PIOS_FSKDAC_cb, fskdac_dev);
130 }
131 
132 // TODO Consider relocation to common header
133 static inline uint16_t serial_frame_char(uint8_t c, int bits, bool parity, bool even,
134  bool twostop, bool inverted, uint8_t *framed_size)
135 {
136  // Bits is expected to be 7 or 8 currently
137  int num = 2 + bits; // Single start and stop counted.
138 
139  // Put in character. Start bit is low on the left, which we need to leave
140  // in at the end. Leave one more bit's room.
141  uint16_t framed = c << 1;
142 
143  if (bits == 7) {
144  // If we're 7 bit, and the high bit is set, don't let it crash into
145  // the start bit.
146  framed &= 0xff;
147  }
148 
149  if (parity) {
150  num++;
151  if (!even) {
152  framed |= 1;
153  }
154 
155  for (int i = 0; i < bits; i++) {
156  framed ^= c & 1;
157  c >>= 1;
158  }
159 
160  framed <<= 1; // Make room for stop
161  }
162 
163  if (twostop) {
164  num++;
165 
166  framed <<= 1; // Make room for add'l stop
167 
168  framed |= 3;
169  } else {
170  framed |= 1;
171  }
172 
173  if (inverted) {
174  framed = ~framed;
175  }
176 
177  // 7N1 = 2 + 7 = 9
178  // 8E2 = 2 + 9 + 1 + 1 = 12
179 
180  framed <<= (16 - num);
181 
182  if (framed_size) {
183  *framed_size = num;
184  }
185 
186  return framed;
187 }
188 
189 static bool PIOS_FSKDAC_cb(void *ctx, uint16_t *buf, int len)
190 {
191  fskdac_dev_t dev = ctx;
192 
193  bool no_next_c = false;
194 
195  for (int i = 0; i < len; i += SAMPLES_PER_BIT) {
196  if ((!no_next_c) && (!dev->send_state)) {
197  uint8_t b;
198  uint16_t bytes_to_send = 0;
199 
200  bool tx_need_yield;
201 
202  if (dev->tx_out_cb) {
203  bytes_to_send = (dev->tx_out_cb)(dev->tx_out_context,
204  &b, 1, NULL, &tx_need_yield);
205  }
206 
207  // pack into a reasonable form 8 / O / 1
208  if (bytes_to_send > 0) {
209  dev->send_state = serial_frame_char(b,
210  8, true, false, false,
211  false, NULL);
212  } else {
213  no_next_c = true;
214  }
215  }
216 
217  uint16_t freq = ((dev->send_state & 0x8000) || (no_next_c)) ?
218  3277 : 6008; /* 1200 mark / 2200 space */
219 
220  for (int j = 0; j < SAMPLES_PER_BIT; j++) {
221  dev->phase_accum += freq;
222 
223  uint16_t result = 32768 +
224  ((sin_approx(dev->phase_accum >> 1) * 6) >> 2);
225 
226  buf[i + j] = result & 0xFFF0;
227  }
228 
229  dev->send_state <<= 1;
230  }
231 
232  return true;
233 }
234 
235 #endif /* PIOS_INCLUDE_DAC_FSK */
236 
Main PiOS header to include all the compiled in PiOS options.
bool PIOS_DAC_install_callback(dac_dev_t dev, uint8_t priority, fill_dma_cb cb, void *ctx)
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
volatile int j
Definition: loadabletest.c:12
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
struct fskdac_dev_s * fskdac_dev_t
Definition: pios_fskdac.h:39
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int32_t PIOS_FSKDAC_Init(fskdac_dev_t *fskdac_id, dac_dev_t dac)
Allocate and initialise FSKDAC device.
static int16_t sin_approx(int32_t x)
Fast approximation of sine; 3rd order taylor expansion. Based on http://www.coranac.com/2009/07/sines/.
Definition: misc_math.h:90
uint8_t i
Definition: msp_messages.h:97
uint32_t magic
const struct pios_com_driver pios_fskdac_com_driver
struct dac_dev_s * dac_dev_t
Definition: pios_dac.h:40
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void(* tx_start)(uintptr_t id, uint16_t tx_bytes_avail)
Definition: pios_com.h:45
uint16_t(* pios_com_callback)(uintptr_t context, uint8_t *buf, uint16_t buf_len, uint16_t *headroom, bool *task_woken)
Definition: pios_com.h:41