main.c 16.1 KB
Newer Older
Dave Hylands's avatar
Dave Hylands committed
1
2
3
4
5
6
7
8
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
9
#include "qstr.h"
Dave Hylands's avatar
Dave Hylands committed
10
#include "lexer.h"
11
#include "lexermemzip.h"
Dave Hylands's avatar
Dave Hylands committed
12
13
14
15
16
17
#include "parse.h"
#include "obj.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "repl.h"
18
#include "servo.h"
Dave Hylands's avatar
Dave Hylands committed
19
20
21
22
23
24
25
26
#include "usb.h"
#include "gc.h"
#include "led.h"

#include "Arduino.h"

extern uint32_t _heap_start;

27
bool do_file(const char *filename);
Dave Hylands's avatar
Dave Hylands committed
28

29
30
31
32
33
34
void flash_error(int n) {
    for (int i = 0; i < n; i++) {
        led_state(PYB_LED_BUILTIN, 1);
        delay(250);
        led_state(PYB_LED_BUILTIN, 0);
        delay(250);
Dave Hylands's avatar
Dave Hylands committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    }
}

static const char *help_text =
"Welcome to Micro Python!\n\n"
"This is a *very* early version of Micro Python and has minimal functionality.\n\n"
"Specific commands for the board:\n"
"    pyb.info()             -- print some general information\n"
"    pyb.gc()               -- run the garbage collector\n"
"    pyb.delay(<n>)         -- wait for n milliseconds\n"
"    pyb.Led(<n>)           -- create Led object for LED n (n=0)\n"
"                              Led methods: on(), off()\n"
"    pyb.gpio(<pin>)        -- read gpio pin\n"
"    pyb.gpio(<pin>, <val>) -- set gpio pin\n"
#if 0
"    pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n"
"                      Servo methods: angle(<x>)\n"
"    pyb.switch()   -- return True/False if switch pressed or not\n"
"    pyb.accel()    -- get accelerometer values\n"
"    pyb.rand()     -- get a 16-bit random number\n"
#endif
;

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
mp_obj_t pyb_analog_read(mp_obj_t pin_obj) {
    uint pin = mp_obj_get_int(pin_obj);
    int val = analogRead(pin);
    return MP_OBJ_NEW_SMALL_INT(val);
}

mp_obj_t pyb_analog_write(mp_obj_t pin_obj, mp_obj_t val_obj) {
    uint pin = mp_obj_get_int(pin_obj);
    int val = mp_obj_get_int(val_obj);
    analogWrite(pin, val);
    return mp_const_none;
}

mp_obj_t pyb_analog_write_resolution(mp_obj_t res_obj) {
    int res = mp_obj_get_int(res_obj);
    analogWriteResolution(res);
    return mp_const_none;
}

mp_obj_t pyb_analog_write_frequency(mp_obj_t pin_obj, mp_obj_t freq_obj) {
    uint pin = mp_obj_get_int(pin_obj);
    int freq = mp_obj_get_int(freq_obj);
    analogWriteFrequency(pin, freq);
    return mp_const_none;
}

Dave Hylands's avatar
Dave Hylands committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// get some help about available functions
static mp_obj_t pyb_help(void) {
    printf("%s", help_text);
    return mp_const_none;
}

// get lots of info about the board
static mp_obj_t pyb_info(void) {
    // get and print unique id; 96 bits
    {
        byte *id = (byte*)0x40048058;
        printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
    }

    // get and print clock speeds
    printf("CPU=%u\nBUS=%u\nMEM=%u\n", F_CPU, F_BUS, F_MEM);

    // to print info about memory
    {
        extern void *_sdata;
        extern void *_edata;
        extern void *_sbss;
        extern void *_ebss;
        extern void *_estack;
        extern void *_etext;
        printf("_sdata=%p\n", &_sdata);
        printf("_edata=%p\n", &_edata);
        printf("_sbss=%p\n", &_sbss);
        printf("_ebss=%p\n", &_ebss);
        printf("_estack=%p\n", &_estack);
        printf("_etext=%p\n", &_etext);
        printf("_heap_start=%p\n", &_heap_start);
    }

    // GC info
    {
        gc_info_t info;
        gc_info(&info);
        printf("GC:\n");
        printf("  %lu total\n", info.total);
        printf("  %lu used %lu free\n", info.used, info.free);
        printf("  1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
    }

#if 0
    // free space on flash
    {
        DWORD nclst;
        FATFS *fatfs;
        f_getfree("0:", &nclst, &fatfs);
        printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
    }
#endif

    return mp_const_none;
}

#define RAM_START (0x1FFF8000) // fixed for chip
#define HEAP_END  (0x20006000) // tunable
#define RAM_END   (0x20008000) // fixed for chip

void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);

void gc_collect(void) {
    uint32_t start = micros();
    gc_collect_start();
    gc_collect_root((void**)RAM_START, (((uint32_t)&_heap_start) - RAM_START) / 4);
    machine_uint_t regs[10];
    gc_helper_get_regs_and_clean_stack(regs, HEAP_END);
    gc_collect_root((void**)HEAP_END, (RAM_END - HEAP_END) / 4); // will trace regs since they now live in this function on the stack
    gc_collect_end();
    uint32_t ticks = micros() - start; // TODO implement a function that does this properly

    if (0) {
        // print GC info
        gc_info_t info;
        gc_info(&info);
        printf("GC@%lu %luus\n", start, ticks);
        printf(" %lu total\n", info.total);
        printf(" %lu used %lu free\n", info.used, info.free);
        printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
    }
}

mp_obj_t pyb_gc(void) {
    gc_collect();
    return mp_const_none;
}

mp_obj_t pyb_gpio(int n_args, mp_obj_t *args) {
    //assert(1 <= n_args && n_args <= 2);

    uint pin = mp_obj_get_int(args[0]);
    if (pin > CORE_NUM_DIGITAL) {
        goto pin_error;
    }

    if (n_args == 1) {
        // get pin
        pinMode(pin, INPUT);
        return MP_OBJ_NEW_SMALL_INT(digitalRead(pin));
    }
    
    // set pin
    pinMode(pin, OUTPUT);
Damien George's avatar
Damien George committed
189
    digitalWrite(pin, mp_obj_is_true(args[1]));
Dave Hylands's avatar
Dave Hylands committed
190
191
192
    return mp_const_none;

pin_error:
193
    nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin));
Dave Hylands's avatar
Dave Hylands committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
}

MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);

#if 0
mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
    mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
    uint8_t data[4];
    data[0] = mp_obj_get_int(items[0]);
    data[1] = mp_obj_get_int(items[1]);
    data[2] = mp_obj_get_int(items[2]);
    data[3] = mp_obj_get_int(items[3]);
    usb_hid_send_report(data);
    return mp_const_none;
}
#endif

211
212
static mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
static mp_obj_t pyb_config_main = MP_OBJ_NULL;
213
214

mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
215
216
217
218
219
220
    if (MP_OBJ_IS_STR(source_dir)) {
        pyb_config_source_dir = source_dir;
        printf("source_dir = '");
        mp_obj_print(source_dir, PRINT_STR);
        printf("'\n");
    }
221
222
223
224
    return mp_const_none;
}

mp_obj_t pyb_main(mp_obj_t main) {
225
226
227
228
229
230
    if (MP_OBJ_IS_STR(main)) {
        pyb_config_main = main;
        printf("main = '");
        mp_obj_print(main, PRINT_STR);
        printf("'\n");
    }
231
232
233
    return mp_const_none;
}

Dave Hylands's avatar
Dave Hylands committed
234
235
236
237
238
239
mp_obj_t pyb_delay(mp_obj_t count) {
    delay(mp_obj_get_int(count));
    return mp_const_none;
}

mp_obj_t pyb_led(mp_obj_t state) {
Damien George's avatar
Damien George committed
240
    led_state(PYB_LED_BUILTIN, mp_obj_is_true(state));
Dave Hylands's avatar
Dave Hylands committed
241
242
243
    return state;
}

244
mp_obj_t pyb_run(mp_obj_t filename_obj) {
245
    const char *filename = qstr_str(mp_obj_str_get_qstr(filename_obj));
246
247
248
249
    do_file(filename);
    return mp_const_none;
}

Dave Hylands's avatar
Dave Hylands committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
char *strdup(const char *str) {
    uint32_t len = strlen(str);
    char *s2 = m_new(char, len + 1);
    memcpy(s2, str, len);
    s2[len] = 0;
    return s2;
}

#define READLINE_HIST_SIZE (8)

static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};

void stdout_tx_str(const char *str) {
//    usart_tx_str(str);
    usb_vcp_send_str(str);
}

int readline(vstr_t *line, const char *prompt) {
    stdout_tx_str(prompt);
    int len = vstr_len(line);
    int escape = 0;
    int hist_num = 0;
    for (;;) {
        char c;
        for (;;) {
            if (usb_vcp_rx_any() != 0) {
                c = usb_vcp_rx_get();
                break;
#if 0
            } else if (usart_rx_any()) {
                c = usart_rx_char();
                break;
#endif
            }
            //delay(1);
            //if (storage_needs_flush()) {
            //    storage_flush();
            //}
        }
        if (escape == 0) {
            if (c == 4 && vstr_len(line) == len) {
                return 0;
            } else if (c == '\r') {
                stdout_tx_str("\r\n");
                for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
                    readline_hist[i] = readline_hist[i - 1];
                }
                readline_hist[0] = strdup(vstr_str(line));
                return 1;
            } else if (c == 27) {
                escape = true;
            } else if (c == 127) {
                if (vstr_len(line) > len) {
                    vstr_cut_tail(line, 1);
                    stdout_tx_str("\b \b");
                }
            } else if (32 <= c && c <= 126) {
                vstr_add_char(line, c);
                stdout_tx_str(line->buf + line->len - 1);
            }
        } else if (escape == 1) {
            if (c == '[') {
                escape = 2;
            } else {
                escape = 0;
            }
        } else if (escape == 2) {
            escape = 0;
            if (c == 'A') {
                // up arrow
                if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
                    // erase line
                    for (int i = line->len - len; i > 0; i--) {
                        stdout_tx_str("\b \b");
                    }
                    // set line to history
                    line->len = len;
                    vstr_add_str(line, readline_hist[hist_num]);
                    // draw line
                    stdout_tx_str(readline_hist[hist_num]);
                    // increase hist num
                    hist_num += 1;
                }
            }
        } else {
            escape = 0;
        }
        delay(10);
    }
}

341
342
343
344
345
346
347
348
bool do_file(const char *filename) {
    mp_lexer_t *lex = mp_lexer_new_from_memzip_file(filename);

    if (lex == NULL) {
        printf("could not open file '%s' for reading\n", filename);
        return false;
    }

349
350
    mp_parse_error_kind_t parse_error_kind;
    mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
351
    qstr source_name = mp_lexer_source_name(lex);
352
353

    if (pn == MP_PARSE_NODE_NULL) {
354
        // parse error
355
        mp_parse_show_exception(lex, parse_error_kind);
356
        mp_lexer_free(lex);
357
358
359
        return false;
    }

360
361
    mp_lexer_free(lex);

362
    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
363
364
    mp_parse_node_free(pn);

365
366
367
368
369
370
    if (module_fun == mp_const_none) {
        return false;
    }

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
Damien George's avatar
Damien George committed
371
        mp_call_function_0(module_fun);
372
373
374
375
        nlr_pop();
        return true;
    } else {
        // uncaught exception
376
        mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR);
377
378
379
380
381
        printf("\n");
        return false;
    }
}

Dave Hylands's avatar
Dave Hylands committed
382
383
384
385
386
void do_repl(void) {
    stdout_tx_str("Micro Python for Teensy 3.1\r\n");
    stdout_tx_str("Type \"help()\" for more information.\r\n");

    vstr_t line;
387
    vstr_init(&line, 32);
Dave Hylands's avatar
Dave Hylands committed
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

    for (;;) {
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
        if (ret == 0) {
            // EOF
            break;
        }

        if (vstr_len(&line) == 0) {
            continue;
        }

        if (mp_repl_is_compound_stmt(vstr_str(&line))) {
            for (;;) {
                vstr_add_char(&line, '\n');
                int len = vstr_len(&line);
                int ret = readline(&line, "... ");
                if (ret == 0 || vstr_len(&line) == len) {
                    // done entering compound statement
                    break;
                }
            }
        }

413
        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
414
415
        mp_parse_error_kind_t parse_error_kind;
        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind);
416
417
418
419
        qstr source_name = mp_lexer_source_name(lex);

        if (pn == MP_PARSE_NODE_NULL) {
            // parse error
420
            mp_parse_show_exception(lex, parse_error_kind);
421
422
423
424
            mp_lexer_free(lex);
        } else {
            // parse okay
            mp_lexer_free(lex);
425
            mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
Dave Hylands's avatar
Dave Hylands committed
426
427
428
429
            if (module_fun != mp_const_none) {
                nlr_buf_t nlr;
                uint32_t start = micros();
                if (nlr_push(&nlr) == 0) {
Damien George's avatar
Damien George committed
430
                    mp_call_function_0(module_fun);
Dave Hylands's avatar
Dave Hylands committed
431
432
433
434
                    nlr_pop();
                    // optional timing
                    if (0) {
                        uint32_t ticks = micros() - start; // TODO implement a function that does this properly
435
                        printf("(took %lu ms)\n", ticks);
Dave Hylands's avatar
Dave Hylands committed
436
437
438
                    }
                } else {
                    // uncaught exception
439
                    mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR);
Dave Hylands's avatar
Dave Hylands committed
440
441
442
443
444
445
446
447
448
                    printf("\n");
                }
            }
        }
    }

    stdout_tx_str("\r\n");
}

449
int main(void) {
450
451
    pinMode(LED_BUILTIN, OUTPUT);
#if 0
Dave Hylands's avatar
Dave Hylands committed
452
453
454
455
    // Wait for host side to get connected
    while (!usb_vcp_is_connected()) {
        ;
    }
456
457
458
#else
    delay(1000);
#endif
Dave Hylands's avatar
Dave Hylands committed
459
460
461
462
463
464
465
466
467
468
469
470

    led_init();
    led_state(PYB_LED_BUILTIN, 1);

//    int first_soft_reset = true;

soft_reset:

    // GC init
    gc_init(&_heap_start, (void*)HEAP_END);

    qstr_init();
Damien George's avatar
Damien George committed
471
    mp_init();
Dave Hylands's avatar
Dave Hylands committed
472
473
474

    // add some functions to the python namespace
    {
Damien George's avatar
Damien George committed
475
        mp_store_name(MP_QSTR_help, mp_make_function_n(0, pyb_help));
476
        mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb);
Damien George's avatar
Damien George committed
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
        mp_store_attr(m, MP_QSTR_info, mp_make_function_n(0, pyb_info));
        mp_store_attr(m, MP_QSTR_source_dir, mp_make_function_n(1, pyb_source_dir));
        mp_store_attr(m, MP_QSTR_main, mp_make_function_n(1, pyb_main));
        mp_store_attr(m, MP_QSTR_gc, mp_make_function_n(0, pyb_gc));
        mp_store_attr(m, MP_QSTR_delay, mp_make_function_n(1, pyb_delay));
        mp_store_attr(m, MP_QSTR_led, mp_make_function_n(1, pyb_led));
        mp_store_attr(m, MP_QSTR_Led, mp_make_function_n(1, pyb_Led));
        mp_store_attr(m, MP_QSTR_analogRead, mp_make_function_n(1, pyb_analog_read));
        mp_store_attr(m, MP_QSTR_analogWrite, mp_make_function_n(2, pyb_analog_write));
        mp_store_attr(m, MP_QSTR_analogWriteResolution, mp_make_function_n(1, pyb_analog_write_resolution));
        mp_store_attr(m, MP_QSTR_analogWriteFrequency, mp_make_function_n(2, pyb_analog_write_frequency));

        mp_store_attr(m, MP_QSTR_gpio, (mp_obj_t)&pyb_gpio_obj);
        mp_store_attr(m, MP_QSTR_Servo, mp_make_function_n(0, pyb_Servo));
        mp_store_name(MP_QSTR_pyb, m);
        mp_store_name(MP_QSTR_run, mp_make_function_n(1, pyb_run));
Dave Hylands's avatar
Dave Hylands committed
493
494
    }

495
    printf("About execute /boot.py\n");
496
497
498
499
    if (!do_file("/boot.py")) {
        printf("Unable to open '/boot.py'\n");
        flash_error(4);
    }
500
    printf("Done executing /boot.py\n");
501

Dave Hylands's avatar
Dave Hylands committed
502
503
504
    // Turn bootup LED off
    led_state(PYB_LED_BUILTIN, 0);

505
506
507
508
    // run main script
    {
        vstr_t *vstr = vstr_new();
        vstr_add_str(vstr, "/");
509
        if (pyb_config_source_dir == MP_OBJ_NULL) {
510
511
            vstr_add_str(vstr, "src");
        } else {
512
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir));
513
514
        }
        vstr_add_char(vstr, '/');
515
        if (pyb_config_main == MP_OBJ_NULL) {
516
517
            vstr_add_str(vstr, "main.py");
        } else {
518
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main));
519
        }
520
        printf("About execute '%s'\n", vstr_str(vstr));
521
522
523
524
        if (!do_file(vstr_str(vstr))) {
            printf("Unable to open '%s'\n", vstr_str(vstr));
            flash_error(3);
        }
525
        printf("Done executing '%s'\n", vstr_str(vstr));
526
527
528
        vstr_free(vstr);
    }

Dave Hylands's avatar
Dave Hylands committed
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    do_repl();

    printf("PYB: soft reboot\n");

//    first_soft_reset = false;
    goto soft_reset;
}

double sqrt(double x) {
    // TODO
    return 0.0;
}

machine_float_t machine_sqrt(machine_float_t x) {
    // TODO
    return x;
}

// stub out __libc_init_array. It's called by mk20dx128.c and is used to call
// global C++ constructors. Since this is a C-only projects, we don't need to
// call constructors.
void __libc_init_array(void) {
}

char * ultoa(unsigned long val, char *buf, int radix) 	
{
	unsigned digit;
	int i=0, j;
	char t;

	while (1) {
		digit = val % radix;
		buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10);
		val /= radix;
		if (val == 0) break;
		i++;
	}
	buf[i + 1] = 0;
	for (j=0; j < i; j++, i--) {
		t = buf[j];
		buf[j] = buf[i];
		buf[i] = t;
	}
	return buf;
}