YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
soft_i2c_slave_states.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14// This class is used by the soft_i2c_slave driver.
15// It implements all necessary states for the state
16// machine, which processes the SDA and SCL line
17// changes. The state pattern (GoF) is used!
18
19#include "soft_i2c_slave_states.h"
20#include "soft_i2c_slave.h"
21
22namespace I2C {
23
25// STATE base //
27void STATE::start() {
28 _context.setState(&_context._read_addr);
29}
30void STATE::stop() {
31 _context.setState(&_context._idle);
32 _context._stop();
33}
34
36// State IDLE //
38void IDLE::enter() {
39 // Make sure we do not touch the bus...
40 _context._sda.gpioWrite(HIGH);
41 _context._scl.gpioWrite(HIGH);
42}
43
45// State READ_ADDR //
47void READ_ADDR::enter() {
48 _data = 0;
49 _bit_mask = 0x80;
50 _context._byte_index = 0;
51}
52void READ_ADDR::high() {
53 _data |= _bit_mask;
54 _bit_mask >>= 1;
55}
56void READ_ADDR::low() {
57 _bit_mask >>= 1;
58}
59void READ_ADDR::scl_falling() {
60 if (!_bit_mask) {
61 // process device address
62 _context._send = _data & 0x01;
63 _data >>= 1;
64 _context._ack = (_data == _context._i2c_address);
65 // Write the ACK to master
66 _context.setState(&_context._write_ack);
67 }
68}
69
71// State WRITE_ACK //
73void WRITE_ACK::enter() {
74 _context._sda.gpioDisableIrq();
75 _context._sda.gpioWrite(!_context._ack);
76 _context._sda.gpioEnableIrq();
77 return;
78}
79void WRITE_ACK::scl_falling() {
80 // release SDA line (in case of ACK!)
81 _context._sda.gpioWrite(HIGH);
82 // Do not clear SDA interrupts here !
83 if (_context._ack) {
84 if (_context._send) {
85 _context.setState(&_context._write_data );
86 } else {
87 _context.setState(&_context._read_data );
88 }
89 } else {
90 _context.setState(&_context._idle);
91 }
92}
93
95// State READ_DATA //
97void READ_DATA::enter() {
98 _data = 0;
99 _bit_mask = 0x80;
100}
101void READ_DATA::high() {
102 _data |= _bit_mask;
103 _bit_mask >>= 1;
104}
105void READ_DATA::low() {
106 _bit_mask >>= 1;
107}
108void READ_DATA::scl_falling() {
109 if (!_bit_mask) {
110 _context._ack = _context._receive(_context._byte_index++, _data);
111 _context.setState(&_context._write_ack);
112 }
113}
114
116// State WRITE_DATA //
118void WRITE_DATA::enter() {
119 // We are controlling the SDA line now, so no interrupts
120 _context._sda.gpioDisableIrq();
121 // Read in the byte to send
122 _data = _context._transmit(_context._byte_index++);
123 // send first bit
124 _bit_mask = 0x80;
125 _context._sda.gpioWrite(_data & _bit_mask);
126 _bit_mask >>= 1;
127}
128void WRITE_DATA::scl_falling() {
129 if (_bit_mask) {
130 // send next bit
131 _context._sda.gpioWrite(_data & _bit_mask);
132 _bit_mask >>= 1;
133 } else {
134 // release SDA line
135 _context._sda.gpioWrite(HIGH);
136 _context._sda.gpioEnableIrq();
137 _context.setState(&_context._read_ack);
138 }
139}
140
142// State READ_ACK //
144void READ_ACK::high() {
145 _context._ack = false;
146}
147void READ_ACK::low() {
148 _context._ack = true;
149}
150void READ_ACK::scl_falling() {
151 if (_context._ack) {
152 _context.setState(&_context._write_data);
153 } else {
154 _context.setState(&_context._idle);
155 }
156}
157
158} // namespace