ngc 1.4.0
 
Loading...
Searching...
No Matches
ngcbI2C.hpp
Go to the documentation of this file.
1
7#ifndef ngcbI2C_H
8#define ngcbI2C_H
9
10
11#ifndef __cplusplus
12#error This is a C++ include file and cannot be used from plain C
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17
19#define ngcbI2C_TX_SIZE7(n) ((((n + 1) * 8) + 2) * 3)
20
22#define ngcbI2C_TX_SIZE10(n) ((((n + 2) * 8) + 2) * 3)
23
24/*
25 * Error codes
26 */
27
29#define ngcbI2C_ERR_CLK 0x0000000A
30
32#define ngcbI2C_ERR_ACK 0x0000000B
33
37class ngcbI2C {
38public:
43 ngcbI2C() {Init_(0, 1, 0);}
44
50 explicit ngcbI2C(int cnt) {Init_(0, 1, cnt);}
51
56 ngcbI2C(int scl, int sda) {Init_(scl, sda, 0);}
57
67 ngcbI2C(int scl, int sda, int cnt) {Init_(scl, sda, cnt);}
68
73 ngcbI2C(int scl, int sda, int sclIn, int sdaIn, int ackIn, int cnt) {
74 Init_(scl, sda, cnt);
75 sclIn_ = sclIn;
76 sdaIn_ = sdaIn;
77 ackIn_ = ackIn;
78 }
79
81 virtual ~ngcbI2C() {}
82
84 char *ErrMsg() {return (erms_);}
85
87 void AckOn() {ignoreAck_ = 0;}
88
90 void AckOff() {ignoreAck_ = 1;}
91
93 void SCL_IN(int bit) {sclIn_ = bit;}
94
96 void SDA_IN(int bit) {sdaIn_ = bit; ackIn_ = sdaIn_;}
97
99 void ACK_IN(int bit) {ackIn_ = bit;}
100
102 void SDA_DIR_SWITCH(int bit) {sdaDirSwitch_ = bit;}
103
105 void SCL_DIR_SWITCH(int bit) {sclDirSwitch_ = bit;}
106
108 void ClkStretching(int rx, int tx) {
109 /*
110 * Clock-stretching capability on RX-operations
111 */
112 if (rx < 0) rxStretching_ = 0;
113 else rxStretching_ = rx;
114
115 /*
116 * Clock-stretching capability on TX-operations
117 */
118 if (tx < 0) txStretching_ = 0;
119 else txStretching_ = tx;
120 }
121
123 void ClkStretchCnt(int cnt) {
124 if (cnt < 0) clkStretchCnt_ = 0;
125 else clkStretchCnt_ = cnt;
126 }
127
129 int ClkStretchCnt() {return (clkStretchCnt_);}
130
132 int Write(int addr, const char *byte, int n) {
133 int byteBuf[8 * 3];
134 int *b;
135 int i = 0;
136 int res;
137
138 erms_[0] = '\0';
139
140 /*
141 * Start
142 */
143 res = Start_();
144 if (res != 0)
145 {
146 return (res);
147 }
148
149 b = byteBuf;
150
151 /*
152 * 7-Bit address
153 */
154 for (i=6;i>=0;i--)
155 {
156 *b++ = ((addr >> i) & 0x1) << sda_;
157 *b++ = (((addr >> i) & 0x1) << sda_) | (1 << scl_);
158 *b++ = ((addr >> i) & 0x1) << sda_;
159 }
160
161 /*
162 * R/W bit (0 for write-operation)
163 */
164 *b++ = 0x0;
165 *b++ = 1 << scl_;
166 *b++ = 0x0;
167
168 /*
169 * Send the address byte
170 */
171 res = SendByte_(byteBuf);
172 if (res != 0)
173 {
174 return (res);
175 }
176
177 /*
178 * Now send the n data bytes
179 */
180 for (i=0;i<n;i++)
181 {
182 int j;
183
184 b = byteBuf;
185 for (j=7;j>=0;j--)
186 {
187 *b++ = ((byte[i] >> j) & 0x1) << sda_;
188 *b++ = (((byte[i] >> j) & 0x1) << sda_) | (1 << scl_);
189 *b++ = ((byte[i] >> j) & 0x1) << sda_;
190 }
191
192 res = SendByte_(byteBuf);
193 if (res != 0)
194 {
195 return (res);
196 }
197 }
198
199 /*
200 * Stop
201 */
202 res = Stop_();
203 if (res != 0)
204 {
205 return (res);
206 }
207
208 return (0);
209 }
210
212 int Write10(int addr, const char *byte, int n) {
213 int byteBuf[8 * 3];
214 int *b;
215 int i = 0;
216 int res;
217 int a0 = addr & 0xff;
218 int a1 = 0xf0 | ((addr >> 7) & 0x6);
219
220 erms_[0] = '\0';
221
222 /*
223 * Start
224 */
225 res = Start_();
226 if (res != 0)
227 {
228 return (res);
229 }
230
231 /*
232 * 10-Bit marker + 2 MSB bits of address + R/W
233 */
234 b = byteBuf;
235 for (i=7;i>=0;i--)
236 {
237 *b++ = ((a1 >> i) & 0x1) << sda_;
238 *b++ = (((a1 >> i) & 0x1) << sda_) | (1 << scl_);
239 *b++ = ((a1 >> i) & 0x1) << sda_;
240 }
241 res = SendByte_(byteBuf);
242 if (res != 0)
243 {
244 return (res);
245 }
246
247 /*
248 * 8 LSB bits of address
249 */
250 b = byteBuf;
251 for (i=7;i>=0;i--)
252 {
253 *b++ = ((a0 >> i) & 0x1) << sda_;
254 *b++ = (((a0 >> i) & 0x1) << sda_) | (1 << scl_);
255 *b++ = ((a0 >> i) & 0x1) << sda_;
256 }
257 res = SendByte_(byteBuf);
258 if (res != 0)
259 {
260 return (res);
261 }
262
263 /*
264 * Now send the n bytes
265 */
266 for (i=0;i<n;i++)
267 {
268 int j;
269
270 b = byteBuf;
271 for (j=7;j>=0;j--)
272 {
273 *b++ = ((byte[i] >> j) & 0x1) << sda_;
274 *b++ = (((byte[i] >> j) & 0x1) << sda_) | (1 << scl_);
275 *b++ = ((byte[i] >> j) & 0x1) << sda_;
276 }
277
278 res = SendByte_(byteBuf);
279 if (res != 0)
280 {
281 return (res);
282 }
283 }
284
285 /*
286 * Stop
287 */
288 res = Stop_();
289 if (res != 0)
290 {
291 return (res);
292 }
293
294 return (0);
295 }
296
298 int Read(int addr, char *byte, int n) {
299 int byteBuf[8 * 3];
300 int *b;
301 int i = 0;
302 int res;
303
304 erms_[0] = '\0';
305
306 /*
307 * Start
308 */
309 res = Start_();
310 if (res != 0)
311 {
312 return (res);
313 }
314
315 b = byteBuf;
316
317 /*
318 * 7-Bit address
319 */
320 for (i=6;i>=0;i--)
321 {
322 *b++ = ((addr >> i) & 0x1) << sda_;
323 *b++ = (((addr >> i) & 0x1) << sda_) | (1 << scl_);
324 *b++ = ((addr >> i) & 0x1) << sda_;
325 }
326
327 /*
328 * R/W bit (1 for read-operation)
329 */
330 *b++ = (0x1 << sda_) | (0x0 << scl_);
331 *b++ = (0x1 << sda_) | (0x1 << scl_);
332 *b++ = (0x1 << sda_) | (0x0 << scl_);
333
334 /*
335 * Send the address byte
336 */
337 res = SendByte_(byteBuf);
338 if (res != 0)
339 {
340 return (res);
341 }
342
343 /*
344 * Now read the n bytes
345 */
346 for (i=0;i<n;i++)
347 {
348 res = RecvByte_(&byte[i], (i == (n-1)));
349 if (res != 0)
350 {
351 return (res);
352 }
353 }
354
355 /*
356 * Stop
357 */
358 res = Stop_();
359 if (res != 0)
360 {
361 return (res);
362 }
363
364 return (0);
365 }
366
368 int Read10(int addr, char *byte, int n) {
369 int byteBuf[8 * 3];
370 int *b;
371 int i = 0;
372 int res;
373 int a0 = addr & 0xff;
374 int a1 = 0xf1 | ((addr >> 7) & 0x6);
375
376 erms_[0] = '\0';
377
378 /*
379 * Start
380 */
381 res = Start_();
382 if (res != 0)
383 {
384 return (res);
385 }
386
387 /*
388 * 10-Bit marker + 2 MSB bits of address + R/W
389 */
390 b = byteBuf;
391 for (i=7;i>=0;i--)
392 {
393 *b++ = ((a1 >> i) & 0x1) << sda_;
394 *b++ = (((a1 >> i) & 0x1) << sda_) | (1 << scl_);
395 *b++ = ((a1 >> i) & 0x1) << sda_;
396 }
397 res = SendByte_(byteBuf);
398 if (res != 0)
399 {
400 return (res);
401 }
402
403 /*
404 * 8 LSB bits of address
405 */
406 b = byteBuf;
407 for (i=7;i>=0;i--)
408 {
409 *b++ = ((a0 >> i) & 0x1) << sda_;
410 *b++ = (((a0 >> i) & 0x1) << sda_) | (1 << scl_);
411 *b++ = ((a0 >> i) & 0x1) << sda_;
412 }
413 res = SendByte_(byteBuf);
414 if (res != 0)
415 {
416 return (res);
417 }
418
419 /*
420 * Now read the n bytes
421 */
422 for (i=0;i<n;i++)
423 {
424 res = RecvByte_(&byte[i]);
425 if (res != 0)
426 {
427 return (res);
428 }
429 }
430
431 /*
432 * Stop
433 */
434 res = Stop_();
435 if (res != 0)
436 {
437 return (res);
438 }
439
440 return (0);
441 }
442
444 int LastState() {
445 int s = lastState_ & (1 << sda_) & (1 << scl_);
446 return (s);
447 }
448
449protected:
451 virtual int OutCB(int d, int *resultCode, char *erms) {
452 char s[33];
453 *resultCode = 0;
454 erms[0] = '\0';
455 Int2Bin_(s, d);
456 fprintf(stdout, "<%s>\n", s);
457 return (0);
458 }
459
461 virtual int InCB(int *d, int *resultCode, char *erms) {
462 *resultCode = 0;
463 erms[0] = '\0';
464 *d = 0;
465 return (0);
466 }
467
468private:
470 char erms_[256];
471
473 int scl_;
474
476 int sda_;
477
479 int sclIn_;
480
482 int sdaIn_;
483
485 int ackIn_;
486
488 int sdaDirSwitch_;
489
491 int sclDirSwitch_;
492
494 int lastClkState_;
495
497 int clkStretchCnt_;
498
500 int ignoreAck_;
501
503 int txStretching_;
504
506 int rxStretching_;
507
509 int lastState_;
510
512 void Init_(int scl, int sda, int cnt) {
513 scl_ = scl;
514 sda_ = sda;
515 clkStretchCnt_ = cnt;
516
517 sclIn_ = scl_; // same as SCL output
518 sdaIn_ = sda_; // same as SDA output
519 ackIn_ = sdaIn_; // same as SDA input
520 sdaDirSwitch_ = -1; // SDA direction switch disabled
521 sclDirSwitch_ = -1; // SCL direction disabled
522
523 erms_[0] = '\0';
524
525 lastClkState_ = -1; // unknown
526 lastState_ = 0x0; // all lines zero
527 ignoreAck_ = 0; // consider acknowledge signal
528 txStretching_ = 0; // no clock stretching for write operations
529 rxStretching_ = 1; // clock stretching for read operations
530 }
531
533 int Start_() {
534 int buf[2];
535 buf[0] = (0x1 << sda_) | (0x1 << scl_);
536 buf[1] = (0x0 << sda_) | (0x1 << scl_);
537 return (Out_(buf, 2));
538 }
539
541 int Stop_() {
542 int buf[2];
543 buf[0] = (0x0 << sda_) | (0x1 << scl_);
544 buf[1] = (0x1 << sda_) | (0x1 << scl_);
545 return (Out_(buf, 2));
546 }
547
549 int SendByte_(const int *buf) {
550 int a;
551 int res;
552
553 /*
554 * Send the 8 bits
555 */
556 res = Out_(buf, 8 * 3, txStretching_);
557 if (res != 0)
558 {
559 return (res);
560 }
561
562 /*
563 * Read the acknowledge bit
564 */
565 res = GetAck_(&a);
566 if (res != 0)
567 {
568 return (res);
569 }
570
571 if (a)
572 {
573 /*
574 * Ack is high - we have to stop
575 */
576 res = Stop_();
577 if (res != 0)
578 {
579 return (res);
580 }
581 else
582 {
583 sprintf(ErrMsg(), "no acknowledge from slave-device");
584 return (ngcbI2C_ERR_ACK);
585 }
586 }
587
588 return (0);
589 }
590
592 int RecvByte_(char *byte, int last=0) {
593 int d;
594 int buf[3];
595 int res;
596 int i;
597 int ds = 0;
598
599 if (sdaDirSwitch_ >= 0)
600 {
601 /*
602 * Switch SDA direction
603 */
604 ds = 1 << sdaDirSwitch_;
605 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
606 res = Out_(buf, 1);
607 if (res != 0)
608 {
609 return (res);
610 }
611 }
612
613 *byte = 0;
614 for (i=7;i>=0;i--)
615 {
616 /*
617 * Issue clock pulse
618 */
619 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
620 buf[1] = (0x1 << sda_) | (0x1 << scl_) | ds;
621 res = Out_(buf, 2, rxStretching_);
622 if (res != 0)
623 {
624 return (res);
625 }
626
627 /*
628 * Read data
629 */
630 res = In_(&d);
631 if (res != 0)
632 {
633 return (res);
634 }
635
636 /*
637 * Last edge on clock-line
638 */
639 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
640 res = Out_(buf, 1);
641 if (res != 0)
642 {
643 return (res);
644 }
645
646 /*
647 * Shift data bit to correct position
648 */
649 *byte |= (char)(((d >> sdaIn_) & 0x1) << i);
650 }
651
652 if (sdaDirSwitch_ >= 0)
653 {
654 /*
655 * Switch back SDA direction
656 */
657 buf[0] = (0x1 << sda_) | (0x0 << scl_);
658 res = Out_(buf, 1);
659 if (res != 0)
660 {
661 return (res);
662 }
663 }
664
665 if (!last)
666 {
667 /*
668 * Issue acknowledge (hold data-line low)
669 */
670 buf[0] = (0x0 << sda_) | (0x0 << scl_);
671 buf[1] = (0x0 << sda_) | (0x1 << scl_);
672 buf[2] = (0x0 << sda_) | (0x0 << scl_);
673 }
674 else
675 {
676 /*
677 * Deny acknowledge (release data-line)
678 */
679 buf[0] = (0x1 << sda_) | (0x0 << scl_);
680 buf[1] = (0x1 << sda_) | (0x1 << scl_);
681 buf[2] = (0x1 << sda_) | (0x0 << scl_);
682 }
683 res = Out_(buf, 3, txStretching_);
684 if (res != 0)
685 {
686 return (res);
687 }
688
689 return (0);
690 }
691
693 int GetAck_(int *a) {
694 int buf[2];
695 int res;
696
697 /*
698 * Release data-line and issue clock pulse. Unless the
699 * acknowledge signal is ignored we have to consider
700 * clock-stretching (if enabled)
701 */
702 buf[0] = (0x1 << sda_) | (0x0 << scl_);
703 buf[1] = (0x1 << sda_) | (0x1 << scl_);
704 res = Out_(buf, 2, (!ignoreAck_ && rxStretching_) || txStretching_);
705 if (res != 0)
706 {
707 return (res);
708 }
709
710 if (!ignoreAck_)
711 {
712 if ((sdaDirSwitch_ >= 0) && ((ackIn_ == sdaIn_) || (ackIn_ == sda_)))
713 {
714 /*
715 * Switch SDA direction to read the acknowledge signal
716 */
717 buf[0] = (0x1 << sda_) | (0x1 << scl_) | (1 << sdaDirSwitch_);
718 res = Out_(buf, 1);
719 if (res != 0)
720 {
721 return (res);
722 }
723 }
724
725 /*
726 * Read actual state
727 */
728 res = In_(a, ackIn_);
729 if (res != 0)
730 {
731 return (res);
732 }
733 }
734 else
735 {
736 /*
737 * We assume the acknowledge signal was there
738 */
739 *a = 0;
740 }
741
742 /*
743 * Last edge on clock-line
744 */
745 buf[0] = (0x1 << sda_) | (0x0 << scl_);
746 res = Out_(buf, 1);
747 if (res != 0)
748 {
749 return (res);
750 }
751
752 return (0);
753 }
754
756 int Out_(const int *buf, int size, int doStretching=0) {
757 int i, r;
758
759 for (i=0;i<size;i++)
760 {
761 /*
762 * Send new state
763 */
764 if (OutCB(buf[i], &r, erms_) != 0)
765 {
766 lastClkState_ = -1;
767 return (r);
768 }
769
770 /*
771 * Always save last state (here we use the full word to
772 * have it for whatever purpose)
773 */
774 lastState_ = buf[i];
775
776 if (doStretching && (clkStretchCnt_ > 0))
777 {
778 int thisClkState = (buf[i] >> scl_) & 0x1;
779
780 if ((lastClkState_ == 0) && (thisClkState == 1))
781 {
782 int b = 0;
783 int cnt = 0;
784
785 if (sclDirSwitch_ >= 0)
786 {
787 /*
788 * Switch SCL direction to read the clock-line signal
789 */
790 if (OutCB(lastState_ | (1 << sclDirSwitch_), &r, erms_) != 0)
791 {
792 lastClkState_ = -1;
793 return (r);
794 }
795 }
796
797 /*
798 * Poll for clock high
799 */
800 while (!((b >> sclIn_) & 0x1) && (cnt < clkStretchCnt_))
801 {
802 if (InCB(&b, &r, erms_) != 0)
803 {
804 return (r);
805 }
806
807 cnt++;
808 if (cnt >= clkStretchCnt_)
809 {
810 sprintf(ErrMsg(), "clock line is forced low");
811 return (ngcbI2C_ERR_CLK);
812 }
813
814 // delay (TBD)
815 }
816
817 if (sclDirSwitch_ >= 0)
818 {
819 /*
820 * Switch back SCL direction
821 */
822 if (OutCB(lastState_, &r, erms_) != 0)
823 {
824 lastClkState_ = -1;
825 return (r);
826 }
827 }
828 }
829 }
830
831 /*
832 * Save last clock state
833 */
834 lastClkState_ = (buf[i] >> scl_) & 0x1;
835 }
836
837 return (0);
838 }
839
841 int In_(int *d) {return (In_(d, sdaIn_));}
842
844 int In_(int *d, int line) {
845 int b, r;
846
847 /*
848 * Read actual state
849 */
850 if (InCB(&b, &r, erms_) != 0)
851 {
852 *d = 0;
853 return (r);
854 }
855
856 /*
857 * Get data bit
858 */
859 *d = (b >> line) & 0x1;
860
861 return (0);
862 }
863
865 void Int2Bin_(char *str, int in) {
866 int x = in;
867 int i;
868
869 for (i=0;i<32;i++)
870 {
871 if ((x & 0x00000001) == 1) str[31 - i]='1';
872 else str[31 - i]='0';
873 x = x >> 1;
874 }
875 str[32] = '\0';
876 }
877
878};
879
880
881#endif
ngcbI2C()
Definition ngcbI2C.hpp:43
void AckOff()
Disable acknowledge handling.
Definition ngcbI2C.hpp:90
void AckOn()
Enable acknowledge handling.
Definition ngcbI2C.hpp:87
virtual int OutCB(int d, int *resultCode, char *erms)
Output call-back (1 word)
Definition ngcbI2C.hpp:451
void ClkStretching(int rx, int tx)
Set clock-stretching capabilities.
Definition ngcbI2C.hpp:108
void ClkStretchCnt(int cnt)
Set counter for clock-stretching.
Definition ngcbI2C.hpp:123
char * ErrMsg()
Return error-message buffer.
Definition ngcbI2C.hpp:84
int LastState()
Return last state of SDA and SCL.
Definition ngcbI2C.hpp:444
int Write10(int addr, const char *byte, int n)
10-bit write operation
Definition ngcbI2C.hpp:212
virtual ~ngcbI2C()
Destructor.
Definition ngcbI2C.hpp:81
int Read(int addr, char *byte, int n)
Standard 7-bit read operation.
Definition ngcbI2C.hpp:298
ngcbI2C(int cnt)
Definition ngcbI2C.hpp:50
void SDA_IN(int bit)
Define data-line bit for read (by default ack-line is the same)
Definition ngcbI2C.hpp:96
int Read10(int addr, char *byte, int n)
10-bit read operation
Definition ngcbI2C.hpp:368
void SCL_IN(int bit)
Define clock-line bit fot read (clock-stretching)
Definition ngcbI2C.hpp:93
void ACK_IN(int bit)
Define ack-line bit.
Definition ngcbI2C.hpp:99
ngcbI2C(int scl, int sda, int cnt)
Definition ngcbI2C.hpp:67
void SCL_DIR_SWITCH(int bit)
Define SCL direction switch bit.
Definition ngcbI2C.hpp:105
int ClkStretchCnt()
Return clock-stretching counter.
Definition ngcbI2C.hpp:129
ngcbI2C(int scl, int sda, int sclIn, int sdaIn, int ackIn, int cnt)
Definition ngcbI2C.hpp:73
virtual int InCB(int *d, int *resultCode, char *erms)
Input call-back (1 word)
Definition ngcbI2C.hpp:461
int Write(int addr, const char *byte, int n)
Standard 7-bit write operation.
Definition ngcbI2C.hpp:132
void SDA_DIR_SWITCH(int bit)
Define SDA direction switch bit.
Definition ngcbI2C.hpp:102
ngcbI2C(int scl, int sda)
Definition ngcbI2C.hpp:56
#define ngcbI2C_ERR_CLK
I2C-bus clock line forced low.
Definition ngcbI2C.hpp:29
#define ngcbI2C_ERR_ACK
I2C-bus no acknowledge.
Definition ngcbI2C.hpp:32