Merge remote-tracking branch 'origin/master' into tizen
[platform/core/csapi/tizenfx.git] / internals / src / Tizen.Peripheral / Tizen.Peripheral / Gpio.cs
1 /*
2 * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 using System;
18 using Tizen.Internals.Errors;
19 using NativeGpio = Interop.Peripheral.Gpio;
20
21 namespace Tizen.Peripheral.Gpio
22 {
23     /// <summary>
24     /// Enumeration of GPIO direction options.
25     /// </summary>
26     public enum GpioPinDriveMode
27     {
28         /// <summary>
29         /// Input Mode.
30         /// </summary>
31         Input,
32
33         /// <summary>
34         /// Output mode with high value.
35         /// </summary>
36         OutputInitiallyLow,
37
38         /// <summary>
39         /// Output mode with low value.
40         /// </summary>
41         OutputInitiallyHigh,
42     }
43
44     /// <summary>
45     /// Enumeration of GPIO values.
46     /// </summary>
47     public enum GpioPinValue
48     {
49         /// <summary>
50         /// Low value.
51         /// </summary>
52         Low = 0,
53
54         /// <summary>
55         /// High value.
56         /// </summary>
57         High
58     }
59
60     /// <summary>
61     /// Enumeration of edge types for the GPIO interrupt.
62     /// </summary>
63     public enum GpioChangePolarity
64     {
65         /// <summary>
66         /// No interrupt on GPIO.
67         /// </summary>
68         None = 0,
69
70         /// <summary>
71         /// Interrupt on rising only.
72         /// </summary>
73         Rising,
74
75         /// <summary>
76         /// Interrupt on falling only.
77         /// </summary>
78         Falling,
79
80         /// <summary>
81         /// Interrupt on rising and falling.
82         /// </summary>
83         Both
84     }
85
86     /// <summary>
87     /// The class allows applications to use the platform Digital Pins as Input/Output.
88     /// </summary>
89     /// <privilege>http://tizen.org/privilege/peripheralio</privilege>
90     public class Gpio : IDisposable
91     {
92
93         private GpioChangePolarity _polarityType;
94         private NativeGpio.InterruptedEventCallback _interruptedEventCallback;
95
96         /// <summary>
97         /// Native handle to Gpio.
98         /// </summary>
99         private IntPtr _handle;
100         private bool _disposed = false;
101
102         /// <summary>
103         /// Invoked when Gpio pin was interrupted.
104         /// </summary>
105         public event EventHandler<PinUpdatedEventArgs> ValueChanged;
106
107         /// <summary>
108         /// Opens a GPIO pin.
109         /// </summary>
110         /// <param name="pinNumber">The GPIO pin number.</param>
111         /// <param name="mode">GPIO direction.</param>
112         public Gpio(int pinNumber, GpioPinDriveMode mode)
113         {
114             var ret = NativeGpio.Open(pinNumber, out IntPtr handle);
115             if (ret != ErrorCode.None)
116                 throw ExceptionFactory.CreateException(ret);
117
118             _handle = handle;
119             PinNumber = pinNumber;
120             try
121             {
122                 switch (mode)
123                 {
124                     case GpioPinDriveMode.Input:
125                         ret = NativeGpio.SetEdgeMode(handle, NativeGpio.EdgeType.Both);
126                         if (ret != ErrorCode.None)
127                             throw ExceptionFactory.CreateException(ret);
128
129                         ret = NativeGpio.SetDirection(handle, NativeGpio.Direction.In);
130                         if (ret != ErrorCode.None)
131                             throw ExceptionFactory.CreateException(ret);
132                         SetIntteruptedCallback();
133                         break;
134                     case GpioPinDriveMode.OutputInitiallyLow:
135                         ret = NativeGpio.SetDirection(handle, NativeGpio.Direction.OutLow);
136                         if (ret != ErrorCode.None)
137                             throw ExceptionFactory.CreateException(ret);
138                         break;
139                     case GpioPinDriveMode.OutputInitiallyHigh:
140                         ret = NativeGpio.SetDirection(handle, NativeGpio.Direction.OutHigh);
141                         if (ret != ErrorCode.None)
142                             throw ExceptionFactory.CreateException(ret);
143                         break;
144                 }
145             } catch(Exception e) {
146                 Dispose();
147                 throw;
148             }
149         }
150
151
152         /// <summary>
153         /// Closes the GPIO pin.
154         /// </summary>
155         ~Gpio()
156         {
157             Dispose(false);
158         }
159
160         private void SetIntteruptedCallback()
161         {
162             _interruptedEventCallback = OnInterrupted;
163             var ret = NativeGpio.SetInterruptedCb(_handle, _interruptedEventCallback, IntPtr.Zero);
164             if (ret != ErrorCode.None)
165             {
166                 throw ExceptionFactory.CreateException(ret);
167             }
168         }
169
170         private void OnInterrupted(IntPtr handle, ErrorCode error, IntPtr data)
171         {
172             ValueChanged?.Invoke(this, new PinUpdatedEventArgs(PinNumber, Read()));
173         }
174
175         /// <summary>
176         /// Closes a GPIO pin.
177         /// </summary>
178         public void Close() => Dispose();
179
180         /// <summary>
181         /// Disposes GPIO.
182         /// </summary>
183         public void Dispose()
184         {
185             Dispose(true);
186             GC.SuppressFinalize(this);
187         }
188
189         /// <summary>
190         /// Disposes GPIO.
191         /// </summary>
192         protected virtual void Dispose(bool disposing)
193         {
194             if (_disposed)
195             {
196                 return;
197             }
198
199             NativeGpio.UnsetInterruptedCb(_handle);
200             NativeGpio.Close(_handle);
201             _disposed = true;
202         }
203
204         /// <summary>
205         /// GPIO pin number.
206         /// </summary>
207         public int PinNumber { get; }
208
209         /// <summary>
210         /// Gets pin value.
211         /// </summary>
212         /// <returns>Pin value</returns>
213         public GpioPinValue Read()
214         {
215             var ret = NativeGpio.Read(_handle, out uint value);
216             if (ret != ErrorCode.None)
217                 throw ExceptionFactory.CreateException(ret);
218
219             return value == 1 ? GpioPinValue.High : GpioPinValue.Low;
220         }
221
222         /// <summary>
223         /// Sets pin value.
224         /// </summary>
225         public void Write(GpioPinValue value)
226         {
227             var ret = NativeGpio.Write(_handle, value == GpioPinValue.High ? 1 : (uint)0);
228             if (ret != ErrorCode.None)
229                 throw ExceptionFactory.CreateException(ret);
230         }
231
232         /// <summary>
233         /// Sets or gets the GPIO edge mode.
234         /// </summary>
235         /// <remarks>Get value is initialized after successful Set call.</remarks>
236         public GpioChangePolarity Polarity
237         {
238             get => _polarityType;
239             set
240             {
241                 var ret = NativeGpio.SetEdgeMode(_handle, (NativeGpio.EdgeType)value);
242                 if (ret != ErrorCode.None)
243                     throw ExceptionFactory.CreateException(ret);
244
245                 _polarityType = value;
246             }
247         }
248     }
249 }