summaryrefslogtreecommitdiff
path: root/dali_ctl.c
blob: 4d8f872cc3ae0d7e6ad54e1d7407e0fcc7fac9ed (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
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
#define DALI_C_QBALLAST		0x0191

#define DALI_C_TERMINATE	0xa100
#define DALI_C_DTR		0xa300
#define DALI_C_INITIALISE	0xa500
#define DALI_C_RANDOMISE	0xa700
#define DALI_C_COMPARE		0xa900
#define DALI_C_WITHDRAW		0xab00

#define DALI_C_SADDR_H		0xb100
#define DALI_C_SADDR_M		0xb300
#define DALI_C_SADDR_L		0xb500

#define DALI_C_PROGSHORT	0xb701
#define DALI_C_VRFYSHORT	0xb901
#define DALI_C_QURYSHORT	0xbb00

static uint8_t dali_s_byte, dali_sh, dali_sm, dali_sl;
static bool dali_s_notfound;

EEMEM uint8_t dali_nextaddr = 0x02;
static uint8_t dali_assign;

static bool dali_compare(void)
{
	uint16_t manchester = dalistat.manchester, falsestart = dalistat.falsestart, noise = dalistat.noise;

	dali_send(DALI_C_COMPARE);
	asm volatile ("" ::: "memory");

	return dali_rx_avail
		|| (manchester != dalistat.manchester)
		|| (falsestart != dalistat.falsestart)
		|| (noise != dalistat.noise);
}

static void dali_search_byte(uint16_t cmd)
{
	dali_s_byte = 0xff;
	uint8_t bit = 0x80;

	while (bit) {
		wdt_reset();

		dali_twice(cmd | (dali_s_byte & ~bit));
		if (dali_compare()) {
			_delay_ms(1);
			if (dali_compare())
				dali_s_byte &= ~bit;
		}
		bit >>= 1;
	}
	dali_twice(cmd | dali_s_byte);
	uart_puthex(dali_s_byte);
}

static void dali_search_single(void)
{
	dali_twice(DALI_C_SADDR_H | 0xff);
	dali_twice(DALI_C_SADDR_M | 0xff);
	dali_twice(DALI_C_SADDR_L | 0xff);

	if (!dali_compare()) {
		dali_s_notfound = 1;
		return;
	}

	dali_search_byte(DALI_C_SADDR_H);
	if (dali_s_notfound)
		return;
	dali_sh = dali_s_byte;
	dali_search_byte(DALI_C_SADDR_M);
	if (dali_s_notfound)
		return;
	dali_sm = dali_s_byte;
	dali_search_byte(DALI_C_SADDR_L);
	if (dali_s_notfound)
		return;
	dali_sl = dali_s_byte;
}

static void dali_search(void)
{
	uint8_t errtries = 0;

	dali_twice(DALI_C_INITIALISE);

	/* _some_ EVGs keep the long address in nonvolatile memory,
	 * among them the OSRAM one we have lying around.  however,
	 * this doesn't seem to work with Tridonic EVGs.
	 */
	dali_twice(DALI_C_RANDOMISE);

	dali_assign = eeprom_read_byte(&dali_nextaddr);

	do {
		uint8_t ph = dali_sh, pm = dali_sm, pl = dali_sl;

		uart_puttick();
		uart_puts("dali search... ");
		dali_search_single();
		uart_puts("\n");
		if (!dali_s_notfound) {
			wdt_reset();

			uart_puttick();
			uart_puts("dali scan found\t\t");
			uart_puthex(dali_sh);
			uart_puthex(dali_sm);
			uart_puthex(dali_sl);
			dali_send(DALI_C_QURYSHORT);
			if (!dali_rx_avail)
				dali_send(DALI_C_QURYSHORT);
			wdt_reset();
			if (dali_rx_avail) {
				uint8_t addr = 0xff;
				errtries = 0;

				if ((dali_rx & 0x81) == 0x01) {
					addr = dali_rx >> 1;

					uart_puts(" current: ");
					uart_puthex(addr);
				}

				if (addr == 0x00 || target_present(addr)) {
					uart_puts(" reprog");
					addr = 0xff;
				}

				if (addr == 0xff) {
					dali_send(DALI_C_PROGSHORT | (dali_assign << 1));
					dali_send(DALI_C_VRFYSHORT | (dali_assign << 1));
					if (dali_rx_avail) {
						uart_puts("prog ");
						uart_puthex(dali_assign);
					} else
						uart_puts("progfail");

					addr = dali_assign;
					dali_assign++;
				}
				uart_puts("\n");

				if (addr < 64)
					target_set_present(addr);

				wdt_reset();
				dali_send(DALI_C_WITHDRAW);
			} else {
				uart_puts(" error\n");
				if (errtries < 3) {
					dali_sh = ph;
					dali_sm = pm;
					dali_sl = pl;
					errtries++;
				} else
					errtries = 0;
			}

		}
	} while (!dali_s_notfound);

	wdt_reset();

	dali_twice(DALI_C_TERMINATE);
	uart_puttick();
	uart_puts("dali scan end\n");

	eeprom_write_byte(&dali_nextaddr, dali_assign);
}