File: sig_i2c_bus.h

package info (click to toggle)
faumachine 20180503-4
  • links: PTS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 61,272 kB
  • sloc: ansic: 272,290; makefile: 6,199; asm: 4,251; sh: 3,022; perl: 886; xml: 563; pascal: 311; lex: 214; vhdl: 204
file content (309 lines) | stat: -rw-r--r-- 8,995 bytes parent folder | download
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
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
/*
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __SIG_I2C_BUS_H_INCLUDED
#define __SIG_I2C_BUS_H_INCLUDED

#include <stdbool.h>

#include "sig_gen.h"

/**
 * The I²C bus.
 */

/** possible callback handlers */
struct sig_i2c_bus_funcs {
	/* callbacks for cooked bus interface */

	/** read a byte from the slave device
	 *  @param s slave instance
	 *  @param val slave device fills in byte
	 */
	void (*read_byte)(void *s, unsigned char *val);

	/** write a byte to a the slave device
	 *  @param s slave instance
	 *  @param val byte value written to the slave device
	 *  @return true if the byte was acknowledge by the slave device, 
	 *          false otherwise.
	 */
	bool (*write_byte)(void *s, unsigned char val);

	/** acknowledge if the address belongs to the device.
	 *  @param s slave instance
	 *  @param addr 7+1 bit address (with last bit denoting read or
	 *         write access).
	 *  @return true if the device responds to given address, false 
	 *          otherwise.
	 */
	bool (*ack_addr)(void *s, unsigned char addr);

	/** stop the current transaction (aka stop condition).
	 *  @param s slave instance
	 */
	void (*stop_transaction)(void *s);

	/* callback handlers for signal line bus interface */

	/** callback handler, if the state of the data signal changes
	 *  @param s registered object.
	 *  @param data state of the data line.
	 */
	void (*data_event)(void *s, bool data);

	/** callback handler, if the state of the clock signal changes
	 *  @param s registered object
	 *  @param clk state of the clock line.
	 */
	void (*clk_event)(void *s, bool clk);
};

/** private enumeration for different i2c protocol states. All are meant
 *  from the POV of a i2c receiver (slave) device. */
enum SIG_I2C_PROTO_STATE {
	/** initial state, either nothing going on, or not interested in
	 *  because device not addressed. */
	SIG_I2C_NOT_INTERESTED,
	/** address phase. Transaction was started and address gets put on the
	 *  bus within the next 8 clock cycles. */
	SIG_I2C_ADR,
	/** s.th. was written to the bus, and the slave needs to generate an 
	 *  acknowledge in the next clock phase. This state is before the
	 *  next clock cycle.
	 */
	SIG_I2C_SLAVE_ACK,
	/** the slave generated an ACK in the last clock cycle. It needs to 
	 *  release the data line now after the clock has changed to low 
	 *  again.
	 */
	SIG_I2C_SLAVE_ACK_DOWN,
	/** address is set and valid, reading/writing data from the bus */
	SIG_I2C_DATA,
	/** master ACK expected with next clock */
	SIG_I2C_MASTER_ACK,
	/** master ACK was just sent or (NACK). */
	SIG_I2C_MASTER_ACK_DOWN,
};

/** structure for one member connected to the sig_i2c_bus.
 *  Not meant to be used outside of sig_i2c_bus.c.
 */
struct sig_i2c_bus_member {
	/** registered object for raw callbacks 
	 *  his points to the sender device instance for raw access
	 *  mode, and to the member instance for cooked access.
	 */
	void *s;
	/** registered object of the device for cooked access. */
	void *cs;
	/** link to the bus itself, in case of cooked access. */
	void *bus;
	/** callbacks contining a clock and data event */
	const struct sig_i2c_bus_funcs *f;
	/** eventually original callbacks, in case of cooked access */
	const struct sig_i2c_bus_funcs *cf;
	/** driving value of this member for the data signal */
	bool data;
	/** driving value of this member for the clock signal */
	bool clk;
	/** last sensed data value */
	bool last_data;
	/** last sensed clock value */
	bool last_clk;
	/** (slave) state of a connected device. */
	enum SIG_I2C_PROTO_STATE state;
	/** shift register for serial reading of a byte */
	unsigned char shift_register;
	/** shift counter for the shift_register */
	unsigned int counter;
	/** true, if in read_mode, false if in write_mode. */
	bool read_mode;
	/** is the member a bus segment? */
	bool is_bus_segment;
};

/** bus structure
 */
struct sig_i2c_bus {
	/** magic SIG_GEN_I2C_BUS */
	enum sig_gen_type type;

	/** connected members */
	struct sig_i2c_bus_member member[16];
	/** number of members connected to bus */
	unsigned int nmembers;

	/** resolved value of the clock signal */
	bool clk;
	/** resolved value of the data signal */
	bool data;
	/** slave index (for cooked transactions), -1 means unset */
	int slave;
	/** signal resolving/updating is in progress */
	bool resolve_in_progress;
	/** a signal change occured while signal resolving is in progress */
	bool resolve_again;
};

/** structure for connecting two bus segments */
struct sig_i2c_bus_merge {
	/** first bus instance */
	struct sig_i2c_bus *s0;
	/** second bus instance */
	struct sig_i2c_bus *s1;
};

/* cooked interface */

/** send a start condition and read size bytes from the 
 *  slave device with address addr. For a continued transaction,
 *  sig_i2c_read_bytes/sig_i2c_write_bytes may be called 
 *  repeatedly before sending a stop condition via 
 *  sig_i2c_bus_stop_transaction.
 *
 *  @param b bus instance.
 *  @param s sender instance.
 *  @param addr address of requested slave (must have read/write
 *         bit set accordingly).
 *  @param size read size bytes from slave until sending a NACK.
 *  @param buffer buffer which can store at least size bytes.
 *  @return true if the slave acknowledged the address and
 *          transferred size bytes (note: a slave cannot deny to
 *          transfer size bytes).
 */
extern bool
sig_i2c_bus_read_bytes(
	struct sig_i2c_bus *b,
	void *s,
	unsigned char addr,
	unsigned int size,
	unsigned char *buffer
);

/** send send a start condition and write size bytes to the slave
 *  device with address addr. For a continued transaction,
 *  sig_i2c_read_bytes/sig_i2c_write_bytes may be called 
 *  repeatedly before sending a stop condition via 
 *  sig_i2c_bus_stop_transaction.
 *
 *  @param b bus instance
 *  @param s sender instance.
 *  @param addr address of requested slave (must have read/write
 *         bit set accordingly).
 *  @param size write size bytes to slave.
 *  @param buffer buffer that holds at least size bytes.
 *  @return number of bytes acknowledged by the slave, -1 if
 *         no device responded to the address.
 */
extern int
sig_i2c_bus_write_bytes(
	struct sig_i2c_bus *b,
	void *s,
	unsigned char addr,
	unsigned int size,
	const unsigned char *buffer
);

/** stop the current transaction on the i²c bus by sending
 *  a stop condition.
 *  @param b bus instance.
 *  @param s sender instance.
 */
extern void
sig_i2c_bus_stop_transaction(
	struct sig_i2c_bus *b,
	void *s
);

/* raw bus handling... don't mix with abstract calls */

/** set the driving value for the data signal line
 *  @param b bus instance
 *  @param s sender instance
 *  @param val driving value for the data line
 */
extern void
sig_i2c_bus_set_data(struct sig_i2c_bus *b, void *s, bool val);

/** set the driving value for the clock signal line
 *  @param b bus instance
 *  @param s sender instance
 *  @param val driving value for the clock line
 */
extern void
sig_i2c_bus_set_clk(struct sig_i2c_bus *b, void *s, bool val);


/* general functions */

/** connect to the i2c bus, using raw access. For raw mode, a participant must
 *  provide callback handlers for clk_event and data_event.
 *  @param b bus instance
 *  @param s sender object
 *  @param f callback functions. Must use all of the raw callbacks.
 */
extern void
sig_i2c_bus_connect_raw(
	struct sig_i2c_bus *b, 
	void *s, 
	const struct sig_i2c_bus_funcs *f
);

/** connect to the i2c bus, using only the abstracted protocol interface
 *  With this method, a member must not call sig_i2c_bus_set_data and 
 *  sig_i2c_bus_set_clk.
 *
 *  @param b bus instance
 *  @param s sender object
 *  @param f callback functions.
 */
extern void
sig_i2c_bus_connect_cooked(
	struct sig_i2c_bus *b, 
	void *s, 
	const struct sig_i2c_bus_funcs *f
);


/** initilize the i2c bus
 *  @param name signal name
 *  @param nr signal number
 */
extern struct sig_i2c_bus *
sig_i2c_bus_create(const char *name);

/** destroy the i2c bus
 *  @param name signal name
 *  @param nr signal number
 */
extern void
sig_i2c_bus_destroy(struct sig_i2c_bus *sig);

/** connect two i2c busses s0 and s1 together.
 *  @param s0 one bus segement to connect
 *  @param s1 second bus segment to connect
 *  @return pointer to data structure that will hold the two bus segments
 */
extern struct sig_i2c_bus_merge *
sig_i2c_bus_merge(
	struct sig_i2c_bus *s0,
	struct sig_i2c_bus *s1
);

/** split two i2c busses.
 *  @param m pointer to data structure that holds the two bus segments.
 */
extern void
sig_i2c_bus_split(struct sig_i2c_bus_merge *m);

extern void
sig_i2c_bus_suspend(struct sig_i2c_bus *b, FILE *fSig);
extern void
sig_i2c_bus_resume(struct sig_i2c_bus *b, FILE *fSig);

#endif /* __SIG_I2C_BUS_H_INCLUDED */