1 /*
2 TwoWire.cpp - TWI/I2C library for Wiring & Arduino
3 Copyright (c) 2006 Nicholas Zambetti. All right reserved.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 extern "C" {
21 #include <stdlib.h>
22 #include <string.h>
23 #include <inttypes.h>
24 #include "twi.h"
25 }
26
27 #include "Wire.h"
28
29 // Initialize Class Variables //////////////////////////////////////////////////
30
31 uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
32 uint8_t TwoWire::rxBufferIndex = 0;
33 uint8_t TwoWire::rxBufferLength = 0;
34
35 uint8_t TwoWire::txAddress = 0;
36 uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
37 uint8_t TwoWire::txBufferIndex = 0;
38 uint8_t TwoWire::txBufferLength = 0;
39
40 uint8_t TwoWire::transmitting = 0;
41 void (*TwoWire::user_onRequest)(void);
42 void (*TwoWire::user_onReceive)(int);
43
44 // Constructors ////////////////////////////////////////////////////////////////
45
TwoWire()46 TwoWire::TwoWire()
47 {
48 }
49
50 // Public Methods //////////////////////////////////////////////////////////////
51
begin(void)52 void TwoWire::begin(void)
53 {
54 rxBufferIndex = 0;
55 rxBufferLength = 0;
56
57 txBufferIndex = 0;
58 txBufferLength = 0;
59
60 twi_init();
61 }
62
begin(uint8_t address)63 void TwoWire::begin(uint8_t address)
64 {
65 twi_setAddress(address);
66 twi_attachSlaveTxEvent(onRequestService);
67 twi_attachSlaveRxEvent(onReceiveService);
68 begin();
69 }
70
begin(int address)71 void TwoWire::begin(int address)
72 {
73 begin((uint8_t)address);
74 }
75
requestFrom(uint8_t address,uint8_t quantity)76 uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
77 {
78 // clamp to buffer length
79 if(quantity > BUFFER_LENGTH){
80 quantity = BUFFER_LENGTH;
81 }
82 // perform blocking read into buffer
83 uint8_t read = twi_readFrom(address, rxBuffer, quantity);
84 // set rx buffer iterator vars
85 rxBufferIndex = 0;
86 rxBufferLength = read;
87
88 return read;
89 }
90
requestFrom(int address,int quantity)91 uint8_t TwoWire::requestFrom(int address, int quantity)
92 {
93 return requestFrom((uint8_t)address, (uint8_t)quantity);
94 }
95
beginTransmission(uint8_t address)96 void TwoWire::beginTransmission(uint8_t address)
97 {
98 // indicate that we are transmitting
99 transmitting = 1;
100 // set address of targeted slave
101 txAddress = address;
102 // reset tx buffer iterator vars
103 txBufferIndex = 0;
104 txBufferLength = 0;
105 }
106
beginTransmission(int address)107 void TwoWire::beginTransmission(int address)
108 {
109 beginTransmission((uint8_t)address);
110 }
111
endTransmission(void)112 uint8_t TwoWire::endTransmission(void)
113 {
114 // transmit buffer (blocking)
115 int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
116 // reset tx buffer iterator vars
117 txBufferIndex = 0;
118 txBufferLength = 0;
119 // indicate that we are done transmitting
120 transmitting = 0;
121 return ret;
122 }
123
124 // must be called in:
125 // slave tx event callback
126 // or after beginTransmission(address)
send(uint8_t data)127 void TwoWire::send(uint8_t data)
128 {
129 if(transmitting){
130 // in master transmitter mode
131 // don't bother if buffer is full
132 if(txBufferLength >= BUFFER_LENGTH){
133 return;
134 }
135 // put byte in tx buffer
136 txBuffer[txBufferIndex] = data;
137 ++txBufferIndex;
138 // update amount in buffer
139 txBufferLength = txBufferIndex;
140 }else{
141 // in slave send mode
142 // reply to master
143 twi_transmit(&data, 1);
144 }
145 }
146
147 // must be called in:
148 // slave tx event callback
149 // or after beginTransmission(address)
send(uint8_t * data,uint8_t quantity)150 void TwoWire::send(uint8_t* data, uint8_t quantity)
151 {
152 if(transmitting){
153 // in master transmitter mode
154 for(uint8_t i = 0; i < quantity; ++i){
155 send(data[i]);
156 }
157 }else{
158 // in slave send mode
159 // reply to master
160 twi_transmit(data, quantity);
161 }
162 }
163
164 // must be called in:
165 // slave tx event callback
166 // or after beginTransmission(address)
send(char * data)167 void TwoWire::send(char* data)
168 {
169 send((uint8_t*)data, strlen(data));
170 }
171
172 // must be called in:
173 // slave tx event callback
174 // or after beginTransmission(address)
send(int data)175 void TwoWire::send(int data)
176 {
177 send((uint8_t)data);
178 }
179
180 // must be called in:
181 // slave rx event callback
182 // or after requestFrom(address, numBytes)
available(void)183 uint8_t TwoWire::available(void)
184 {
185 return rxBufferLength - rxBufferIndex;
186 }
187
188 // must be called in:
189 // slave rx event callback
190 // or after requestFrom(address, numBytes)
receive(void)191 uint8_t TwoWire::receive(void)
192 {
193 // default to returning null char
194 // for people using with char strings
195 uint8_t value = '\0';
196
197 // get each successive byte on each call
198 if(rxBufferIndex < rxBufferLength){
199 value = rxBuffer[rxBufferIndex];
200 ++rxBufferIndex;
201 }
202
203 return value;
204 }
205
206 // behind the scenes function that is called when data is received
onReceiveService(uint8_t * inBytes,int numBytes)207 void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
208 {
209 // don't bother if user hasn't registered a callback
210 if(!user_onReceive){
211 return;
212 }
213 // don't bother if rx buffer is in use by a master requestFrom() op
214 // i know this drops data, but it allows for slight stupidity
215 // meaning, they may not have read all the master requestFrom() data yet
216 if(rxBufferIndex < rxBufferLength){
217 return;
218 }
219 // copy twi rx buffer into local read buffer
220 // this enables new reads to happen in parallel
221 for(uint8_t i = 0; i < numBytes; ++i){
222 rxBuffer[i] = inBytes[i];
223 }
224 // set rx iterator vars
225 rxBufferIndex = 0;
226 rxBufferLength = numBytes;
227 // alert user program
228 user_onReceive(numBytes);
229 }
230
231 // behind the scenes function that is called when data is requested
onRequestService(void)232 void TwoWire::onRequestService(void)
233 {
234 // don't bother if user hasn't registered a callback
235 if(!user_onRequest){
236 return;
237 }
238 // reset tx buffer iterator vars
239 // !!! this will kill any pending pre-master sendTo() activity
240 txBufferIndex = 0;
241 txBufferLength = 0;
242 // alert user program
243 user_onRequest();
244 }
245
246 // sets function called on slave write
onReceive(void (* function)(int))247 void TwoWire::onReceive( void (*function)(int) )
248 {
249 user_onReceive = function;
250 }
251
252 // sets function called on slave read
onRequest(void (* function)(void))253 void TwoWire::onRequest( void (*function)(void) )
254 {
255 user_onRequest = function;
256 }
257
258 // Preinstantiate Objects //////////////////////////////////////////////////////
259
260 TwoWire Wire = TwoWire();
261
262