-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathsw.c
122 lines (103 loc) · 3.18 KB
/
sw.c
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
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>
#include <util/delay.h>
#include "external/fleury-i2cmaster/i2cmaster_a.h"
#include "external/fleury-i2cmaster/i2cmaster_b.h"
#include "protocol.h"
#include "sw.h"
#define SWITCH_CNT 5
// switch turn-on time @3.3V from datasheet, probably even less for 5V
#define SWITCH_ON_DELAY_US 35
const __flash struct switch_drv {
void (*i2c_start_wait)(unsigned char);
void (*i2c_stop)(void);
unsigned char (*i2c_write)(unsigned char);
uint8_t i2c_addr;
uint8_t gnd_mask;
} zif_switch[SWITCH_CNT] = {
{i2c_a_start_wait, i2c_a_stop, i2c_a_write, 0x98, 0b00110000}, // A0
{i2c_a_start_wait, i2c_a_stop, i2c_a_write, 0x9a, 0b10101011}, // A1
{i2c_a_start_wait, i2c_a_stop, i2c_a_write, 0x9c, 0b00000010}, // A2
{i2c_b_start_wait, i2c_b_stop, i2c_b_write, 0x98, 0b00101011}, // B0
{i2c_b_start_wait, i2c_b_stop, i2c_b_write, 0x9c, 0b00000000}, // B1 (i2c address is 2 instead of 1)
};
uint8_t switch_config[MAX_CONFIGS][SWITCH_CNT];
uint8_t *switch_config_active;
// -----------------------------------------------------------------------
void sw_init()
{
i2c_a_init();
i2c_b_init();
sw_config_clear();
switch_config_active = NULL;
}
// -----------------------------------------------------------------------
void sw_config_select(uint8_t cfgnum)
{
switch_config_active = switch_config[cfgnum];
}
// -----------------------------------------------------------------------
void sw_on(uint8_t port, uint8_t bit)
{
switch_config_active[port] |= _BV(bit);
}
// -----------------------------------------------------------------------
bool sw_config_sane()
{
if ((switch_config_active[A1] & 0b00001010) == 0b00001010) return false; // pin 8 VCC+GND
if ((switch_config_active[B0] & 0b00000011) == 0b00000011) return false; // pin 24 VCC+GND
// check for disallowed inter-config changes
return true;
}
// -----------------------------------------------------------------------
static void sw_push_config(uint8_t pin_type)
{
const __flash struct switch_drv *sw = zif_switch;
for (uint8_t i=0 ; i<SWITCH_CNT ; i++, sw++) {
uint16_t switch_config = switch_config_active[i];
if (pin_type == SW_PINS_PWR) {
switch_config &= sw->gnd_mask;
}
sw->i2c_start_wait(sw->i2c_addr);
sw->i2c_write(0);
sw->i2c_write(switch_config);
sw->i2c_stop();
}
}
// -----------------------------------------------------------------------
bool sw_connect(uint8_t pin_type)
{
if (!switch_config_active) {
error(ERR_NO_PINCFG);
return false;
}
if (!sw_config_sane()) {
error(ERR_PIN_COMB);
return false;
}
sw_push_config(pin_type);
_delay_us(SWITCH_ON_DELAY_US);
return true;
}
// -----------------------------------------------------------------------
void sw_config_clear()
{
for (uint8_t cfgnum=0 ; cfgnum<MAX_CONFIGS ; cfgnum++) {
for (uint8_t i=0 ; i<SWITCH_CNT ; i++) {
switch_config[cfgnum][i] = 0;
}
}
}
// -----------------------------------------------------------------------
void sw_disconnect()
{
if (!switch_config_active) return;
// disconnect grounds last
sw_push_config(SW_PINS_PWR);
sw_config_clear();
sw_push_config(SW_PINS_ALL);
_delay_us(SWITCH_ON_DELAY_US);
switch_config_active = NULL;
}
// vim: tabstop=4 shiftwidth=4 autoindent