blob: d6852bc8667a4694cf5a18ba6843c1bbd852f4e1 [file] [log] [blame]
Harald Welte67b2aba2019-04-16 20:47:22 +02001/*
2 * Copyright (C) 2019 Harald Welte <laforge@gnumonks.org>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <parts.h>
22
23#include "atmel_start.h"
24#include "atmel_start_pins.h"
25
26#include "i2c_bitbang.h"
27#include "octsim_i2c.h"
28#include "ncn8025.h"
29
30#include "command.h"
31
32enum testmode_test {
33 TEST_USER_LED,
34 /* test the per-slot LED by blinking it shortly */
35 TEST_LED,
36 /* test the voltages of the SIMVCC */
37 TEST_VOLTAGE,
38 /* test the clock rates of the SIMCLK pin */
39 TEST_CLOCK,
40 /* test the RST line by asserting it low and then back high */
41 TEST_RST,
42 /* test the RST line by asserting it low and then back high */
43 TEST_IO,
44 _NUM_TESTS
45};
46static const char *test_names[_NUM_TESTS] = {
47 [TEST_USER_LED] = "USER_LED",
48 [TEST_LED] = "LED",
49 [TEST_VOLTAGE] = "VOLTAGE",
50 [TEST_CLOCK] = "CLOCK",
51 [TEST_RST] = "RST",
52 [TEST_IO] = "IO",
53};
54
55struct testmode_state {
56 uint8_t slot;
57 enum testmode_test test_nr;
58 int test_int;
59 struct ncn8025_settings ncn;
60};
61static struct testmode_state g_tms;
62
63#define BLINK_MS 500
64
65static void set_slot(uint8_t slot)
66{
67 printf("changing slot to %u\r\n", slot);
68 g_tms.slot = slot;
69 g_tms.ncn = (struct ncn8025_settings) {
70 .rstin = false,
71 .cmdvcc = false,
72 .led = false,
73 .clkdiv = SIM_CLKDIV_8,
74 .vsel = SIM_VOLT_3V0,
75 };
76 ncn8025_set(g_tms.slot, &g_tms.ncn);
77 ncn8025_get(g_tms.slot, &g_tms.ncn);
78}
79
80static void next_test(void)
81{
82 g_tms.test_nr = (g_tms.test_nr + 1) % _NUM_TESTS;
83 g_tms.test_int = 0;
84 printf("changing test to %s\r\n", test_names[g_tms.test_nr]);
85}
86
87static void test_user_led(void)
88{
89 printf("blinking User LED\r\n");
90
91 gpio_set_pin_function(PIN_PC26, GPIO_PIN_FUNCTION_OFF);
92 gpio_set_pin_direction(PIN_PC26, GPIO_DIRECTION_OUT);
93 gpio_set_pin_level(PIN_PC26, true);
94 delay_ms(BLINK_MS);
95 gpio_set_pin_level(PIN_PC26, false);
96}
97
98static void test_led(void)
99{
100 printf("blinking Slot LED\r\n");
101
102 g_tms.ncn.led = true;
103 ncn8025_set(g_tms.slot, &g_tms.ncn);
104 delay_ms(BLINK_MS);
105 g_tms.ncn.led = false;
106 ncn8025_set(g_tms.slot, &g_tms.ncn);
107}
108
109static enum ncn8025_sim_voltage voltage[3] = { SIM_VOLT_1V8, SIM_VOLT_3V0, SIM_VOLT_5V0 };
110static const char *voltage_name[3] = { "1.8", "3.0", "5.0" };
111
112static void ncn_change_voltage(enum ncn8025_sim_voltage vsel)
113{
114 /* first disable the output; VSEL changes require output to be disabled */
115 g_tms.ncn.cmdvcc = false;
116 ncn8025_set(g_tms.slot, &g_tms.ncn);
117
118 /* then re-enable it with the new voltage setting */
119 g_tms.ncn.vsel = vsel;
120 g_tms.ncn.cmdvcc = true;
121 ncn8025_set(g_tms.slot, &g_tms.ncn);
122}
123
124static void test_voltage(void)
125{
126 printf("Testing Voltage %s\r\n", voltage_name[g_tms.test_int]);
127
128 ncn_change_voltage(voltage[g_tms.test_int]);
129 g_tms.test_int = (g_tms.test_int+1) % 3;
130}
131
132static enum ncn8025_sim_clkdiv clk_div[4] = { SIM_CLKDIV_8, SIM_CLKDIV_4, SIM_CLKDIV_2, SIM_CLKDIV_1 };
133static const uint8_t clk_div_val[4] = { 8, 4, 2, 1 };
134
135static void test_clock(void)
136{
137 printf("Testing Clock Divider %u\r\n", clk_div_val[g_tms.test_int]);
138 g_tms.ncn.cmdvcc = true;
139 g_tms.ncn.clkdiv = clk_div[g_tms.test_int];
140 ncn8025_set(g_tms.slot, &g_tms.ncn);
141 g_tms.test_int = (g_tms.test_int+1) % 4;
142}
143
144static void test_rst(void)
145{
146 printf("blinking RST\r\n");
147
148 /* well-defined voltage for LED brightness */
149 ncn_change_voltage(SIM_VOLT_3V0);
150
151 g_tms.ncn.cmdvcc = true;
152 g_tms.ncn.rstin = true;
153 ncn8025_set(g_tms.slot, &g_tms.ncn);
154
155 delay_ms(BLINK_MS);
156
157 g_tms.ncn.rstin = false;
158 ncn8025_set(g_tms.slot, &g_tms.ncn);
159}
160
161#ifndef SIM7_IO
162#define SIM7_IO PIN_PB21
163#endif
164static const enum gpio_port sim_io_gpio[] = { SIM0_IO, SIM1_IO, SIM2_IO, SIM3_IO,
165 SIM4_IO, SIM5_IO, SIM6_IO, SIM7_IO };
166
167static void test_io(void)
168{
169 enum gpio_port gpio = sim_io_gpio[g_tms.slot];
170 printf("blinking I/O\r\n");
171
172 /* well-defined voltage for LED brightness */
173 ncn_change_voltage(SIM_VOLT_3V0);
174
175 gpio_set_pin_function(gpio, GPIO_PIN_FUNCTION_OFF);
176 gpio_set_pin_direction(gpio, GPIO_DIRECTION_OUT);
177 gpio_set_pin_level(gpio, false);
178 delay_ms(BLINK_MS);
179 gpio_set_pin_level(gpio, true);
180
181 /* FIXME: restore tack to original function! */
182 //gpio_set_pin_function(sim_io_gpio[g_tms.slot], GPIO_PIN_FUNCTION_OFF);
183}
184
185typedef void (*test_fn)(void);
186static const test_fn test_functions[_NUM_TESTS] = {
187 [TEST_USER_LED] = test_user_led,
188 [TEST_LED] = test_led,
189 [TEST_VOLTAGE] = test_voltage,
190 [TEST_CLOCK] = test_clock,
191 [TEST_RST] = test_rst,
192 [TEST_IO] = test_io,
193};
194
195static void execute_test(void)
196{
197 printf("(%u) %-10s: ", g_tms.slot, test_names[g_tms.test_nr]);
198 test_functions[g_tms.test_nr]();
199}
200
201static int wait_for_key_and_process(void)
202{
203 int c;
204
205 do {
Kévin Redon0c3533f2019-04-03 21:00:09 +0200206 } while (!usart_async_rings_is_rx_not_empty(&UART_debug));
Harald Welte67b2aba2019-04-16 20:47:22 +0200207
208 c = getchar();
209 if (c < 0)
210 return -1;
211
212 switch (c) {
213 case '0':
214 case '1':
215 case '2':
216 case '3':
217 case '4':
218 case '5':
219 case '6':
220 case '7':
221 set_slot(c - '0');
222 execute_test();
223 break;
224 case 'n':
225 case 'N':
226 next_test();
227 execute_test();
228 break;
229 case 'Q':
230 case 'q':
231 printf("Leaving Test Mode\r\n");
232 return -1;
233 case ' ':
234 execute_test();
235 break;
236 }
237 return 0;
238}
239
240DEFUN(testmode_fn, cmd_testmode,
241 "testmode", "Enter board testing mode (Use `Q` to exit)")
242{
243 printf("Manual test mode. 'Q': exit, 'N': next test, SPACE: re-run, '0'-'7': slot\r\n");
244
245 printf("SPACE will start the current test (%s)\r\n", test_names[g_tms.test_nr]);
246 while (1) {
247 if (wait_for_key_and_process() < 0)
248 break;
249 }
250}
251
252void testmode_init(void)
253{
254 command_register(&cmd_testmode);
255}