1////////////////////////////////////////////////////////////////////////////////
2// //
3// This software is supplied under the terms of a license agreement or //
4// nondisclosure agreement with Mitov Software and may not be copied //
5// or disclosed except in accordance with the terms of that agreement. //
6// Copyright(c) 2002-2016 Mitov Software. All Rights Reserved. //
7// //
8////////////////////////////////////////////////////////////////////////////////
9
10#ifndef _MITOV_MICROCHIP_MCP23017_h
11#define _MITOV_MICROCHIP_MCP23017_h
12
13#include <Mitov.h>
14#include <Mitov_Basic_GPIO.h>
15
16namespace Mitov
17{
18//---------------------------------------------------------------------------
19 class Microchip_MCP23017 : public Mitov::BasicGPIO<OpenWire::Component>
20 {
21 typedef Mitov::BasicGPIO<OpenWire::Component> inherited;
22
23 public:
24 byte Address = 0;
25
26 public:
27 enum TRegisterIndex { riDirection, riPullUp, riInvert, riValue };
28
29 protected:
30 uint16_t FRegValues[ 4 ][ 2 ];
31 uint16_t FReadRegisterMap = 0;
32 uint16_t FReadBits = 0;
33
34
35 protected:
36 void BeginTransmissionAt( byte ARegister )
37 {
38 byte AAddress = 0b0100000 | ( Address & 0b111 );
39
40 Wire.beginTransmission( AAddress );
41
42 Wire.write( ARegister );
43 }
44
45 void WriteAt( byte ARegister, uint16_t AData )
46 {
47// Serial.print( "WriteAt: " ); Serial.print( ARegister ); Serial.print( " " ); Serial.println( AData );
48 BeginTransmissionAt( ARegister );
49
50 Wire.write( (byte *)&AData, 2 );
51
52 Wire.endTransmission();
53 }
54
55 void StartReadFrom( byte ARegister, int ALength )
56 {
57 BeginTransmissionAt( ARegister );
58 Wire.endTransmission();
59 Wire.requestFrom( 0b0100000 | ( Address & 0b111 ), ALength );
60 while( Wire.available() < ALength );
61 }
62
63 void UpdateAll()
64 {
65 const byte CPorts[] =
66 {
67 0x00, // IODIR register
68 0x02, // IPOL register
69 0x0C, // GPPU register
70 0x14 // OLAT register
71 };
72
73 for( int i = 0; i < 4; ++i )
74 if( FRegValues[ i ][ 0 ] != FRegValues[ i ][ 1 ] )
75 {
76 WriteAt( CPorts[ i ], FRegValues[ i ][ 0 ] );
77 FRegValues[ i ][ 1 ] = FRegValues[ i ][ 0 ];
78 }
79
80/*
81 // Read the port
82 BeginTransmissionAt( 0x12 ); // GPIO register
83 Wire.endTransmission();
84
85 Wire.requestFrom( 0b0100000 | ( Address & 0b111 ), 2 );
86 uint16_t AValue;
87 ((byte *)&AValue )[ 0 ] = Wire.read();
88 ((byte *)&AValue )[ 1 ] = Wire.read();
89
90 for( int i = 0; i < FChannels.size(); ++i )
91 FChannels[ i ]->UpdateOutput( AValue & ( 1 << i ) != 0 );
92*/
93 }
94
95 virtual void PerformRead()
96 {
97 if( ! FReadRegisterMap )
98 return;
99
100// Serial.println( FReadRegisterMap );
101
102 if( FReadRegisterMap & 0x0F )
103 {
104 if( FReadRegisterMap & 0xF0 )
105 {
106 StartReadFrom( 0x12, 2 ); // GPIO register
107 ((byte *)&FReadBits )[ 0 ] = Wire.read();
108 ((byte *)&FReadBits )[ 1 ] = Wire.read();
109 }
110
111 else
112 {
113 StartReadFrom( 0x12, 1 ); // GPIO register
114 ((byte *)&FReadBits )[ 0 ] = Wire.read();
115 ((byte *)&FReadBits )[ 1 ] = 0;
116
117// Serial.print( "FReadBits: " ); Serial.println( FReadBits );
118 }
119 }
120 else
121 {
122 // Read the port
123 StartReadFrom( 0x13, 1 ); // GPIO register
124 ((byte *)&FReadBits )[ 0 ] = 0;
125 ((byte *)&FReadBits )[ 1 ] = Wire.read();
126 }
127
128 for( int i = 0; i < FChannels.size(); ++i )
129 FChannels[ i ]->UpdateInput();
130
131 }
132
133 public:
134 bool GetBitValue( uint32_t AIndex )
135 {
136 return( ( FReadBits & ( ((uint32_t)1 ) << AIndex )) != 0 );
137 }
138
139 public:
140 void SetChannelValue( int AIndex, bool AValue )
141 {
142 SetChannelRegisterValue( AIndex, Microchip_MCP23017::riValue, AValue );
143 }
144
145 protected:
146 virtual void SystemStart()
147 {
148 inherited::SystemStart();
149
150 for( int i = 0; i < 4; ++i )
151 FRegValues[ i ][ 1 ] = ~FRegValues[ i ][ 0 ];
152
153 UpdateAll();
154
155 for( int i = 0; i < FChannels.size(); ++i )
156 FChannels[ i ]->SendOutput();
157 }
158
159 virtual void SystemLoopUpdateHardware()
160 {
161 UpdateAll();
162 inherited::SystemLoopUpdateHardware();
163 }
164
165 public:
166 void SetChannelRegisterValue( int AIndex, int ARegisterIndex, bool AValue )
167 {
168 FRegValues[ ARegisterIndex ][ 0 ] &= ~( ((uint16_t) 0b1 ) << AIndex );
169 FRegValues[ ARegisterIndex ][ 0 ] |= ( (uint16_t)( AValue & 1 ) ) << AIndex;
170
171 if( ARegisterIndex == Microchip_MCP23017::riDirection )
172 {
173 if( AValue )
174 FReadRegisterMap |= ((uint16_t) 1) << AIndex;
175
176 else
177 FReadRegisterMap &= ~( ((uint16_t) 1) << AIndex );
178 }
179 }
180
181 public:
182 Microchip_MCP23017()
183 {
184 for( int i = 0; i < 4; ++i )
185 FRegValues[ i ][ 0 ] = 0;
186 }
187
188 };
189//---------------------------------------------------------------------------
190 class Microchip_MCP23017_Channel : public OwnedBasicGPIOChannel<Microchip_MCP23017>
191 {
192 typedef OwnedBasicGPIOChannel<Microchip_MCP23017> inherited;
193
194 public:
195 void SetIsInverted( bool AValue )
196 {
197 if( FIsInverted == AValue )
198 return;
199
200 FIsInverted = AValue;
201 PinDirectionsInit();
202 }
203
204 protected:
205 bool FIsInverted;
206
207 public:
208 virtual void UpdateInput()
209 {
210 UpdateOutput( FOwner.GetBitValue( FIndex ));
211 }
212
213 protected:
214 virtual void PinDirectionsInit()
215 {
216 FOwner.SetChannelRegisterValue( FIndex, Microchip_MCP23017::riDirection, ! FIsOutput );
217 FOwner.SetChannelRegisterValue( FIndex, Microchip_MCP23017::riPullUp, FIsPullUp );
218 FOwner.SetChannelRegisterValue( FIndex, Microchip_MCP23017::riInvert, FIsInverted );
219 }
220
221 public:
222 Microchip_MCP23017_Channel( Microchip_MCP23017 &AOwner, int AIndex, bool AInitialValue, bool AIsOutput, bool AIsPullUp, bool AIsCombinedInOut, bool AIsInverted ) :
223 inherited( AOwner, AIndex, AInitialValue, AIsOutput, AIsPullUp, AIsCombinedInOut ),
224 FIsInverted( AIsInverted )
225 {
226 PinDirectionsInit();
227 }
228
229 };
230//---------------------------------------------------------------------------
231}
232
233#endif