librobotcontrol-sys 0.4.0

Rust port of librobotcontrol
Documentation
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/**
 * @file i2c.c
 *
 * @author James Strawson
 */

#include <stdint.h> // for uint8_t types etc
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h> //for IOCTL defs

#include <rc/i2c.h>

// preposessor macros
#define unlikely(x)	__builtin_expect (!!(x), 0)
#define likely(x)	__builtin_expect (!!(x), 1)


/**
 * contains the current state of a bus. you don't need to create your own
 * instance of this, one for each bus is allocated here
 */
typedef struct rc_i2c_state_t {
	/* data */
	uint8_t devAddr;
	int fd;
	int initialized;
	int lock;
} rc_i2c_state_t;

static rc_i2c_state_t i2c[I2C_MAX_BUS+1];


// local function
static int __check_bus_range(int bus)
{
	if(unlikely(bus<0 || bus>I2C_MAX_BUS)){
		fprintf(stderr,"ERROR: i2c bus must be between 0 & %d\n", I2C_MAX_BUS);
		return -1;
	}
	return 0;
}


int rc_i2c_init(int bus, uint8_t devAddr)
{
	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;

	// if already initialized just set the device address
	if(i2c[bus].initialized){
		return rc_i2c_set_device_address(bus, devAddr);
	}

	// lock the bus during this operation
	i2c[bus].lock = 1;
	i2c[bus].initialized = 0;

	// open file descriptor
	char str[16];
	sprintf(str,"/dev/i2c-%d",bus);
	i2c[bus].fd = open(str, O_RDWR);
	if(i2c[bus].fd==-1){
		fprintf(stderr,"ERROR: in rc_i2c_init, failed to open /dev/i2c\n");
		return -1;
	}

	// set device adress
	if(unlikely(ioctl(i2c[bus].fd, I2C_SLAVE, devAddr)<0)){
		fprintf(stderr,"ERROR: in rc_i2c_init, ioctl slave address change failed\n");
		return -1;
	}
	i2c[bus].devAddr = devAddr;
	// return the lock state to previous state.
	i2c[bus].lock = 0;
	i2c[bus].initialized = 1;
	return 0;
}


int rc_i2c_close(int bus)
{
	if(unlikely(__check_bus_range(bus))) return -1;
	close(i2c[bus].fd);
	i2c[bus].devAddr = 0;
	i2c[bus].initialized = 0;
	i2c[bus].lock=0;
	return 0;
}



int rc_i2c_set_device_address(int bus, uint8_t devAddr)
{
	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_set_device_address, bus not initialized yet\n");
		return -1;
	}
	// if the device address is already correct, just return
	if(i2c[bus].devAddr == devAddr){
		return 0;
	}
	// if not, change it with ioctl
	if(unlikely(ioctl(i2c[bus].fd, I2C_SLAVE, devAddr)<0)){
		fprintf(stderr,"ERROR: in rc_i2c_set_device_address, ioctl slave address change failed\n");
		return -1;
	}
	i2c[bus].devAddr = devAddr;
	return 0;
}


int rc_i2c_read_byte(int bus, uint8_t regAddr, uint8_t *data)
{
	return rc_i2c_read_bytes(bus, regAddr, 1, data);
}


int rc_i2c_read_bytes(int bus, uint8_t regAddr, size_t count, uint8_t *data)
{
	int ret, old_lock;

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_read_bytes, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation, preserving old state to return to
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// write register to device
	ret = write(i2c[bus].fd, &regAddr, 1);
	if(unlikely(ret!=1)){
		fprintf(stderr,"ERROR: in rc_i2c_read_bytes, failed to write to bus\n");
		i2c[bus].lock = old_lock;
		return -1;
	}

	// then read the response
	ret = read(i2c[bus].fd, data, count);
	if(unlikely((size_t)ret!=count)){
		fprintf(stderr,"ERROR: in rc_i2c_read_bytes, received %d bytes from device, expected %d\n", ret, (int)count);
		i2c[bus].lock = old_lock;
		return -1;
	}

	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return ret;


}


int rc_i2c_read_word(int bus, uint8_t regAddr, uint16_t *data)
{
	return rc_i2c_read_words(bus, regAddr, 1, data);
}


int rc_i2c_read_words(int bus, uint8_t regAddr, size_t count, uint16_t *data)
{
	int ret, old_lock;
	size_t i;
	char buf[count*2];

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_read_words, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// write register to device
	ret = write(i2c[bus].fd, &regAddr, 1);
	if(unlikely(ret!=1)){
		fprintf(stderr,"ERROR: in rc_i2c_read_words, failed to write to bus\n");
		i2c[bus].lock = old_lock;
		return -1;
	}

	// then read the response
	ret = read(i2c[bus].fd, buf, count*2);
	if(ret!=(signed)(count*2)){
		fprintf(stderr,"ERROR: in rc_i2c_read_words, received %d bytes, expected %zu\n", ret, count*2);
		i2c[bus].lock = old_lock;
		return -1;
	}

	// form words from bytes and put into user's data array
	for(i=0;i<count;i++){
		data[i] = (((uint16_t)buf[i*2])<<8 | buf[(i*2)+1]);
	}

	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return 0;
}





int rc_i2c_write_bytes(int bus, uint8_t regAddr, size_t count, uint8_t* data)
{
	int ret, old_lock;
	size_t i;
	uint8_t writeData[count+1];

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_write_bytes, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// assemble array to send, starting with the register address
	writeData[0] = regAddr;
	for(i=0; i<count; i++) writeData[i+1]=data[i];

	// send the bytes
	ret = write(i2c[bus].fd, writeData, count+1);
	// write should have returned the correct # bytes written
	if(unlikely(ret!=(signed)(count+1))){
		fprintf(stderr,"ERROR in rc_i2c_write_bytes, bus wrote %d bytes, expected %zu\n", ret, count+1);
		i2c[bus].lock = old_lock;
		return -1;
	}
	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return 0;
}


int rc_i2c_write_byte(int bus, uint8_t regAddr, uint8_t data)
{
	int ret, old_lock;
	uint8_t writeData[2];

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_write_byte, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// assemble array to send, starting with the register address
	writeData[0] = regAddr;
	writeData[1] = data;

	// send the bytes
	ret = write(i2c[bus].fd, writeData, 2);

	// write should have returned the correct # bytes written
	if(unlikely(ret!=2)){
		fprintf(stderr,"ERROR: in rc_i2c_write_byte, system write returned %d, expected 2\n", ret);
		i2c[bus].lock = old_lock;
		return -1;
	}
	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return 0;
}


int rc_i2c_write_words(int bus, uint8_t regAddr, size_t count, uint16_t* data)
{
	int ret,old_lock;
	size_t i;
	uint8_t writeData[(count*2)+1];

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_write_words, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// assemble bytes to send
	writeData[0] = regAddr;
	for (i=0; i<count; i++){
		writeData[(i*2)+1] = (uint8_t)(data[i] >> 8);
		writeData[(i*2)+2] = (uint8_t)(data[i] & 0xFF);
	}

	ret = write(i2c[bus].fd, writeData, (count*2)+1);
	if(unlikely(ret!=(signed)(count*2)+1)){
		fprintf(stderr,"ERROR: in rc_i2c_write_words, system write returned %d, expected %zu\n", ret, (count*2)+1);
		i2c[bus].lock = old_lock;
		return -1;
	}
	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return 0;
}


int rc_i2c_write_word(int bus, uint8_t regAddr, uint16_t data)
{
	int ret,old_lock;
	uint8_t writeData[3];

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_write_words, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	old_lock = i2c[bus].lock;
	i2c[bus].lock = 1;

	// assemble bytes to send from data casted as uint8_t*
	writeData[0] = regAddr;
	writeData[1] = (uint8_t)(data >> 8);
	writeData[2] = (uint8_t)(data & 0xFF);

	ret = write(i2c[bus].fd, writeData, 3);
	if(unlikely(ret!=3)){
		fprintf(stderr,"ERROR: in rc_i2c_write_word, system write returned %d, expected 3\n", ret);
		i2c[bus].lock = old_lock;
		return -1;
	}
	// return the lock state to previous state.
	i2c[bus].lock = old_lock;
	return 0;
}


int rc_i2c_send_byte(int bus, uint8_t data)
{
	return rc_i2c_send_bytes(bus,1,&data);
}


int rc_i2c_send_bytes(int bus, size_t count, uint8_t* data)
{
	int ret;

	// sanity check
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_send_bytes, bus not initialized yet\n");
		return -1;
	}

	// lock the bus during this operation
	int old_lock= i2c[bus].lock;
	i2c[bus].lock = 1;

	// send the bytes
	ret = write(i2c[bus].fd, data, count);
	// write should have returned the correct # bytes written
	if(ret!=(signed)count){
		fprintf(stderr,"ERROR: in rc_i2c_send_bytes, system write returned %d, expected %zu\n", ret, count);
		i2c[bus].lock = old_lock;
		return -1;
	}

	// return the lock state to previous state.
	i2c[bus].lock = old_lock;

	return 0;
}






int rc_i2c_lock_bus(int bus)
{
	if(unlikely(__check_bus_range(bus))) return -1;
	int ret=i2c[bus].lock;
	i2c[bus].lock=1;
	return ret;
}


int rc_i2c_unlock_bus(int bus)
{
	if(unlikely(__check_bus_range(bus))) return -1;
	int ret=i2c[bus].lock;
	i2c[bus].lock=0;
	return ret;
}


int rc_i2c_get_lock(int bus)
{
	if(unlikely(__check_bus_range(bus))) return -1;
	return i2c[bus].lock;
}


int rc_i2c_get_fd(int bus) {
	if(unlikely(__check_bus_range(bus))) return -1;
	if(unlikely(i2c[bus].initialized==0)){
		fprintf(stderr,"ERROR: in rc_i2c_get_fd, bus not initialized yet\n");
		return -1;
	}
	return i2c[bus].fd;
}


#ifdef RC_AUTOPILOT_EXT
int rc_i2c_read_data(int bus, uint8_t regAddr, size_t length, uint8_t *data)
{
	return rc_i2c_read_bytes(bus, regAddr, length, data);
}
#endif // RC_AUTOPILOT_EXT