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