summaryrefslogtreecommitdiff
path: root/firmware/src/os/blinkcode.c
blob: 9e887164e1f80bd46a25e5be0fe544dd2313e7a9 (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
/* SAM7DFU blink code support 
 * (C) 2006 by Harald Welte <laforge@gnumonks.org>
 *
 */

#include <os/pit.h>
#include <os/dbgu.h>
#include <os/led.h>
#include <os/blinkcode.h>

#define NUM_LEDS 2

enum blinkcode_state {
	BLINKCODE_STATE_NONE,
	BLINKCODE_STATE_SILENT,		/* period of silence at start */
	BLINKCODE_STATE_INIT,		/* initial long light */
	BLINKCODE_STATE_BLINK_OFF,	/* blinking out, currently off */
	BLINKCODE_STATE_BLINK_ON,	/* blinking out, currently on */
	BLINKCODE_STATE_DONE,
};

#define TIME_SILENT	(1*HZ)
#define TIME_INIT	(1*HZ)
#define TIME_BLINK	(HZ/4)

struct blinker {
	struct timer_list timer;
	enum blinkcode_state state;
	int num;
	int cur;
	uint8_t led;
};

static struct blinker blink_state[NUM_LEDS];

static void blinkcode_cb(void *data)
{
	/* we got called back by the timer */
	struct blinker *bl = data;
	
	DEBUGPCRF("(jiffies=%lu, data=%p, state=%u)",
		  jiffies, data, bl->state);
	switch (bl->state) {
	case BLINKCODE_STATE_NONE:
		led_switch(bl->led, 0);
		bl->state = BLINKCODE_STATE_SILENT;
		bl->timer.expires = jiffies + TIME_SILENT;
		bl->cur = bl->num;
		break;
	case BLINKCODE_STATE_SILENT:
		/* we've finished the period of silence, turn led on */
		led_switch(bl->led, 1);
		bl->state = BLINKCODE_STATE_INIT;
		bl->timer.expires = jiffies + TIME_INIT;
		break;
	case BLINKCODE_STATE_INIT:
		/* we've finished the period of init */
		led_switch(bl->led, 0);
		bl->state = BLINKCODE_STATE_BLINK_OFF;
		bl->timer.expires = jiffies + TIME_INIT;
		break;
	case BLINKCODE_STATE_BLINK_OFF:
		/* we've been off, turn on */
		led_switch(bl->led, 1);
		bl->state = BLINKCODE_STATE_BLINK_ON;
		bl->cur--;
		bl->timer.expires = jiffies + TIME_BLINK;
		if (bl->cur <= 0)
			bl->state = BLINKCODE_STATE_DONE;
		break;
	case BLINKCODE_STATE_BLINK_ON:
		/* we've been on, turn off */
		led_switch(bl->led, 0);
		bl->state = BLINKCODE_STATE_BLINK_OFF;
		bl->timer.expires = jiffies + TIME_BLINK;
		break;
	case BLINKCODE_STATE_DONE:
		/* we've been on, turn off */
		led_switch(bl->led, 0);
		return;
		break;
	}
	/* default case: re-add the timer */
	timer_add(&bl->timer);
}

void blinkcode_set(int led, enum blinkcode_num num)
{
	DEBUGPCRF("(jiffies=%lu, led=%u, num=%u)", jiffies, led, num);

	if (--led > NUM_LEDS)
		return;

	timer_del(&blink_state[led].timer);

	blink_state[led].num = num;
	blink_state[led].state = BLINKCODE_STATE_NONE;
	blink_state[led].timer.expires = jiffies;

	if (num != BLINKCODE_NONE)
		timer_add(&blink_state[led].timer);
}

void blinkcode_init(void)
{
	int i;

	for (i = 0; i < NUM_LEDS; i++) {
		blink_state[i].num = 0;
		blink_state[i].state = BLINKCODE_STATE_NONE;
		blink_state[i].led = i+1;
		blink_state[i].timer.data = &blink_state[i];
		blink_state[i].timer.function = &blinkcode_cb;
	}
}
personal git repositories of Harald Welte. Your mileage may vary