1 using NewLife;
2 using NewLife.Log;
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Threading;
9 using System.Threading.Tasks;
10
11 namespace Linux
12 {
13 /// <summary>GPIO 组</summary>
14 public enum PinGroup : int
15 {
16 PA = 0,
17 PB = 1,
18 PC = 2,
19 PD = 3,
20 PE = 4,
21 PG = 5,
22 PH = 6,
23 PI = 7,
24 PJ = 6,
25 }
26
27 /// <summary>引脚输入输出模式</summary>
28 public enum PinDir
29 {
30 In = 0,
31 Out = 1,
32 }
33
34 /// <summary>简单实现 GPIO 的读写,不包含中断处理</summary>
35 public class SimpleGpio : DisposeBase
36 {
37 /// <summary> 保证 结尾有/ 的路径</summary>
38 private static String _GpioBasePath = @"/sys/class/gpio/";
39
40 /// <summary>GPIO 的目录</summary>
41 public static String GpioBasePath
42 {
43 get { return _GpioBasePath; }
44 set
45 {
46 if (value == null) return;
47 if (value == "") return;
48
49 _GpioBasePath = value;
50
51 if (!_GpioBasePath.EndsWith("/")) _GpioBasePath += "/";
52 }
53 }
54
55 /// <summary>方向</summary>
56 public PinDir Dir;
57
58 /// <summary>状态</summary>
59 public Boolean Opened { get; private set; } = false;
60
61 /// <summary>名称</summary>
62 public String Name { get; set; }
63
64
65 /// <summary>引脚编号</summary>
66 private int _PinIdx = -1;
67
68 /// <summary>引脚路径</summary>
69 private String pinPath;
70
71
72 #region 构造
73
74 public SimpleGpio() { }
75
76 /// <summary></summary>
77 /// <param name="gp">gpio 组</param>
78 /// <param name="gpidx">组内编号</param>
79 public SimpleGpio(PinGroup gp, int gpidx)
80 {
81 _PinIdx = (int)gp * 32 + gpidx;
82
83 Name = "gpio" + _PinIdx;
84 }
85
86 /// <summary></summary>
87 /// <param name="idx">全局gpio index</param>
88 public SimpleGpio(int idx)
89 {
90 _PinIdx = idx;
91
92 Name = "gpio" + _PinIdx;
93 }
94
95 /// <summary>析构</summary>
96 protected override void OnDispose(bool disposing)
97 {
98 base.OnDispose(disposing);
99
100 UnexportPin();
101 }
102
103 #endregion
104
105 #region 基础操作
106
107 /// <summary></summary>
108 /// <param name="idx">全局gpio index</param>
109 public void SetPin(int idx)
110 {
111 _PinIdx = idx;
112
113 Name = "gpio" + _PinIdx;
114 }
115
116 /// <summary> </summary>
117 /// <param name="gp">gpio 组</param>
118 /// <param name="gpidx">组内编号</param>
119 /// <param name="dir">输入/输出</param>
120 public void SetPin(PinGroup gp, int gpidx, PinDir dir = PinDir.In)
121 {
122 _PinIdx = (int)gp * 32 + gpidx;
123 Dir = dir;
124
125 Name = "gpio" + _PinIdx;
126 }
127
128
129 /// <summary>打开</summary>
130 /// <returns></returns>
131 public Boolean Open()
132 {
133 pinPath = GpioBasePath + Name + "/";
134 XTrace.WriteLine("打开 " + pinPath);
135
136 if (!pinPath.AsDirectory().Exists)
137 {
138 try
139 {
140 if (!ExportPin()) return false;
141 }
142 catch
143 {
144 XTrace.WriteLine(pinPath + "导出引脚出错,请 检查参数 和 权限");
145 return false;
146 }
147 }
148
149 // 写入配置
150 var dir = new FileInfo(pinPath + "direction");
151 if (!dir.Exists) { XTrace.WriteLine("direction 文件呢?"); return false; }
152
153 var str = Dir == PinDir.Out ? "out\n" : "in\n";
154 dir.WriteBytes(str.GetBytes());
155
156 Opened = true;
157 return true;
158 }
159
160 /// <summary>关闭</summary>
161 public void Close()
162 {
163 UnexportPin();
164
165 Opened = false;
166 }
167
168 /// <summary>写引脚状态</summary>
169 /// <param name="value"></param>
170 public void Write(bool value)
171 {
172 if (!Opened) return;
173
174 if (Dir == PinDir.In) return;
175
176 var fi = new FileInfo(pinPath + "value");
177 if (!fi.Exists) { XTrace.WriteLine("value 文件呢?"); return; }
178
179 if (value)
180 fi.WriteBytes("1\n".GetBytes());
181 else
182 fi.WriteBytes("0\n".GetBytes());
183 }
184
185 /// <summary>读取状态</summary>
186 /// <returns></returns>
187 public bool Read()
188 {
189 if (!Opened) return false;
190
191 var fi = new FileInfo(pinPath + "value");
192 if (!fi.Exists) { XTrace.WriteLine("value 文件呢?"); return false; }
193
194 var v = fi.ReadBytes(0, 1);
195 if (v == null) return false;
196 if (v.Length == 0) return false;
197 if (v[0] == '0') return false;
198
199 return true;
200 }
201
202 #endregion
203
204 #region 辅助
205 /// <summary>导出引脚</summary>
206 /// <returns></returns>
207 public bool ExportPin()
208 {
209 if (!GpioBasePath.AsDirectory().Exists)
210 {
211 XTrace.WriteLine("基础目录 {0} 不存在", GpioBasePath);
212 return false;
213 }
214
215 var export = new FileInfo(GpioBasePath + "export");
216 if (!export.Exists)
217 {
218 XTrace.WriteLine("export 文件不存在,请确认gpio目录是否正确");
219 return false;
220 }
221
222 var param = _PinIdx + "\n";
223 export.WriteBytes(param.GetBytes());
224 Thread.Sleep(100);
225
226 if (!pinPath.AsDirectory().Exists)
227 {
228 XTrace.WriteLine("导出失败,请确认 Pin 是否正确");
229 return false;
230 }
231
232 // XTrace.WriteLine("导出 {0},成功", Name);
233 return true;
234 }
235
236 /// <summary>取消导出引脚</summary>
237 public void UnexportPin()
238 {
239 var unexport = new FileInfo(GpioBasePath + "unexport");
240 if (!unexport.Exists)
241 {
242 XTrace.WriteLine("unexport 文件不存在,请确认gpio目录是否正确");
243 return;
244 }
245
246 var param = _PinIdx + "\n";
247 unexport.WriteBytes(param.GetBytes());
248 }
249 #endregion
250 }
251 }