aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/cpu-firmware/util.c
blob: c41afba69dc543cff2f1d7acf5d62325b187f2b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
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
/*
 *   Utility functions
 *
 *   Copyright (C) 2009-2011 Michael Buesch <m@bues.ch>
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   version 2 as published by the Free Software Foundation.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 */

#include "util.h"
#include "main.h"
#include "debug.h"
#include "lcd.h"
#include "uart.h"

#include <avr/io.h>
#include <avr/wdt.h>


void long_delay_ms(uint16_t ms)
{
	while (ms) {
		_delay_ms(50);
		wdt_reset();
		ms = (ms >= 50) ? ms - 50 : 0;
	}
}

char hexdigit_to_ascii(uint8_t digit)
{
	/* Convert a hexadecimal digit (0-F) to an ASCII character */
	if (digit >= 0xAu)
		digit = (uint8_t)(digit + 0x41u - 0xAu);
	else
		digit = (uint8_t)(digit + 0x30u);
	return (char)digit;
}

#ifndef BOOTLOADER
void do_panic(const char PROGPTR *msg)
{
	irq_disable();

	debug_printf("*** PANIC :( ***\n");
	_debug_printf(msg);
	debug_printf("\n");

	lcd_clear_buffer();
	lcd_printf("*** PANIC :( ***\n");
	lcd_commit();

	long_delay_ms(10000);
	reboot();
}

void reboot(void)
{
	irq_disable();
	debug_printf("*** REBOOTING ***\n");
	wdt_enable(WDTO_15MS);
	while (1);
}

uint8_t ffs16(uint16_t value)
{
	uint16_t mask;
	uint8_t count;

	for (mask = 1, count = 1; mask; mask <<= 1, count++) {
		if (value & mask)
			return count;
	}

	return 0;
}

#endif /* BOOTLOADER */

#ifdef STACKCHECK

/* Stack usage threshold, in percent of SRAM */
#define STACKTHRES	25

#define RAMSIZE		(RAMEND - RAMSTART)
#define STACKLIM	(RAMEND - ((uint32_t)RAMSIZE * STACKTHRES / 100))

static noinstrument void stack_check(void *this_fn,
				     void *call_site)
{
	static bool had_overflow = 0;
	uint16_t sp = SP;

	if (sp >= STACKLIM)
		return;
	if (had_overflow)
		return;

	had_overflow = 1;
	mb();

	uart_putstr("WARNING: Stack size limit reached in 0x");
	uart_puthex((uint16_t)this_fn >> 8);
	uart_puthex((uint16_t)this_fn);
	uart_putstr(" (called from 0x");
	uart_puthex((uint16_t)call_site >> 8);
	uart_puthex((uint16_t)call_site);
	uart_putstr(")\n");
}

noinstrument noinline void __cyg_profile_func_enter(void *this_fn,
						    void *call_site)
{
	stack_check(this_fn, call_site);
}

noinstrument noinline void __cyg_profile_func_exit(void *this_fn,
						   void *call_site)
{
}
#endif /* STACKCHECK */
bues.ch cgit interface