altos: remove telescience support
[fw/altos] / src / usbtrng / ao_usbtrng.c
1 /*
2  * Copyright © 2014 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20
21 #define AO_TRNG_SPI_BUS         1
22
23 static uint32_t                 spi_speed = AO_SPI_SPEED_4MHz;
24
25 #define AO_TRNG_SPI_BUF         1024
26
27 #if 0
28
29 static uint8_t  *spi_buf;
30 static uint8_t  *spi_head, *spi_tail;
31 static uint8_t  spi_wakeup;
32
33 static void
34 ao_trng_run(void)
35 {
36         int     this_time;
37         uint8_t *end;
38
39         if (!spi_buf)
40                 spi_buf = ao_usb_alloc(AO_TRNG_SPI_BUF);
41         flush();
42         ao_spi_get(AO_TRNG_SPI_BUS, spi_speed);
43         spi_tail = spi_buf;
44         spi_head = spi_buf;
45         ao_spi_recv_ring_start(spi_buf, AO_TRNG_SPI_BUF, &spi_head, &spi_tail, &spi_wakeup, AO_TRNG_SPI_BUS);
46         while (!ao_usb_out_avail) {
47                 ao_arch_block_interrupts();
48                 while (spi_head == spi_tail) {
49                         spi_wakeup = 0;
50                         ao_sleep(&spi_wakeup);
51                 }
52                 ao_arch_release_interrupts();
53                 if (spi_tail > spi_head)
54                         end = spi_buf + AO_TRNG_SPI_BUF;
55                 else
56                         end = spi_head;
57                 this_time = end - spi_tail;
58                 if (this_time > 64)
59                         this_time = 64;
60                 ao_usb_write(spi_tail, this_time);
61                 spi_tail += this_time;
62                 if (spi_tail == spi_buf + AO_TRNG_SPI_BUF)
63                         spi_tail = spi_buf;
64         }
65         ao_spi_put(AO_TRNG_SPI_BUS);
66         getchar();
67 }
68
69
70 static void
71 ao_trng_test(void)
72 {
73         static uint8_t  random[32];
74         uint8_t         i;
75
76         ao_spi_get(AO_TRNG_SPI_BUS, spi_speed);
77         ao_spi_recv(random, sizeof (random), AO_TRNG_SPI_BUS);
78         ao_spi_put(AO_TRNG_SPI_BUS);
79         for (i = 0; i < sizeof (random); i++)
80                 printf (" %02x", random[i]);
81         printf ("\n");
82 }
83 #endif
84
85 #define ADC_RING_SIZE   512
86
87 static uint8_t *adc_ring;
88 static uint16_t adc_head, adc_tail;
89 static uint16_t adc_wake;
90
91 void  lpc_adc_isr(void)
92 {
93         uint16_t        avail;
94         uint16_t        this, next;
95
96         this = adc_head;
97         next = (this + 1) & (ADC_RING_SIZE - 1);
98         if  (next == adc_tail) {
99                 lpc_adc.inten = 0;
100                 return;
101         }
102         adc_ring[this] = lpc_adc.dr[6] >> 8;
103         adc_head = next;
104
105         /* If there are enough entries, wake up any waiters
106          */
107         avail = (next - adc_tail) & (ADC_RING_SIZE - 1);
108         if (avail >= adc_wake) {
109                 adc_wake = 0;
110                 ao_wakeup(&adc_wake);
111         }
112 }
113
114 #define AO_ADC_CLKDIV   (AO_LPC_SYSCLK / 450000)
115
116 static void
117 ao_trng_adc_init(void)
118 {
119         adc_ring = ao_usb_alloc(ADC_RING_SIZE);
120
121         lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
122         lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
123
124         /* Enable interrupt when AO_ADC_6 is complete */
125         lpc_adc.inten = 0;
126
127         lpc_nvic_set_enable(LPC_ISR_ADC_POS);
128         lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
129
130 #if AO_ADC_0
131         ao_enable_analog(0, 11, 0);
132 #endif
133 #if AO_ADC_1
134         ao_enable_analog(0, 12, 1);
135 #endif
136 #if AO_ADC_2
137         ao_enable_analog(0, 13, 2);
138 #endif
139 #if AO_ADC_3
140         ao_enable_analog(0, 14, 3);
141 #endif
142 #if AO_ADC_4
143         ao_enable_analog(0, 15, 4);
144 #endif
145 #if AO_ADC_5
146         ao_enable_analog(0, 16, 5);
147 #endif
148 #if AO_ADC_6
149         ao_enable_analog(0, 22, 6);
150 #endif
151 #if AO_ADC_7
152         ao_enable_analog(0, 23, 7);
153 #endif
154
155         lpc_adc.cr = ((1 << (LPC_ADC_CR_SEL + 6)) |
156                       (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
157                       (1 << LPC_ADC_CR_BURST) |
158                       (LPC_ADC_CR_CLKS_9 << LPC_ADC_CR_CLKS));
159 }
160
161 static void
162 ao_trng_adc_dump(void)
163 {
164         int     i;
165
166         while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 16) {
167                 lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
168                 adc_wake = 16;
169                 ao_sleep(&adc_wake);
170         }
171         printf("adc_head %d tail %d\n", adc_head, adc_tail);
172
173         for (i = 0; i < 16; i++) {
174                 printf(" %4d", adc_ring[adc_tail]);
175                 adc_tail = (adc_tail + 1) & (ADC_RING_SIZE - 1);
176         }
177         printf("\n");
178         lpc_adc.inten = 0;
179 }
180
181 static void
182 ao_trng_run(void)
183 {
184         uint16_t        this_time;
185         flush();
186
187         while (!ao_usb_out_avail) {
188                 ao_arch_block_interrupts();
189                 while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 64) {
190                         lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
191                         adc_wake = 64;
192                         ao_sleep(&adc_wake);
193                 }
194                 ao_arch_release_interrupts();
195
196                 this_time = ADC_RING_SIZE - adc_tail;
197                 if (this_time > 64)
198                         this_time = 64;
199                 ao_usb_write(&adc_ring[adc_tail], this_time);
200                 adc_tail = (adc_tail + this_time) & (ADC_RING_SIZE - 1);
201         }
202         lpc_adc.inten = 0;
203 }
204
205 static void
206 ao_trng_speed(void)
207 {
208         ao_cmd_decimal();
209
210         if (ao_cmd_lex_u32 == 0 || ao_cmd_status != ao_cmd_success) {
211                 ao_cmd_status = ao_cmd_success;
212                 printf ("Current spi speed %d\n", spi_speed);
213         } else {
214                 spi_speed = ao_cmd_lex_u32;
215         }
216 }
217
218 static const struct ao_cmds ao_trng_cmds[] = {
219 //      { ao_trng_test, "R\0Dump some random numbers" },
220         { ao_trng_run,  "s\0Send random bits until char" },
221         { ao_trng_speed, "S <speed>\0Set SPI speed (48MHz/speed)" },
222         { ao_trng_adc_dump, "a\0Dump ADC data" },
223         { 0, NULL }
224 };
225
226 void
227 main(void)
228 {
229         ao_clock_init();
230         ao_task_init();
231         ao_timer_init();
232
233 //      ao_spi_init();
234         ao_usb_init();
235
236         ao_trng_adc_init();
237
238         ao_serial_init();
239
240         ao_led_init(LEDS_AVAILABLE);
241
242         ao_cmd_init();
243
244         ao_cmd_register(ao_trng_cmds);
245
246         ao_start_scheduler();
247 }