├── .github
└── workflows
│ └── develop-ci.yml
├── .gitignore
├── Contributing.md
├── Design
├── Enclosure
│ ├── STLs_For_Printing
│ │ ├── PL_D-Pad_2.stl
│ │ ├── PL_Enclosure_Bottom.stl
│ │ ├── PL_Enclosure_Bottom_w_DIN_Mount.stl
│ │ └── PL_Enclosure_Top.stl
│ └── Source
│ │ ├── PLv3 Enclosure w DIN Mounts.f3z
│ │ └── PLv3 Enclosure.f3z
├── meadow-projectlab.jpg
├── project-lab-samples.png
├── project-lab-specs.jpg
├── project-lab-v3-enclosure.jpg
├── projectlab-pcb.jpg
├── projectlab-pinout-v1.jpg
├── projectlab-pinout-v2.jpg
├── projectlab-pinout-v3.jpg
└── projectlab-store.jpg
├── Hardware
├── v1.e
│ └── Schematic_v1.e.pdf
├── v2.e
│ ├── BOM_v2.e.csv
│ ├── Gerbers_v2.e.zip
│ └── Schematic_v2.e.pdf
├── v3.d
│ └── Schematic.pdf
├── v3.e
│ ├── BOM.csv
│ ├── EasyEDA_Source.json
│ └── Schematic.pdf
├── v4.a
│ └── Schematic_v4a.pdf
└── v4.b
│ └── Schematic_v4b.pdf
├── LICENSE
├── README.md
└── Source
├── Directory.Packages.props
├── Meadow.ProjectLab.sln
├── Meadow.ProjectLab
├── ConnectorProviderV3.cs
├── ConnectorProviderV3e.cs
├── Constants.cs
├── DisplayConnector.cs
├── IConnectorProvider.cs
├── IOTerminalConnector.cs
├── IProjectLabHardware.cs
├── Meadow.ProjectLab.csproj
├── ProjectLab.cs
├── ProjectLabHardwareBase.cs
├── ProjectLabHardwareV1.cs
├── ProjectLabHardwareV2.cs
├── ProjectLabHardwareV3.cs
├── ProjectLabHardwareV4.cs
├── ProjectLabModbusRtuClient.cs
└── icon.png
└── ProjectLab_Demo
├── .vscode
└── launch.config
├── DisplayController.cs
├── MeadowApp.cs
├── ProjectLab_Demo.csproj
├── app.build.yaml
└── app.config.yaml
/.github/workflows/develop-ci.yml:
--------------------------------------------------------------------------------
1 | name: Develop Build
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | branches: [ develop ]
7 | push:
8 | branches: [ develop ]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: windows-latest
14 |
15 | steps:
16 | - name: Checkout Meadow.Logging
17 | uses: actions/checkout@v4
18 | with:
19 | repository: WildernessLabs/Meadow.Logging
20 | path: Meadow.Logging
21 | ref: develop
22 |
23 | - name: Checkout Meadow.Units
24 | uses: actions/checkout@v4
25 | with:
26 | repository: WildernessLabs/Meadow.Units
27 | path: Meadow.Units
28 | ref: develop
29 |
30 | - name: Checkout Meadow.Contracts
31 | uses: actions/checkout@v4
32 | with:
33 | repository: WildernessLabs/Meadow.Contracts
34 | path: Meadow.Contracts
35 | ref: develop
36 |
37 | - name: Checkout Meadow.Core
38 | uses: actions/checkout@v4
39 | with:
40 | repository: WildernessLabs/Meadow.Core
41 | path: Meadow.Core
42 | ref: develop
43 |
44 | - name: Checkout MQTTnet
45 | uses: actions/checkout@v4
46 | with:
47 | repository: WildernessLabs/MQTTnet
48 | path: MQTTnet
49 | ref: develop
50 |
51 | - name: Checkout Meadow.Modbus
52 | uses: actions/checkout@v4
53 | with:
54 | repository: WildernessLabs/Meadow.Modbus
55 | path: Meadow.Modbus
56 | ref: develop
57 |
58 | - name: Checkout Meadow.Foundation
59 | uses: actions/checkout@v4
60 | with:
61 | repository: WildernessLabs/Meadow.Foundation
62 | path: Meadow.Foundation
63 | ref: develop
64 |
65 | - name: Checkout Meadow.ProjectLab
66 | uses: actions/checkout@v4
67 | with:
68 | path: Meadow.ProjectLab
69 |
70 | - name: Setup .NET SDK
71 | uses: actions/setup-dotnet@v1
72 | with:
73 | dotnet-version:
74 | 8.0.x
75 |
76 | - name: Build Meadow.ProjectLab
77 | run: dotnet build -c Release Meadow.ProjectLab/Source/Meadow.ProjectLab.sln
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | **/.idea/
399 | *.sln.iml
400 |
401 | # BeatPulse healthcheck temp database
402 | healthchecksdb
403 |
404 | # MacOS Stuff
405 | .DS_Store
406 | *.DS_Store
407 | **/.DS_Store
408 |
--------------------------------------------------------------------------------
/Contributing.md:
--------------------------------------------------------------------------------
1 | # Contribute to Meadow.ProjectLab
2 |
3 | **Meadow.ProjectLab** is an open-source project by [Wilderness Labs](https://www.wildernesslabs.co/) and we encourage community feedback and contributions.
4 |
5 | ## How to Contribute
6 |
7 | - **Found a bug?** [Report an issue](https://github.com/WildernessLabs/Meadow_Issues/issues)
8 | - Have a **feature idea or driver request?** [Open a new feature request](https://github.com/WildernessLabs/Meadow_Issues/issues)
9 | - Want to **contribute code?** Fork the [Meadow.ProjectLab](https://github.com/WildernessLabs/Meadow.ProjectLab) repository and submit a pull request against the `develop` branch
10 |
11 | ## Pull Requests
12 |
13 | 1. All PRs should target the `develop` branch on the Meadow.ProjectLab repository.
14 | 2. All new public or protected classes, methods, and properties need XML comment documentation.
15 | 3. Please try to follow the existing coding patterns and practices.
16 |
17 | ## Pull Request Steps
18 |
19 | 1. Fork the repository
20 | 2. Clone your fork locally: `git clone https://github.com/WildernessLabs/Meadow.ProjectLab`
21 | 3. Switch to the `develop` branch
22 | 4. Create a new branch: `git checkout -b feature/your-contribution`
23 | 5. Make your changes and commit: `git commit -m 'Added/Updated [feature/fix]`
24 | 6. Push to your fork: `git push origin feature/your-contribution`
25 | 7. Open a pull request at [Meadow.ProjectLab/pulls](https://github.com/WildernessLabs/Meadow.ProjectLab/pulls) targetting the `develop` branch
26 | ## Need Help?
27 |
28 | If you have questions or need assistance, please join the Wilderness Labs [community on Slack](http://slackinvite.wildernesslabs.co/).
29 |
--------------------------------------------------------------------------------
/Design/Enclosure/STLs_For_Printing/PL_D-Pad_2.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/STLs_For_Printing/PL_D-Pad_2.stl
--------------------------------------------------------------------------------
/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Bottom.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Bottom.stl
--------------------------------------------------------------------------------
/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Bottom_w_DIN_Mount.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Bottom_w_DIN_Mount.stl
--------------------------------------------------------------------------------
/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Top.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/STLs_For_Printing/PL_Enclosure_Top.stl
--------------------------------------------------------------------------------
/Design/Enclosure/Source/PLv3 Enclosure w DIN Mounts.f3z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/Source/PLv3 Enclosure w DIN Mounts.f3z
--------------------------------------------------------------------------------
/Design/Enclosure/Source/PLv3 Enclosure.f3z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/Enclosure/Source/PLv3 Enclosure.f3z
--------------------------------------------------------------------------------
/Design/meadow-projectlab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/meadow-projectlab.jpg
--------------------------------------------------------------------------------
/Design/project-lab-samples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/project-lab-samples.png
--------------------------------------------------------------------------------
/Design/project-lab-specs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/project-lab-specs.jpg
--------------------------------------------------------------------------------
/Design/project-lab-v3-enclosure.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/project-lab-v3-enclosure.jpg
--------------------------------------------------------------------------------
/Design/projectlab-pcb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/projectlab-pcb.jpg
--------------------------------------------------------------------------------
/Design/projectlab-pinout-v1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/projectlab-pinout-v1.jpg
--------------------------------------------------------------------------------
/Design/projectlab-pinout-v2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/projectlab-pinout-v2.jpg
--------------------------------------------------------------------------------
/Design/projectlab-pinout-v3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/projectlab-pinout-v3.jpg
--------------------------------------------------------------------------------
/Design/projectlab-store.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Design/projectlab-store.jpg
--------------------------------------------------------------------------------
/Hardware/v1.e/Schematic_v1.e.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v1.e/Schematic_v1.e.pdf
--------------------------------------------------------------------------------
/Hardware/v2.e/BOM_v2.e.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v2.e/BOM_v2.e.csv
--------------------------------------------------------------------------------
/Hardware/v2.e/Gerbers_v2.e.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v2.e/Gerbers_v2.e.zip
--------------------------------------------------------------------------------
/Hardware/v2.e/Schematic_v2.e.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v2.e/Schematic_v2.e.pdf
--------------------------------------------------------------------------------
/Hardware/v3.d/Schematic.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v3.d/Schematic.pdf
--------------------------------------------------------------------------------
/Hardware/v3.e/BOM.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v3.e/BOM.csv
--------------------------------------------------------------------------------
/Hardware/v3.e/Schematic.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v3.e/Schematic.pdf
--------------------------------------------------------------------------------
/Hardware/v4.a/Schematic_v4a.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v4.a/Schematic_v4a.pdf
--------------------------------------------------------------------------------
/Hardware/v4.b/Schematic_v4b.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Hardware/v4.b/Schematic_v4b.pdf
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Meadow.ProjectLab
4 |
5 | Project Lab is the most functional IoT prototyping platform on the planet. No more breadboards, complicated wiring, or soldering. Project Lab was built from the ground up using the industry's most powerful, capable, and reliable sensors, components, and connectors.
6 |
7 | ## Contents
8 | * [Purchasing or Building](#purchasing-or-building)
9 | * [Getting Started](#getting-started)
10 | * [Hardware Specifications](#hardware-specifications)
11 | * [Pinout Diagram](#pinout-diagram)
12 | * [Project Lab v3.e](#project-lab-v3e)
13 | * [Project Lab v2.e](#project-lab-v2e)
14 | * [Project Lab v1.e](#project-lab-v1e)
15 | * [Industrial Enclosure Design](#industrial-enclosure-design)
16 | * [Additional Samples](#additional-samples)
17 | * [Support](#support)
18 |
19 | ## Purchasing or Building
20 |
21 |
22 |
23 |
24 |
25 | |
26 |
27 |
28 | |
29 |
30 |
31 |
32 | You can get a Project Lab fully assembled from the Wilderness Labs store.
33 | |
34 |
35 | It's also designed so that it can be assembled at home for the adventurous. All design files can be found in the Hardware Design folder.
36 | |
37 |
38 |
39 |
40 | ## Getting Started
41 |
42 | To make using the hardware even simpler, we've created a Nuget package that instantiates and encapsulates the onboard hardware into a `ProjectLab` class.
43 |
44 | 1. Add the ProjectLab Nuget package your project:
45 | - `dotnet add package Meadow.ProjectLab`, or
46 | - [Meadow.ProjectLab Nuget Package](https://www.nuget.org/packages/Meadow.ProjectLab)
47 | - [Explore in Fuget.org](https://www.fuget.org/packages/Meadow.ProjectLab/0.1.0/lib/netstandard2.1/ProjectLab.dll/Meadow.Devices/ProjectLab)
48 |
49 | 2. Instantiate the `ProjectLab` class:
50 | ```csharp
51 | public class MeadowApp : App
52 | {
53 | IProjectLabHardware projLab;
54 |
55 | public override Task Initialize()
56 | {
57 | projLab = ProjectLab.Create();
58 | ...
59 | ```
60 |
61 | 3. To Access the `Project Lab` onboard peripherals:
62 | ```csharp
63 | if (projLab.EnvironmentalSensor is { } bme688)
64 | {
65 | bme688.Updated += Bme688Updated;
66 | bme688.StartUpdating(TimeSpan.FromSeconds(5));
67 | }
68 | ```
69 |
70 | 4. To use an I2C peripheral (with a [Grove Character display](https://wiki.seeedstudio.com/Grove-16x2_LCD_Series) as an example):
71 | ```csharp
72 | var display = new CharacterDisplay
73 | (
74 | i2cBus: projLab.I2cBus,
75 | address: (byte)I2cCharacterDisplay.Addresses.Grove,
76 | rows: 2, columns: 16,
77 | isGroveDisplay: true
78 | );
79 | ```
80 |
81 | ## Hardware Specifications
82 |
83 |
84 |
85 |
86 |
87 | Onboard Peripherals |
88 | Connectivity |
89 |
90 |
91 | ILI9341 - SPI 320x240 color display |
92 | MikroBUS - Two sets of MikroBUS pin headers |
93 |
94 |
95 | BMI270 - I2C motion and acceleration sensor |
96 | Qwiic - Stemma QT I2C connector |
97 |
98 |
99 | BH1750 - I2C light sensor |
100 | Grove - Analog header |
101 |
102 |
103 | BME688 - I2C atmospheric sensor |
104 | Grove - GPIO/serial header |
105 |
106 |
107 | Push Button - 4 momentary buttons |
108 | RS-485 - Serial |
109 |
110 |
111 | Magnetic Audio Transducer - High quality piezo speaker |
112 | Ports - 3.3V, 5V, ground, one analog and two GPIO ports |
113 |
114 |
115 |
116 | You can find the schematics and other design files in the [Hardware folder](/Hardware).
117 |
118 | ## Pinout Diagram
119 |
120 | Check the diagrams below to see what pins on the Meadow are connected to every peripheral on board and its connectors:
121 |
122 |
123 | ### Project Lab v3.e
124 |
125 |
126 |
127 | ### Project Lab v2.e
128 |
129 |
130 |
131 | ### Project Lab v1.e
132 |
133 |
134 |
135 | ## Industrial Enclosure Design
136 |
137 | The enclosure was designed in Autodesk Fusion 360. The source file can be found and STL files can be found [here](Design/Enclosure/STLs_For_Printing/).
138 |
139 |
140 |
141 | ## Additional Samples
142 |
143 | 1. **[Setup your Meadow Build Environment](http://developer.wildernesslabs.co/Meadow/Getting_Started/Deploying_Meadow/)** - If you haven't deployed a Meadow app before, you'll need to setup your IDE extension(s), deploy Meadow.OS, etc.
144 | 2. **[Run the Demo App](Source/ProjectLab_Demo)** - Deploy the Project Lab demonstration app to see the built in peripherals at work.
145 | 3. **[Check out the Project Lab Samples](https://github.com/WildernessLabs/Meadow.ProjectLab.Samples)** - We recommend cloning the [Meadow.ProjectLab.Samples](https://github.com/WildernessLabs/Meadow.ProjectLab.Samples) repo. There you'll find a bunch of awesome samples that you can run right out-of-the box!
146 |
147 |
148 |
149 |
150 | ## Support
151 |
152 | Having trouble building/running these projects?
153 | * File an [issue](https://github.com/WildernessLabs/Meadow.Desktop.Samples/issues) with a repro case to investigate, and/or
154 | * Join our [public Slack](http://slackinvite.wildernesslabs.co/), where we have an awesome community helping, sharing and building amazing things using Meadow.
--------------------------------------------------------------------------------
/Source/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.ProjectLab", "Meadow.ProjectLab\Meadow.ProjectLab.csproj", "{A263ECD8-AA98-4E1C-B404-EC360584362B}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectLab_Demo", "ProjectLab_Demo\ProjectLab_Demo.csproj", "{C9A1FF4C-7210-4EA6-874E-44BE198B2790}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_External", "_External", "{580CAC8F-38C5-4DEA-AAEA-415F5D08982B}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Foundation.Core", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Core\Meadow.Foundation.Core.csproj", "{37AAB07A-1F40-4660-97A5-D24890ED7F27}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Contracts", "..\..\Meadow.Contracts\Source\Meadow.Contracts\Meadow.Contracts.csproj", "{5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Displays.TftSpi", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Displays.TftSpi\Driver\Displays.TftSpi.csproj", "{2ECCF2AC-44A7-436E-A832-E2A370C3317D}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.IOExpanders.Mcp23xxx", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\ICs.IOExpanders.Mcp23xxx\Driver\ICs.IOExpanders.Mcp23xxx.csproj", "{FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}"
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Atmospheric.Bme68x", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Sensors.Atmospheric.Bme68x\Driver\Sensors.Atmospheric.Bme68x.csproj", "{F0217A3C-41FC-49A0-8481-64853464D5AB}"
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Light.Bh1750", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Sensors.Light.Bh1750\Driver\Sensors.Light.Bh1750.csproj", "{CD675B1D-BC88-4DB5-AF45-8079435F52CA}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Motion.Bmi270", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Sensors.Motion.Bmi270\Driver\Sensors.Motion.Bmi270.csproj", "{95770BEF-6864-493C-A8DA-660D3AC582A0}"
25 | EndProject
26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics.MicroGraphics", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Libraries_and_Frameworks\Graphics.MicroGraphics\Driver\Graphics.MicroGraphics.csproj", "{DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}"
27 | EndProject
28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Modbus", "..\..\Meadow.Modbus\src\Meadow.Modbus\Meadow.Modbus.csproj", "{2D1FC26C-C80D-42E8-92BD-25BE517AC663}"
29 | EndProject
30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Core", "..\..\Meadow.Core\Source\Meadow.Core\Meadow.Core.csproj", "{18EE7297-3E8D-4B94-B6E3-319991927D58}"
31 | EndProject
32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Logging", "..\..\Meadow.Logging\Source\Meadow.Logging\lib\Meadow.Logging.csproj", "{E56BD47C-4997-4831-833C-EA35C83F89B7}"
33 | EndProject
34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Units", "..\..\Meadow.Units\Source\Meadow.Units\Meadow.Units.csproj", "{35B3DDB4-71EF-4A68-B242-982C71126F3E}"
35 | EndProject
36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.F7", "..\..\Meadow.Core\Source\implementations\f7\Meadow.F7\Meadow.F7.csproj", "{EF2050F4-6422-4AB2-BF60-9E5428E474AF}"
37 | EndProject
38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Audio.MicroAudio", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Libraries_and_Frameworks\Audio.MicroAudio\Driver\Audio.MicroAudio.csproj", "{12C58A2F-9D0E-417F-B138-BA25B166C56B}"
39 | EndProject
40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "..\..\MQTTnet\Source\MQTTnet\MQTTnet.csproj", "{B51B10FB-6577-4C06-B7B2-82D2ACCB31B2}"
41 | EndProject
42 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICs.IOExpanders.Sc16is7x2", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\ICs.IOExpanders.Sc16is7x2\Driver\ICs.IOExpanders.Sc16is7x2.csproj", "{20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}"
43 | EndProject
44 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Hid.Xpt2046", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Sensors.Hid.Xpt2046\Driver\Sensors.Hid.Xpt2046.csproj", "{6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}"
45 | EndProject
46 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics.MicroLayout", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Libraries_and_Frameworks\Graphics.MicroLayout\Driver\Graphics.MicroLayout.csproj", "{04A557DE-8136-4AE9-88F0-159D4AB085B8}"
47 | EndProject
48 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serialization.MicroJson", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Libraries_and_Frameworks\Serialization.MicroJson\Driver\Serialization.MicroJson.csproj", "{888F0CDA-2D29-49F2-AF31-898998B3D8F4}"
49 | EndProject
50 | Global
51 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
52 | Debug|Any CPU = Debug|Any CPU
53 | Release|Any CPU = Release|Any CPU
54 | EndGlobalSection
55 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
56 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
59 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {A263ECD8-AA98-4E1C-B404-EC360584362B}.Release|Any CPU.Deploy.0 = Release|Any CPU
62 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
65 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Release|Any CPU.ActiveCfg = Debug|Any CPU
66 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Release|Any CPU.Build.0 = Debug|Any CPU
67 | {C9A1FF4C-7210-4EA6-874E-44BE198B2790}.Release|Any CPU.Deploy.0 = Debug|Any CPU
68 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
71 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Release|Any CPU.ActiveCfg = Release|Any CPU
72 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Release|Any CPU.Build.0 = Release|Any CPU
73 | {37AAB07A-1F40-4660-97A5-D24890ED7F27}.Release|Any CPU.Deploy.0 = Release|Any CPU
74 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
77 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
78 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Release|Any CPU.Build.0 = Release|Any CPU
79 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0}.Release|Any CPU.Deploy.0 = Release|Any CPU
80 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
81 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Debug|Any CPU.Build.0 = Debug|Any CPU
82 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
83 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Release|Any CPU.ActiveCfg = Release|Any CPU
84 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Release|Any CPU.Build.0 = Release|Any CPU
85 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D}.Release|Any CPU.Deploy.0 = Release|Any CPU
86 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
87 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Debug|Any CPU.Build.0 = Debug|Any CPU
88 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
89 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Release|Any CPU.ActiveCfg = Release|Any CPU
90 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Release|Any CPU.Build.0 = Release|Any CPU
91 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048}.Release|Any CPU.Deploy.0 = Release|Any CPU
92 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
93 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
94 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
95 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
96 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Release|Any CPU.Build.0 = Release|Any CPU
97 | {F0217A3C-41FC-49A0-8481-64853464D5AB}.Release|Any CPU.Deploy.0 = Release|Any CPU
98 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
99 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
100 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
101 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
102 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Release|Any CPU.Build.0 = Release|Any CPU
103 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA}.Release|Any CPU.Deploy.0 = Release|Any CPU
104 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
105 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
106 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
107 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
108 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Release|Any CPU.Build.0 = Release|Any CPU
109 | {95770BEF-6864-493C-A8DA-660D3AC582A0}.Release|Any CPU.Deploy.0 = Release|Any CPU
110 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
111 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
112 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
113 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
114 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Release|Any CPU.Build.0 = Release|Any CPU
115 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3}.Release|Any CPU.Deploy.0 = Release|Any CPU
116 | {2D1FC26C-C80D-42E8-92BD-25BE517AC663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
117 | {2D1FC26C-C80D-42E8-92BD-25BE517AC663}.Debug|Any CPU.Build.0 = Debug|Any CPU
118 | {2D1FC26C-C80D-42E8-92BD-25BE517AC663}.Release|Any CPU.ActiveCfg = Release|Any CPU
119 | {2D1FC26C-C80D-42E8-92BD-25BE517AC663}.Release|Any CPU.Build.0 = Release|Any CPU
120 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
121 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Debug|Any CPU.Build.0 = Debug|Any CPU
122 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
123 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Release|Any CPU.ActiveCfg = Release|Any CPU
124 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Release|Any CPU.Build.0 = Release|Any CPU
125 | {18EE7297-3E8D-4B94-B6E3-319991927D58}.Release|Any CPU.Deploy.0 = Release|Any CPU
126 | {E56BD47C-4997-4831-833C-EA35C83F89B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
127 | {E56BD47C-4997-4831-833C-EA35C83F89B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
128 | {E56BD47C-4997-4831-833C-EA35C83F89B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
129 | {E56BD47C-4997-4831-833C-EA35C83F89B7}.Release|Any CPU.Build.0 = Release|Any CPU
130 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
131 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
132 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
133 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
134 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Release|Any CPU.Build.0 = Release|Any CPU
135 | {35B3DDB4-71EF-4A68-B242-982C71126F3E}.Release|Any CPU.Deploy.0 = Release|Any CPU
136 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
137 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
138 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
139 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
140 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Release|Any CPU.Build.0 = Release|Any CPU
141 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF}.Release|Any CPU.Deploy.0 = Release|Any CPU
142 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
143 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Debug|Any CPU.Build.0 = Debug|Any CPU
144 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
145 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Release|Any CPU.ActiveCfg = Release|Any CPU
146 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Release|Any CPU.Build.0 = Release|Any CPU
147 | {12C58A2F-9D0E-417F-B138-BA25B166C56B}.Release|Any CPU.Deploy.0 = Release|Any CPU
148 | {B51B10FB-6577-4C06-B7B2-82D2ACCB31B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
149 | {B51B10FB-6577-4C06-B7B2-82D2ACCB31B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
150 | {B51B10FB-6577-4C06-B7B2-82D2ACCB31B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
151 | {B51B10FB-6577-4C06-B7B2-82D2ACCB31B2}.Release|Any CPU.Build.0 = Release|Any CPU
152 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
153 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Debug|Any CPU.Build.0 = Debug|Any CPU
154 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
155 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Release|Any CPU.ActiveCfg = Release|Any CPU
156 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Release|Any CPU.Build.0 = Release|Any CPU
157 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C}.Release|Any CPU.Deploy.0 = Release|Any CPU
158 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
159 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
160 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
161 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
162 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Release|Any CPU.Build.0 = Release|Any CPU
163 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2}.Release|Any CPU.Deploy.0 = Release|Any CPU
164 | {04A557DE-8136-4AE9-88F0-159D4AB085B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
165 | {04A557DE-8136-4AE9-88F0-159D4AB085B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
166 | {04A557DE-8136-4AE9-88F0-159D4AB085B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
167 | {04A557DE-8136-4AE9-88F0-159D4AB085B8}.Release|Any CPU.Build.0 = Release|Any CPU
168 | {888F0CDA-2D29-49F2-AF31-898998B3D8F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
169 | {888F0CDA-2D29-49F2-AF31-898998B3D8F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
170 | {888F0CDA-2D29-49F2-AF31-898998B3D8F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
171 | {888F0CDA-2D29-49F2-AF31-898998B3D8F4}.Release|Any CPU.Build.0 = Release|Any CPU
172 | EndGlobalSection
173 | GlobalSection(SolutionProperties) = preSolution
174 | HideSolutionNode = FALSE
175 | EndGlobalSection
176 | GlobalSection(NestedProjects) = preSolution
177 | {37AAB07A-1F40-4660-97A5-D24890ED7F27} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
178 | {5FA51D52-0F2C-460A-B0E7-3168A11A1CF0} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
179 | {2ECCF2AC-44A7-436E-A832-E2A370C3317D} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
180 | {FD0FF1E2-C933-4CFD-84A3-6F4F72C7F048} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
181 | {F0217A3C-41FC-49A0-8481-64853464D5AB} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
182 | {CD675B1D-BC88-4DB5-AF45-8079435F52CA} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
183 | {95770BEF-6864-493C-A8DA-660D3AC582A0} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
184 | {DB4C8FC0-18A8-4735-933B-D1FCE59FC1E3} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
185 | {2D1FC26C-C80D-42E8-92BD-25BE517AC663} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
186 | {18EE7297-3E8D-4B94-B6E3-319991927D58} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
187 | {E56BD47C-4997-4831-833C-EA35C83F89B7} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
188 | {35B3DDB4-71EF-4A68-B242-982C71126F3E} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
189 | {EF2050F4-6422-4AB2-BF60-9E5428E474AF} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
190 | {12C58A2F-9D0E-417F-B138-BA25B166C56B} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
191 | {B51B10FB-6577-4C06-B7B2-82D2ACCB31B2} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
192 | {20AFC6E4-46E9-4CBB-A8E2-69BF4CD2039C} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
193 | {6089ABC8-BCBB-4B81-BC6A-D6B4963E5BD2} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
194 | {04A557DE-8136-4AE9-88F0-159D4AB085B8} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
195 | {888F0CDA-2D29-49F2-AF31-898998B3D8F4} = {580CAC8F-38C5-4DEA-AAEA-415F5D08982B}
196 | EndGlobalSection
197 | GlobalSection(ExtensibilityGlobals) = postSolution
198 | SolutionGuid = {C1A24E3C-F7F9-4EB3-8A7F-5C6AB7C2A43D}
199 | EndGlobalSection
200 | EndGlobal
201 |
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ConnectorProviderV3.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.ICs.IOExpanders;
2 | using Meadow.Hardware;
3 | using Meadow.Modbus;
4 | using System;
5 |
6 | namespace Meadow.Devices;
7 |
8 | internal class ConnectorProviderV3 : IConnectorProvider
9 | {
10 | public ModbusRtuClient GetModbusRtuClient(ProjectLabHardwareBase projLab, int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
11 | {
12 | if (Resolver.Device is F7CoreComputeV2)
13 | {
14 | throw new PlatformNotSupportedException("RS485 is not supported on hardware revisions before 3.e");
15 | }
16 |
17 | throw new NotSupportedException();
18 | }
19 |
20 | public MikroBusConnector CreateMikroBus1(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2)
21 | {
22 | return new MikroBusConnector(
23 | "MikroBus1",
24 | new PinMapping
25 | {
26 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, device.Pins.PA3),
27 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, device.Pins.PH10),
28 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, device.Pins.PB12),
29 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, device.Pins.SPI5_SCK),
30 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, device.Pins.SPI5_CIPO),
31 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, device.Pins.SPI5_COPI),
32 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, device.Pins.PB8),
33 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, device.Pins.PC2),
34 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, device.Pins.PB15),
35 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, device.Pins.PB14),
36 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, device.Pins.I2C3_SCL),
37 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, device.Pins.I2C3_SDA),
38 | },
39 | device.PlatformOS.GetSerialPortName("com1")!,
40 | new I2cBusMapping(device, 3),
41 | new SpiBusMapping(device, device.Pins.SPI5_SCK, device.Pins.SPI5_COPI, device.Pins.SPI5_CIPO)
42 | );
43 | }
44 |
45 | public MikroBusConnector CreateMikroBus2(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2)
46 | {
47 | return new MikroBusConnector(
48 | "MikroBus2",
49 | new PinMapping
50 | {
51 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, device.Pins.PB0),
52 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, mcp2.Pins.GP1),
53 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, mcp2.Pins.GP2),
54 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, device.Pins.SCK),
55 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, device.Pins.CIPO),
56 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, device.Pins.COPI),
57 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, device.Pins.PB9),
58 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, mcp2.Pins.GP3),
59 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, device.Pins.PB15),
60 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, device.Pins.PB14),
61 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, device.Pins.I2C1_SCL),
62 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, device.Pins.I2C1_SDA),
63 | },
64 | device.PlatformOS.GetSerialPortName("com1")!,
65 | new I2cBusMapping(device, 1),
66 | new SpiBusMapping(device, device.Pins.SPI5_SCK, device.Pins.SPI5_COPI, device.Pins.SPI5_CIPO)
67 | );
68 | }
69 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ConnectorProviderV3e.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.ICs.IOExpanders;
2 | using Meadow.Hardware;
3 | using Meadow.Modbus;
4 | using Meadow.Units;
5 | using System;
6 |
7 | namespace Meadow.Devices;
8 |
9 | internal class ConnectorProviderV3e : IConnectorProvider
10 | {
11 | private readonly Sc16is752? _uartExpander;
12 | private object _mobusSyncRoot = new();
13 | private ModbusRtuClient? _client;
14 |
15 | public ConnectorProviderV3e(ProjectLabHardwareBase projLab, II2cBus i2CBus)
16 | {
17 | try
18 | {
19 | _uartExpander = new Sc16is752(i2CBus, new Frequency(1.8432, Frequency.UnitType.Megahertz), Sc16is7x2.Addresses.Address_0x4D);
20 | }
21 | catch (Exception ex)
22 | {
23 | Resolver.Log.Error($"Unable to connect to UART expander: {ex.Message}", Constants.LogGroup);
24 | }
25 | }
26 |
27 | public ModbusRtuClient GetModbusRtuClient(ProjectLabHardwareBase projLab, int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
28 | {
29 | if (Resolver.Device is not F7CoreComputeV2) throw new NotSupportedException();
30 |
31 | lock (_mobusSyncRoot)
32 | {
33 | if (_uartExpander == null)
34 | {
35 | throw new Exception("No UART expander available");
36 | }
37 |
38 | if (_client == null)
39 | {
40 | try
41 | {
42 | Resolver.Log.Info($"Creating 485 port...", Constants.LogGroup);
43 | // v3.e+ uses an SC16is I2C UART expander for the RS485
44 | var port = _uartExpander.PortB.CreateRs485SerialPort(baudRate, dataBits, parity, stopBits, false);
45 | Resolver.Log.Trace($"485 port created", Constants.LogGroup);
46 | _client = new ModbusRtuClient(port);
47 | }
48 | catch (Exception ex)
49 | {
50 | Resolver.Log.Warn($"Error creating 485 port: {ex.Message}", Constants.LogGroup);
51 | throw new Exception("Unable to connect to UART expander");
52 | }
53 | }
54 | }
55 |
56 | return _client;
57 | }
58 |
59 | public MikroBusConnector CreateMikroBus1(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2)
60 | {
61 | // todo: verify 3.e and later
62 | return new MikroBusConnector(
63 | "MikroBus1",
64 | new PinMapping
65 | {
66 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, device.Pins.PA3),
67 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, device.Pins.PH10),
68 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, device.Pins.PB12),
69 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, device.Pins.SPI5_SCK),
70 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, device.Pins.SPI5_CIPO),
71 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, device.Pins.SPI5_COPI),
72 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, device.Pins.PB8),
73 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, device.Pins.PC2),
74 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, device.Pins.PB15),
75 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, device.Pins.PB14),
76 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, device.Pins.I2C3_SCL),
77 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, device.Pins.I2C3_SDA),
78 | },
79 | device.PlatformOS.GetSerialPortName("com1")!,
80 | new I2cBusMapping(device, 3),
81 | new SpiBusMapping(device, device.Pins.SPI5_SCK, device.Pins.SPI5_COPI, device.Pins.SPI5_CIPO)
82 | );
83 | }
84 |
85 | public MikroBusConnector CreateMikroBus2(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2)
86 | {
87 | return new MikroBusConnector(
88 | "MikroBus2",
89 | new PinMapping
90 | {
91 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, device.Pins.PB0),
92 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, mcp2.Pins.GP1),
93 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, mcp2.Pins.GP2),
94 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, device.Pins.SCK),
95 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, device.Pins.CIPO),
96 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, device.Pins.COPI),
97 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, device.Pins.PB9),
98 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, mcp2.Pins.GP3),
99 | // new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, uart1rx), // on the I2C uart and not usable for anything else
100 | // new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, uart1tx), // on the I2C uart and not usable for anything else
101 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, device.Pins.I2C1_SCL),
102 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, device.Pins.I2C1_SDA),
103 | },
104 | _uartExpander.PortA,
105 | new I2cBusMapping(device, 1),
106 | new SpiBusMapping(device, device.Pins.SCK, device.Pins.COPI, device.Pins.CIPO)
107 | );
108 | }
109 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Meadow.Devices;
2 |
3 | internal static class Constants
4 | {
5 | public const string LogGroup = "proj_lab";
6 | }
7 |
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/DisplayConnector.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Units;
2 | using System;
3 | using static Meadow.Hardware.DisplayConnector;
4 |
5 | namespace Meadow.Hardware;
6 |
7 | ///
8 | /// Represents the display connector on Project Lab
9 | ///
10 | public class DisplayConnector : Connector
11 | {
12 | ///
13 | /// The set of Display connector connector pins
14 | ///
15 | public static class PinNames
16 | {
17 | ///
18 | /// Display Chip Select pin
19 | ///
20 | public const string DISPLAY_CS = "DISPLAY_CS";
21 | ///
22 | /// Display Reset pin
23 | ///
24 | public const string DISPLAY_RST = "DISPLAY_RST";
25 | ///
26 | /// Display Data/Command pin
27 | ///
28 | public const string DISPLAY_DC = "DISPLAY_DC";
29 | ///
30 | /// Display SPI Clock pin
31 | ///
32 | public const string DISPLAY_CLK = "DISPLAY_CLK";
33 | ///
34 | /// Display SPI controller out, peripheral in pin
35 | ///
36 | public const string DISPLAY_COPI = "DISPLAY_COPI";
37 | ///
38 | /// Display LED (backlight) pin
39 | ///
40 | public const string DISPLAY_LED = "DISPLAY_LED";
41 | ///
42 | /// Touch screen interrupt pin
43 | ///
44 | public const string TOUCH_INT = "TOUCH_INT";
45 | ///
46 | /// Touch Chip Select pin
47 | ///
48 | public const string TOUCH_CS = "TOUCH_CS";
49 | ///
50 | /// Touch SPI Clock pin
51 | ///
52 | public const string TOUCH_CLK = "TOUCH_CLK";
53 | ///
54 | /// Touch SPI controller out, peripheral in pin
55 | ///
56 | public const string TOUCH_COPI = "TOUCH_COPI";
57 | ///
58 | /// Touch SPI controller in, peripheral out pin
59 | ///
60 | public const string TOUCH_CIPO = "TOUCH_CIPO";
61 | }
62 |
63 | ///
64 | /// Represents the pins definitions for the Display connector on Project Lab
65 | ///
66 | public class DisplayConnectorPinDefinitions : PinDefinitionBase
67 | {
68 | private readonly IPin? _csDisplay;
69 | private readonly IPin? _rstDisplay;
70 | private readonly IPin? _dcDisplay;
71 | private readonly IPin? _clkDisplay;
72 | private readonly IPin? _copiDisplay;
73 | private readonly IPin? _ledDisplay;
74 | private readonly IPin? _intTouch;
75 | private readonly IPin? _csTouch;
76 | private readonly IPin? _clkTouch;
77 | private readonly IPin? _copiTouch;
78 | private readonly IPin? _cipoTouch;
79 |
80 | ///
81 | /// Display Chip Select pin
82 | ///
83 | public IPin DISPLAY_CS => _csDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
84 | ///
85 | /// Display Reset pin
86 | ///
87 | public IPin DISPLAY_RST => _rstDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
88 | ///
89 | /// Display Data/Command pin
90 | ///
91 | public IPin DISPLAY_DC => _dcDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
92 | ///
93 | /// Display SPI Clock pin
94 | ///
95 | public IPin DISPLAY_CLK => _clkDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
96 | ///
97 | /// Display SPI controller out, peripheral in pin
98 | ///
99 | public IPin DISPLAY_COPI => _copiDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
100 | ///
101 | /// Display LED (backlight) pin
102 | ///
103 | public IPin DISPLAY_LED => _ledDisplay ?? throw new PlatformNotSupportedException("Pin not connected");
104 | ///
105 | /// Touch interrupt pin
106 | ///
107 | public IPin TOUCH_INT => _intTouch ?? throw new PlatformNotSupportedException("Pin not connected");
108 | ///
109 | /// Touch chip select pin
110 | ///
111 | public IPin TOUCH_CS => _csTouch ?? throw new PlatformNotSupportedException("Pin not connected");
112 | ///
113 | /// Touch SPI Clock pin
114 | ///
115 | public IPin TOUCH_CLK => _clkTouch ?? throw new PlatformNotSupportedException("Pin not connected");
116 | ///
117 | /// Touch SPI controller out, peripheral in pin
118 | ///
119 | public IPin TOUCH_COPI => _copiTouch ?? throw new PlatformNotSupportedException("Pin not connected");
120 | ///
121 | /// Touch SPI controller in, peripheral out pin
122 | ///
123 | public IPin TOUCH_CIPO => _cipoTouch ?? throw new PlatformNotSupportedException("Pin not connected");
124 |
125 | internal DisplayConnectorPinDefinitions(PinMapping mapping)
126 | {
127 | foreach (var m in mapping)
128 | {
129 | switch (m.PinName)
130 | {
131 | case PinNames.DISPLAY_CS:
132 | _csDisplay = m.ConnectsTo;
133 | break;
134 | case PinNames.DISPLAY_RST:
135 | _rstDisplay = m.ConnectsTo;
136 | break;
137 | case PinNames.DISPLAY_DC:
138 | _dcDisplay = m.ConnectsTo;
139 | break;
140 | case PinNames.DISPLAY_CLK:
141 | _clkDisplay = m.ConnectsTo;
142 | break;
143 | case PinNames.DISPLAY_COPI:
144 | _copiDisplay = m.ConnectsTo;
145 | break;
146 | case PinNames.DISPLAY_LED:
147 | _ledDisplay = m.ConnectsTo;
148 | break;
149 | case PinNames.TOUCH_INT:
150 | _intTouch = m.ConnectsTo;
151 | break;
152 | case PinNames.TOUCH_CS:
153 | _csTouch = m.ConnectsTo;
154 | break;
155 | case PinNames.TOUCH_CLK:
156 | _clkTouch = m.ConnectsTo;
157 | break;
158 | case PinNames.TOUCH_COPI:
159 | _copiTouch = m.ConnectsTo;
160 | break;
161 | case PinNames.TOUCH_CIPO:
162 | _cipoTouch = m.ConnectsTo;
163 | break;
164 | }
165 | }
166 | }
167 | }
168 |
169 | private readonly SpiBusMapping _spiBusMappingDisplay;
170 | private readonly SpiBusMapping? _spiBusMappingTouch;
171 | private ISpiBus? _spiDisplay;
172 | private readonly ISpiBus? _spiTouch;
173 |
174 | /// The connector name
175 | /// The mappings to the host controller
176 | /// The mapping for the display connector's SPI bus
177 | /// The mapping for the touch connector's SPI bus
178 | public DisplayConnector(string name, PinMapping mapping, SpiBusMapping spiBusMappingDisplay, SpiBusMapping? spiBusMappingTouch = null)
179 | : base(name, new DisplayConnectorPinDefinitions(mapping))
180 | {
181 | _spiBusMappingDisplay = spiBusMappingDisplay;
182 | _spiBusMappingTouch = spiBusMappingTouch;
183 | }
184 |
185 | ///
186 | /// Gets the display SPI bus
187 | ///
188 | public ISpiBus SpiBusDisplay
189 | => _spiDisplay ??= _spiBusMappingDisplay.Controller.CreateSpiBus(_spiBusMappingDisplay.Clock, _spiBusMappingDisplay.Copi, _spiBusMappingDisplay.Cipo, new Frequency(1, Frequency.UnitType.Megahertz));
190 |
191 | ///
192 | /// Gets the touch screen SPI bus
193 | ///
194 | public ISpiBus? SpiBusTouch
195 | {
196 | get
197 | {
198 | if (_spiBusMappingTouch == null || _spiTouch == null)
199 | {
200 | return null;
201 | }
202 | return _spiBusMappingTouch.Controller.CreateSpiBus(_spiBusMappingTouch.Clock, _spiBusMappingTouch.Copi, _spiBusMappingTouch.Cipo, new Frequency(1, Frequency.UnitType.Megahertz));
203 | }
204 | }
205 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/IConnectorProvider.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.ICs.IOExpanders;
2 | using Meadow.Hardware;
3 | using Meadow.Modbus;
4 |
5 | namespace Meadow.Devices;
6 |
7 | internal interface IConnectorProvider
8 | {
9 | ModbusRtuClient GetModbusRtuClient(ProjectLabHardwareBase projLab, int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One);
10 | MikroBusConnector CreateMikroBus1(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2);
11 | MikroBusConnector CreateMikroBus2(IF7CoreComputeMeadowDevice device, Mcp23008 mcp2);
12 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/IOTerminalConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using static Meadow.Hardware.IOTerminalConnector;
3 |
4 | namespace Meadow.Hardware;
5 |
6 | ///
7 | /// Represents the IO Terminal connector on Project Lab
8 | ///
9 | public class IOTerminalConnector : Connector
10 | {
11 | ///
12 | /// The set of IO terminal connector connector pins
13 | ///
14 | public static class PinNames
15 | {
16 | ///
17 | /// Pin A1
18 | ///
19 | public const string A1 = "A1";
20 | ///
21 | /// Pin D2
22 | ///
23 | public const string D2 = "D2";
24 | ///
25 | /// Pin D3
26 | ///
27 | public const string D3 = "D3";
28 | }
29 |
30 | ///
31 | /// Represents the pins definitions for the IO Terminal connector on Project Lab
32 | ///
33 | public class IOTerminalConnectorPinDefinitions : PinDefinitionBase
34 | {
35 | private readonly IPin? _a1;
36 | private readonly IPin? _d2;
37 | private readonly IPin? _d3;
38 |
39 | ///
40 | /// Pin A1
41 | ///
42 | public IPin A1 => _a1 ?? throw new PlatformNotSupportedException("Pin not connected");
43 | ///
44 | /// Pin D2
45 | ///
46 | public IPin D2 => _d2 ?? throw new PlatformNotSupportedException("Pin not connected");
47 | ///
48 | /// Pin D3
49 | ///
50 | public IPin D3 => _d3 ?? throw new PlatformNotSupportedException("Pin not connected");
51 |
52 | internal IOTerminalConnectorPinDefinitions(PinMapping mapping)
53 | {
54 | foreach (var m in mapping)
55 | {
56 | switch (m.PinName)
57 | {
58 | case PinNames.A1:
59 | _a1 = m.ConnectsTo;
60 | break;
61 | case PinNames.D2:
62 | _d2 = m.ConnectsTo;
63 | break;
64 | case PinNames.D3:
65 | _d3 = m.ConnectsTo;
66 | break;
67 | }
68 | }
69 | }
70 | }
71 |
72 | /// The connector name
73 | /// The mappings to the host controller
74 | public IOTerminalConnector(string name, PinMapping mapping)
75 | : base(name, new IOTerminalConnectorPinDefinitions(mapping))
76 | {
77 | }
78 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/IProjectLabHardware.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Hardware;
2 | using Meadow.Modbus;
3 | using Meadow.Peripherals.Displays;
4 | using Meadow.Peripherals.Leds;
5 | using Meadow.Peripherals.Sensors;
6 | using Meadow.Peripherals.Sensors.Atmospheric;
7 | using Meadow.Peripherals.Sensors.Buttons;
8 | using Meadow.Peripherals.Sensors.Environmental;
9 | using Meadow.Peripherals.Sensors.Light;
10 | using Meadow.Peripherals.Sensors.Motion;
11 | using Meadow.Peripherals.Speakers;
12 |
13 | namespace Meadow.Devices;
14 |
15 | ///
16 | /// Interface for ProjectLab hardware
17 | ///
18 | public interface IProjectLabHardware : IMeadowAppEmbeddedHardware
19 | {
20 | ///
21 | /// Gets the up button on the Project Lab board.
22 | ///
23 | public IButton? UpButton { get; }
24 |
25 | ///
26 | /// Gets the down button on the Project Lab board.
27 | ///
28 | public IButton? DownButton { get; }
29 |
30 | ///
31 | /// Gets the left button on the Project Lab board.
32 | ///
33 | public IButton? LeftButton { get; }
34 |
35 | ///
36 | /// Gets the right button on the Project Lab board.
37 | ///
38 | public IButton? RightButton { get; }
39 |
40 | ///
41 | /// Gets the piezo speaker on the Project Lab board.
42 | ///
43 | public IToneGenerator? Speaker { get; }
44 |
45 | ///
46 | /// Gets the RGB PWM LED on the Project Lab board.
47 | ///
48 | public IRgbPwmLed? RgbLed { get; }
49 |
50 | ///
51 | /// Gets the light sensor on the Project Lab board.
52 | ///
53 | public ILightSensor? LightSensor { get; }
54 |
55 | ///
56 | /// Gets the ITemperatureSensor on the Project Lab board.
57 | ///
58 | public ISamplingTemperatureSensor? TemperatureSensor { get; }
59 |
60 | ///
61 | /// Gets the second/alternate ITemperatureSensor on the Project Lab board.
62 | ///
63 | public ISamplingTemperatureSensor? TemperatureSensor2 { get; }
64 |
65 | ///
66 | /// Gets the IHumiditySensor on the Project Lab board.
67 | ///
68 | public IHumiditySensor? HumiditySensor { get; }
69 |
70 | ///
71 | /// Gets the IBarometricPressureSensor on the Project Lab board.
72 | ///
73 | public IBarometricPressureSensor? BarometricPressureSensor { get; }
74 |
75 | ///
76 | /// Gets the IGasResistanceSensor on the Project Lab board.
77 | ///
78 | public IGasResistanceSensor? GasResistanceSensor { get; }
79 |
80 | ///
81 | /// Gets the IGyroscope on the Project Lab board
82 | ///
83 | public IGyroscope? Gyroscope { get; }
84 |
85 | ///
86 | /// Gets the IAccelerometer on the Project Lab board
87 | ///
88 | public IAccelerometer? Accelerometer { get; }
89 |
90 | ///
91 | /// Gets the graphics display on the Project Lab board.
92 | ///
93 | public IPixelDisplay? Display { get; }
94 |
95 | ///
96 | /// Gets the revision string of the Project Lab board.
97 | ///
98 | public string RevisionString { get; }
99 |
100 | ///
101 | /// Gets MikroBus connector 1 on the Project Lab board.
102 | ///
103 | public MikroBusConnector MikroBus1 { get; }
104 |
105 | ///
106 | /// Gets MikroBus connector 2 on the Project Lab board.
107 | ///
108 | public MikroBusConnector MikroBus2 { get; }
109 |
110 | ///
111 | /// Gets the Grove Digital connector on the Project Lab board.
112 | ///
113 | public GroveDigitalConnector? GroveDigital { get; }
114 |
115 | ///
116 | /// Gets the Grove Analog connector on the Project Lab board.
117 | ///
118 | public GroveDigitalConnector GroveAnalog { get; }
119 |
120 | ///
121 | /// Gets the Grove UART connector on the Project Lab board.
122 | ///
123 | public UartConnector GroveUart { get; }
124 |
125 | ///
126 | /// Gets the Qwiic connector on the Project Lab board.
127 | ///
128 | public I2cConnector Qwiic { get; }
129 |
130 | ///
131 | /// Gets the IO Terminal connector on the Project Lab board.
132 | ///
133 | public IOTerminalConnector IOTerminal { get; }
134 |
135 | ///
136 | /// Gets the display header connector on the Project Lab board.
137 | ///
138 | public DisplayConnector DisplayHeader { get; }
139 |
140 | ///
141 | /// Gets the touchscreen on the Project Lab display
142 | ///
143 | public ITouchScreen? Touchscreen { get; }
144 |
145 | ///
146 | /// Get a Modbus RTU client with optional parameters.
147 | ///
148 | /// The baud rate.
149 | /// The number of data bits.
150 | /// The parity setting.
151 | /// The stop bits setting.
152 | /// A Modbus RTU client.
153 | public ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One);
154 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/Meadow.ProjectLab.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | icon.png
5 | Wilderness Labs, Inc
6 | netstandard2.1
7 | Library
8 | ProjectLab
9 | Wilderness Labs, Inc
10 | https://github.com/WildernessLabs/Meadow.ProjectLab
11 | Meadow.ProjectLab
12 | https://github.com/WildernessLabs/Meadow.ProjectLab
13 | Meadow.ProjectLab,Meadow,ProjectLab,accelerator
14 | true
15 | Library for the Meadow ProjectLab IoT accelerator
16 | enable
17 |
18 |
19 | Apache-2.0
20 | 12
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLab.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.ICs.IOExpanders;
2 | using Meadow.Hardware;
3 | using Meadow.Logging;
4 | using System;
5 |
6 | namespace Meadow.Devices;
7 |
8 | ///
9 | /// A base class for Feather-based, Project Lab-targeted applications
10 | ///
11 | public abstract class ProjectLabFeatherApp : App
12 | {
13 | }
14 |
15 | ///
16 | /// A base class for F7 Core Compute-based, Project Lab-targeted applications
17 | ///
18 | public abstract class ProjectLabCoreComputeApp : App
19 | {
20 | }
21 |
22 | ///
23 | /// Represents Project Lab hardware and exposes its peripherals
24 | ///
25 | public class ProjectLab : IMeadowAppEmbeddedHardwareProvider
26 | {
27 | private ProjectLab() { }
28 |
29 | ///
30 | /// Create an instance of the ProjectLab class
31 | ///
32 | public static IProjectLabHardware Create()
33 | {
34 | return new ProjectLab()
35 | .Create(Resolver.Services.Get()!);
36 | }
37 |
38 | ///
39 | /// Create an instance of the ProjectLab class
40 | ///
41 | /// ProjectLab instance
42 | /// ProjectLab instance must be created after App.Initialize()
43 | /// Couldn't detect known ProjectLab hardware
44 | public IProjectLabHardware Create(IMeadowDevice device)
45 | {
46 | IProjectLabHardware hardware;
47 | Logger? logger = Resolver.Log;
48 |
49 | Mcp23008? mcp = null;
50 |
51 | logger?.Trace("Initializing Project Lab...");
52 |
53 | // make sure not getting instantiated before the App Initialize method
54 | if (device == null)
55 | {
56 | var msg = "ProjectLab instance must be created after App.Initialize()";
57 | logger?.Error(msg);
58 | throw new Exception(msg);
59 | }
60 |
61 | var i2cBus = device.CreateI2cBus();
62 | logger?.Debug("I2C Bus instantiated");
63 |
64 | IDigitalInterruptPort? mcpInterrupt = null;
65 | IDigitalOutputPort? mcpReset = null;
66 | bool isV3 = false;
67 |
68 | if (device is IF7FeatherMeadowDevice f)
69 | {
70 | try
71 | {
72 | mcpInterrupt = device.CreateDigitalInterruptPort(f.Pins.D09, InterruptMode.EdgeRising, ResistorMode.InternalPullDown);
73 | mcpReset = device.CreateDigitalOutputPort(f.Pins.D14);
74 |
75 | mcp = new Mcp23008(i2cBus, address: 0x20, mcpInterrupt, mcpReset);
76 |
77 | logger?.Trace("Mcp_1 up");
78 | }
79 | catch
80 | {
81 | logger?.Debug("Failed to create MCP1: could be a v1 board");
82 | mcpInterrupt?.Dispose();
83 | mcpReset?.Dispose();
84 | }
85 | }
86 | else if (device is IF7CoreComputeMeadowDevice c)
87 | {
88 | try
89 | {
90 | mcpReset = device.CreateDigitalOutputPort(c.Pins.PA10);
91 |
92 | mcp = new Mcp23008(i2cBus, address: 0x27, resetPort: mcpReset);
93 |
94 | logger?.Trace("Mcp_version up");
95 | isV3 = mcp.ReadFromPorts() < 17;
96 | }
97 | catch
98 | {
99 | logger?.Debug("Failed to create version MCP: could be a v3 board");
100 | isV3 = true;
101 | }
102 | finally
103 | {
104 | mcpReset?.Dispose();
105 | mcp = null;
106 | }
107 | }
108 |
109 | switch (device)
110 | {
111 | case IF7FeatherMeadowDevice feather when mcp is null:
112 | logger?.Info("Instantiating Project Lab v1 specific hardware");
113 | hardware = new ProjectLabHardwareV1(feather, i2cBus);
114 | break;
115 | case IF7FeatherMeadowDevice feather:
116 | logger?.Info("Instantiating Project Lab v2 specific hardware");
117 | hardware = new ProjectLabHardwareV2(feather, i2cBus, mcp);
118 | break;
119 | case IF7CoreComputeMeadowDevice ccm when isV3 == true:
120 | logger?.Info($"Instantiating Project Lab v3 specific hardware");
121 | hardware = new ProjectLabHardwareV3(ccm, i2cBus);
122 | break;
123 | case IF7CoreComputeMeadowDevice ccm:
124 | logger?.Info($"Instantiating Project Lab v4 specific hardware");
125 | hardware = new ProjectLabHardwareV4(ccm, i2cBus);
126 | break;
127 | default:
128 | throw new NotSupportedException();
129 | }
130 |
131 | return hardware;
132 | }
133 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabHardwareBase.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.Sensors.Atmospheric;
2 | using Meadow.Foundation.Sensors.Light;
3 | using Meadow.Foundation.Sensors.Motion;
4 | using Meadow.Hardware;
5 | using Meadow.Logging;
6 | using Meadow.Modbus;
7 | using Meadow.Peripherals.Displays;
8 | using Meadow.Peripherals.Leds;
9 | using Meadow.Peripherals.Sensors;
10 | using Meadow.Peripherals.Sensors.Atmospheric;
11 | using Meadow.Peripherals.Sensors.Buttons;
12 | using Meadow.Peripherals.Sensors.Environmental;
13 | using Meadow.Peripherals.Sensors.Light;
14 | using Meadow.Peripherals.Sensors.Motion;
15 | using Meadow.Peripherals.Speakers;
16 | using System;
17 |
18 | namespace Meadow.Devices;
19 |
20 | ///
21 | /// Contains common elements of Project Lab hardware
22 | ///
23 | public abstract class ProjectLabHardwareBase : IProjectLabHardware
24 | {
25 | private IConnector?[]? _connectors;
26 | private IPixelDisplay? _display;
27 | private ILightSensor? _lightSensor;
28 | private Bme688? _atmosphericSensor;
29 | private Bmi270? _motionSensor;
30 | private IGyroscope? _gyroscope;
31 | private IAccelerometer? _accelerometer;
32 | private ISamplingTemperatureSensor? _temperatureSensor;
33 | private ISamplingTemperatureSensor? _temperatureSensor2;
34 | private IHumiditySensor? _humiditySensor;
35 | private IBarometricPressureSensor? _barometricPressureSensor;
36 | private IGasResistanceSensor? _gasResistanceSensor;
37 |
38 | ///
39 | /// Get a reference to Meadow Logger
40 | ///
41 | protected Logger? Logger { get; } = Resolver.Log;
42 |
43 | ///
44 | public abstract IButton? UpButton { get; }
45 |
46 | ///
47 | public IMeadowDevice ComputeModule { get; }
48 |
49 | ///
50 | public abstract IButton? DownButton { get; }
51 |
52 | ///
53 | public abstract IButton? LeftButton { get; }
54 |
55 | ///
56 | public abstract IButton? RightButton { get; }
57 |
58 | ///
59 | public abstract IToneGenerator? Speaker { get; }
60 |
61 | ///
62 | public abstract IRgbPwmLed? RgbLed { get; }
63 |
64 | ///
65 | public virtual ITouchScreen? Touchscreen => null;
66 |
67 | ///
68 | public ILightSensor? LightSensor => GetLightSensor();
69 |
70 | ///
71 | public Bme688? AtmosphericSensor => GetAtmosphericSensor();
72 |
73 | ///
74 | public Bmi270? MotionSensor => GetMotionSensor();
75 |
76 | ///
77 | public IGyroscope? Gyroscope => GetGyroscope();
78 |
79 | ///
80 | public IAccelerometer? Accelerometer => GetAccelerometer();
81 |
82 | ///
83 | public ISamplingTemperatureSensor? TemperatureSensor => GetTemperatureSensor();
84 |
85 | ///
86 | public ISamplingTemperatureSensor? TemperatureSensor2 => GetTemperatureSensor2();
87 |
88 | ///
89 | public IHumiditySensor? HumiditySensor => GetHumiditySensor();
90 |
91 | ///
92 | public IBarometricPressureSensor? BarometricPressureSensor => GetBarometricPressureSensor();
93 |
94 | ///
95 | public IGasResistanceSensor? GasResistanceSensor => GetGasResistanceSensor();
96 |
97 | ///
98 | public IPixelDisplay? Display
99 | {
100 | get
101 | {
102 | _display ??= GetDefaultDisplay();
103 | return _display;
104 | }
105 | set => _display = value;
106 | }
107 |
108 | ///
109 | /// Gets the default display for the Project Lab board.
110 | ///
111 | protected abstract IPixelDisplay? GetDefaultDisplay();
112 |
113 | ///
114 | public virtual string RevisionString { get; set; } = "unknown";
115 |
116 | ///
117 | public MikroBusConnector MikroBus1 => (MikroBusConnector)Connectors[0]!;
118 |
119 | ///
120 | public MikroBusConnector MikroBus2 => (MikroBusConnector)Connectors[1]!;
121 |
122 | ///
123 | public GroveDigitalConnector? GroveDigital => (GroveDigitalConnector?)Connectors[2];
124 |
125 | ///
126 | public GroveDigitalConnector GroveAnalog => (GroveDigitalConnector)Connectors[3]!;
127 |
128 | ///
129 | public UartConnector GroveUart => (UartConnector)Connectors[4]!;
130 |
131 | ///
132 | public I2cConnector Qwiic => (I2cConnector)Connectors[5]!;
133 |
134 | ///
135 | public IOTerminalConnector IOTerminal => (IOTerminalConnector)Connectors[6]!;
136 |
137 | ///
138 | public DisplayConnector DisplayHeader => (DisplayConnector)Connectors[7]!;
139 |
140 | internal abstract MikroBusConnector CreateMikroBus1();
141 | internal abstract MikroBusConnector CreateMikroBus2();
142 | internal virtual GroveDigitalConnector? CreateGroveDigitalConnector()
143 | {
144 | return null;
145 | }
146 |
147 | internal abstract GroveDigitalConnector CreateGroveAnalogConnector();
148 |
149 | internal abstract UartConnector CreateGroveUartConnector();
150 |
151 | internal abstract I2cConnector CreateQwiicConnector();
152 |
153 | internal abstract IOTerminalConnector CreateIOTerminalConnector();
154 |
155 | internal abstract DisplayConnector CreateDisplayConnector();
156 |
157 | ///
158 | /// Collection of connectors on the Project Lab board
159 | ///
160 | public IConnector?[] Connectors
161 | {
162 | get
163 | {
164 | if (_connectors == null)
165 | {
166 | _connectors = new IConnector[8];
167 | _connectors[0] = CreateMikroBus1();
168 | _connectors[1] = CreateMikroBus2();
169 | _connectors[2] = CreateGroveDigitalConnector();
170 | _connectors[3] = CreateGroveAnalogConnector();
171 | _connectors[4] = CreateGroveUartConnector();
172 | _connectors[5] = CreateQwiicConnector();
173 | _connectors[6] = CreateIOTerminalConnector();
174 | _connectors[7] = CreateDisplayConnector();
175 | }
176 |
177 | return _connectors;
178 | }
179 | }
180 |
181 | private readonly II2cBus _peripheralI2cBus;
182 |
183 | internal ProjectLabHardwareBase(IMeadowDevice compute, II2cBus peripheralI2cBus)
184 | {
185 | ComputeModule = compute;
186 |
187 | _peripheralI2cBus = peripheralI2cBus;
188 | }
189 |
190 | private IAccelerometer? GetAccelerometer()
191 | {
192 | if (_accelerometer == null)
193 | {
194 | InitializeBmi270();
195 | }
196 |
197 | return _accelerometer;
198 | }
199 |
200 | private IGyroscope? GetGyroscope()
201 | {
202 | if (_gyroscope == null)
203 | {
204 | InitializeBmi270();
205 | }
206 |
207 | return _gyroscope;
208 | }
209 |
210 | private ISamplingTemperatureSensor? GetTemperatureSensor()
211 | {
212 | if (_temperatureSensor == null)
213 | {
214 | InitializeBmi270();
215 | }
216 |
217 | return _temperatureSensor;
218 | }
219 |
220 | private ISamplingTemperatureSensor? GetTemperatureSensor2()
221 | {
222 | if (_temperatureSensor2 == null)
223 | {
224 | InitializeBme688();
225 | }
226 |
227 | return _temperatureSensor2;
228 | }
229 |
230 | private void InitializeBmi270()
231 | {
232 | try
233 | {
234 | Logger?.Trace("Instantiating motion sensor");
235 | var bmi = new Bmi270(_peripheralI2cBus);
236 | _motionSensor = bmi;
237 | _gyroscope = bmi;
238 | _accelerometer = bmi;
239 | // we use the BMI270 because, I believe, the 688 is closer to an on-board heat source and reads high
240 | _temperatureSensor = bmi;
241 | Resolver.SensorService.RegisterSensor(_motionSensor);
242 | Logger?.Trace("Motion sensor up");
243 | }
244 | catch (Exception ex)
245 | {
246 | Logger?.Error($"Unable to create the BMI270 IMU: {ex.Message}");
247 | }
248 | }
249 |
250 | private Bmi270? GetMotionSensor()
251 | {
252 | if (_motionSensor == null)
253 | {
254 | InitializeBmi270();
255 | }
256 |
257 | return _motionSensor;
258 | }
259 |
260 | private ILightSensor? GetLightSensor()
261 | {
262 | if (_lightSensor == null)
263 | {
264 | try
265 | {
266 | Logger?.Trace("Instantiating light sensor");
267 | _lightSensor = new Bh1750(
268 | i2cBus: _peripheralI2cBus,
269 | measuringMode: Bh1750.MeasuringModes.ContinuouslyHighResolutionMode, // the various modes take differing amounts of time.
270 | lightTransmittance: 0.5, // lower this to increase sensitivity, for instance, if it's behind a semi opaque window
271 | address: (byte)Bh1750.Addresses.Address_0x23);
272 | Resolver.SensorService.RegisterSensor(_lightSensor);
273 | Logger?.Trace("Light sensor up");
274 | }
275 | catch (Exception ex)
276 | {
277 | Logger?.Error($"Unable to create the BH1750 light sensor: {ex.Message}");
278 | }
279 | }
280 |
281 | return _lightSensor;
282 | }
283 |
284 | private Bme688? GetAtmosphericSensor()
285 | {
286 | if (_atmosphericSensor == null)
287 | {
288 | InitializeBme688();
289 | }
290 |
291 | return _atmosphericSensor;
292 | }
293 |
294 | private IHumiditySensor? GetHumiditySensor()
295 | {
296 | if (_humiditySensor == null)
297 | {
298 | InitializeBme688();
299 | }
300 |
301 | return _humiditySensor;
302 | }
303 |
304 | private IBarometricPressureSensor? GetBarometricPressureSensor()
305 | {
306 | if (_barometricPressureSensor == null)
307 | {
308 | InitializeBme688();
309 | }
310 |
311 | return _barometricPressureSensor;
312 | }
313 |
314 | private IGasResistanceSensor? GetGasResistanceSensor()
315 | {
316 | if (_gasResistanceSensor == null)
317 | {
318 | InitializeBme688();
319 | }
320 |
321 | return _gasResistanceSensor;
322 | }
323 |
324 | private void InitializeBme688()
325 | {
326 | try
327 | {
328 | Logger?.Trace("Instantiating atmospheric sensor");
329 | var bme = new Bme688(_peripheralI2cBus, (byte)Bme68x.Addresses.Address_0x76);
330 | _atmosphericSensor = bme;
331 | _humiditySensor = bme;
332 | _barometricPressureSensor = bme;
333 | _gasResistanceSensor = bme;
334 | _temperatureSensor2 = bme;
335 | Resolver.SensorService.RegisterSensor(bme);
336 | Logger?.Trace("Atmospheric sensor up");
337 | }
338 | catch (Exception ex)
339 | {
340 | Logger?.Error($"Unable to create the BME688 atmospheric sensor: {ex.Message}");
341 | }
342 | }
343 |
344 | ///
345 | /// Gets a ModbusRtuClient for the on-board RS485 connector
346 | ///
347 | public abstract ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One);
348 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabHardwareV1.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.Audio;
2 | using Meadow.Foundation.Displays;
3 | using Meadow.Foundation.Leds;
4 | using Meadow.Foundation.Sensors.Buttons;
5 | using Meadow.Hardware;
6 | using Meadow.Modbus;
7 | using Meadow.Peripherals.Displays;
8 | using Meadow.Peripherals.Leds;
9 | using Meadow.Peripherals.Sensors.Buttons;
10 | using Meadow.Peripherals.Speakers;
11 | using Meadow.Units;
12 | using System;
13 | using System.Threading;
14 |
15 | namespace Meadow.Devices;
16 |
17 | ///
18 | /// Represents Project Lab V1 hardware and exposes its peripherals
19 | ///
20 | public class ProjectLabHardwareV1 : ProjectLabHardwareBase
21 | {
22 | private readonly IF7FeatherMeadowDevice _device;
23 | private IToneGenerator? _speaker;
24 | private IRgbPwmLed? _rgbled;
25 | private IPixelDisplay? _display;
26 |
27 | private readonly string revision = "v1.x";
28 |
29 | ///
30 | public override IButton UpButton { get; }
31 |
32 | ///
33 | public override IButton DownButton { get; }
34 |
35 | ///
36 | public override IButton LeftButton { get; }
37 |
38 | ///
39 | public override IButton RightButton { get; }
40 |
41 | ///
42 | public override IToneGenerator? Speaker => GetSpeaker();
43 |
44 | ///
45 | public override IRgbPwmLed? RgbLed => GetRgbLed();
46 |
47 | internal ProjectLabHardwareV1(IF7FeatherMeadowDevice device, II2cBus i2cBus)
48 | : base(device, i2cBus)
49 | {
50 | _device = device;
51 |
52 | Logger?.Trace("Instantiating buttons");
53 | LeftButton = GetPushButton(device.Pins.D10);
54 | RightButton = GetPushButton(device.Pins.D05);
55 | UpButton = GetPushButton(device.Pins.D15);
56 | DownButton = GetPushButton(device.Pins.D02);
57 | Logger?.Trace("Buttons up");
58 | }
59 |
60 | ///
61 | protected override IPixelDisplay? GetDefaultDisplay()
62 | {
63 | if (_display == null)
64 | {
65 | Logger?.Trace("Instantiating display");
66 |
67 | var chipSelectPort = DisplayHeader.Pins.DISPLAY_CS.CreateDigitalOutputPort();
68 | var dcPort = DisplayHeader.Pins.DISPLAY_DC.CreateDigitalOutputPort();
69 | var resetPort = DisplayHeader.Pins.DISPLAY_RST.CreateDigitalOutputPort();
70 | Thread.Sleep(50);
71 |
72 | _display = new St7789(
73 | spiBus: DisplayHeader.SpiBusDisplay,
74 | chipSelectPort: chipSelectPort,
75 | dataCommandPort: dcPort,
76 | resetPort: resetPort,
77 | width: 240, height: 240,
78 | colorMode: ColorMode.Format16bppRgb565)
79 | {
80 | SpiBusMode = SpiClockConfiguration.Mode.Mode3,
81 | SpiBusSpeed = new Frequency(24000, Frequency.UnitType.Kilohertz)
82 | };
83 | ((St7789)_display).SetRotation(RotationType._270Degrees);
84 |
85 | Logger?.Trace("Display up");
86 | }
87 |
88 | return _display;
89 | }
90 |
91 | private IToneGenerator? GetSpeaker()
92 | {
93 | if (_speaker == null)
94 | {
95 | try
96 | {
97 | Logger?.Trace("Instantiating speaker");
98 | _speaker = new PiezoSpeaker(_device.Pins.D11);
99 | Logger?.Trace("Speaker up");
100 | }
101 | catch (Exception ex)
102 | {
103 | Logger?.Error($"Unable to create the Piezo Speaker: {ex.Message}");
104 | }
105 | }
106 |
107 | return _speaker;
108 | }
109 |
110 | private IRgbPwmLed? GetRgbLed()
111 | {
112 | if (_rgbled == null)
113 | {
114 | try
115 | {
116 | Logger?.Trace("Instantiating RGB LED");
117 | _rgbled = new RgbPwmLed(
118 | redPwmPin: _device.Pins.OnboardLedRed,
119 | greenPwmPin: _device.Pins.OnboardLedGreen,
120 | bluePwmPin: _device.Pins.OnboardLedBlue,
121 | CommonType.CommonAnode);
122 | Logger?.Trace("RGB LED up");
123 | }
124 | catch (Exception ex)
125 | {
126 | Logger?.Error($"Unable to create the RGB LED: {ex.Message}");
127 | }
128 | }
129 |
130 | return _rgbled;
131 | }
132 |
133 | internal override MikroBusConnector CreateMikroBus1()
134 | {
135 | Logger?.Trace("Creating MikroBus1 connector");
136 | return new MikroBusConnector(
137 | "MikroBus1",
138 | new PinMapping
139 | {
140 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.A00),
141 | // no DISPLAY_RST connected
142 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, _device.Pins.D14),
143 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SCK),
144 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.CIPO),
145 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.COPI),
146 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.D04),
147 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, _device.Pins.D03),
148 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, _device.Pins.D12),
149 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, _device.Pins.D13),
150 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C_SCL),
151 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C_SDA),
152 | },
153 | _device.PlatformOS.GetSerialPortName("com1")!,
154 | new I2cBusMapping(_device, 1),
155 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO)
156 | );
157 | }
158 |
159 | internal override MikroBusConnector CreateMikroBus2()
160 | {
161 | Logger?.Trace("Creating MikroBus2 connector");
162 | return new MikroBusConnector(
163 | "MikroBus2",
164 | new PinMapping
165 | {
166 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.A01),
167 | // no RST connected
168 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, _device.Pins.A02),
169 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SCK),
170 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.CIPO),
171 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.COPI),
172 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.D03),
173 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, _device.Pins.D04),
174 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, _device.Pins.D12),
175 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, _device.Pins.D13),
176 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C_SCL),
177 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C_SDA),
178 | },
179 | _device.PlatformOS.GetSerialPortName("com1")!,
180 | new I2cBusMapping(_device, 1),
181 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO)
182 | );
183 | }
184 |
185 | internal override GroveDigitalConnector CreateGroveAnalogConnector()
186 | {
187 | Logger?.Trace("Creating Grove analog connector");
188 |
189 | return new GroveDigitalConnector(
190 | nameof(GroveAnalog),
191 | new PinMapping
192 | {
193 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.A01),
194 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, _device.Pins.A02),
195 | });
196 | }
197 |
198 | internal override UartConnector CreateGroveUartConnector()
199 | {
200 | Logger?.Trace("Creating Grove UART connector");
201 |
202 | return new UartConnector(
203 | nameof(GroveUart),
204 | new PinMapping
205 | {
206 | new PinMapping.PinAlias(UartConnector.PinNames.RX, _device.Pins.D13),
207 | new PinMapping.PinAlias(UartConnector.PinNames.TX, _device.Pins.D12),
208 | },
209 | _device.PlatformOS.GetSerialPortName("com1")!);
210 | }
211 |
212 | internal override I2cConnector CreateQwiicConnector()
213 | {
214 | Logger?.Trace("Creating Qwiic I2C connector");
215 |
216 | return new I2cConnector(
217 | nameof(Qwiic),
218 | new PinMapping
219 | {
220 | new PinMapping.PinAlias(I2cConnector.PinNames.SCL, _device.Pins.D08),
221 | new PinMapping.PinAlias(I2cConnector.PinNames.SDA, _device.Pins.D07),
222 | },
223 | new I2cBusMapping(_device, 1));
224 | }
225 |
226 | internal override IOTerminalConnector CreateIOTerminalConnector()
227 | {
228 | Logger?.Trace("Creating IO terminal connector");
229 |
230 | return new IOTerminalConnector(
231 | nameof(IOTerminal),
232 | new PinMapping
233 | {
234 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.A1, _device.Pins.A00),
235 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D2, _device.Pins.D03),
236 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D3, _device.Pins.D04),
237 | });
238 | }
239 |
240 | internal override DisplayConnector CreateDisplayConnector()
241 | {
242 | Logger?.Trace("Creating display connector");
243 |
244 | return new DisplayConnector(
245 | nameof(Display),
246 | new PinMapping
247 | {
248 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CS, _device.Pins.A03),
249 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_RST, _device.Pins.A05),
250 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_DC, _device.Pins.A04),
251 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CLK, _device.Pins.SCK),
252 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_COPI, _device.Pins.COPI),
253 | },
254 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO));
255 | }
256 |
257 | ///
258 | public override string RevisionString => revision;
259 |
260 | private IButton GetPushButton(IPin pin)
261 | {
262 | if (pin.Supports(c => c.InterruptCapable))
263 | {
264 | return new PushButton(pin, ResistorMode.InternalPullDown);
265 | }
266 | else
267 | {
268 | return new PollingPushButton(pin, ResistorMode.InternalPullDown);
269 | }
270 | }
271 |
272 | ///
273 | public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
274 | {
275 | if (Resolver.Device is not F7FeatherBase device) throw new NotSupportedException();
276 | var portName = device.PlatformOS.GetSerialPortName("com4")!;
277 | var port = device.CreateSerialPort(portName, baudRate, dataBits, parity, stopBits);
278 | port.WriteTimeout = port.ReadTimeout = TimeSpan.FromSeconds(5);
279 | var serialEnable = device.CreateDigitalOutputPort(device.Pins.D09, false);
280 | return new ProjectLabModbusRtuClient(port, serialEnable);
281 | }
282 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabHardwareV2.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.Audio;
2 | using Meadow.Foundation.Displays;
3 | using Meadow.Foundation.ICs.IOExpanders;
4 | using Meadow.Foundation.Leds;
5 | using Meadow.Foundation.Sensors.Buttons;
6 | using Meadow.Hardware;
7 | using Meadow.Modbus;
8 | using Meadow.Peripherals.Displays;
9 | using Meadow.Peripherals.Leds;
10 | using Meadow.Peripherals.Sensors.Buttons;
11 | using Meadow.Peripherals.Speakers;
12 | using Meadow.Units;
13 | using System;
14 | using System.Diagnostics;
15 | using System.Threading;
16 |
17 | namespace Meadow.Devices;
18 |
19 | ///
20 | /// Represents Project Lab V2 hardware and exposes its peripherals
21 | ///
22 | public class ProjectLabHardwareV2 : ProjectLabHardwareBase
23 | {
24 | private readonly IF7FeatherMeadowDevice _device;
25 | private IToneGenerator? _speaker;
26 | private IRgbPwmLed? _rgbled;
27 | private IPixelDisplay? _display;
28 |
29 | ///
30 | /// The MCP23008 IO expander connected to internal peripherals
31 | ///
32 | public Mcp23008 Mcp_1 { get; protected set; }
33 |
34 | ///
35 | /// The MCP23008 IO expander connected to IO headers and terminals on Project Lab
36 | ///
37 | public Mcp23008? Mcp_2 { get; protected set; }
38 |
39 | ///
40 | /// The MCP23008 IO expander that contains the ProjectLab hardware version
41 | ///
42 | private Mcp23008? Mcp_Version { get; }
43 |
44 | ///
45 | public override IButton UpButton { get; }
46 |
47 | ///
48 | public override IButton DownButton { get; }
49 |
50 | ///
51 | public override IButton LeftButton { get; }
52 |
53 | ///
54 | public override IButton RightButton { get; }
55 |
56 | ///
57 | public override IToneGenerator? Speaker => GetSpeaker();
58 |
59 | ///
60 | public override IRgbPwmLed? RgbLed => GetRgbLed();
61 |
62 | internal ProjectLabHardwareV2(IF7FeatherMeadowDevice device, II2cBus i2cBus, Mcp23008 mcp1)
63 | : base(device, i2cBus)
64 | {
65 | _device = device;
66 |
67 | Mcp_1 = mcp1;
68 | IDigitalInterruptPort? mcp2_int = null;
69 |
70 | try
71 | {
72 | // MCP the Second
73 | if (device.Pins.D10.Supports(c => c.InterruptCapable))
74 | {
75 | mcp2_int = device.CreateDigitalInterruptPort(
76 | device.Pins.D10, InterruptMode.EdgeRising, ResistorMode.InternalPullDown);
77 | }
78 |
79 | Mcp_2 = new Mcp23008(i2cBus, address: 0x21, mcp2_int);
80 |
81 | Logger?.Info("Mcp_2 up");
82 | }
83 | catch (Exception e)
84 | {
85 | Logger?.Trace($"Failed to create MCP2: {e.Message}");
86 | mcp2_int?.Dispose();
87 | }
88 |
89 | try
90 | {
91 | Mcp_Version = new Mcp23008(i2cBus, address: 0x27);
92 | Logger?.Info("Mcp_Version up");
93 | }
94 | catch (Exception e)
95 | {
96 | Logger?.Trace($"ERR creating the MCP that has version information: {e.Message}");
97 | }
98 |
99 | Logger?.Trace("Instantiating buttons");
100 | var leftPort = mcp1.CreateDigitalInterruptPort(mcp1.Pins.GP2, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
101 | LeftButton = new PushButton(leftPort);
102 | var rightPort = mcp1.CreateDigitalInterruptPort(mcp1.Pins.GP1, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
103 | RightButton = new PushButton(rightPort);
104 | var upPort = mcp1.CreateDigitalInterruptPort(mcp1.Pins.GP0, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
105 | UpButton = new PushButton(upPort);
106 | var downPort = mcp1.CreateDigitalInterruptPort(mcp1.Pins.GP3, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
107 | DownButton = new PushButton(downPort);
108 | Logger?.Trace("Buttons up");
109 | }
110 |
111 | ///
112 | protected override IPixelDisplay? GetDefaultDisplay()
113 | {
114 | if (_display == null)
115 | {
116 | Logger?.Trace("Instantiating display");
117 |
118 | var chipSelectPort = DisplayHeader.Pins.DISPLAY_CS.CreateDigitalOutputPort();
119 | var dcPort = DisplayHeader.Pins.DISPLAY_DC.CreateDigitalOutputPort();
120 | var resetPort = DisplayHeader.Pins.DISPLAY_RST.CreateDigitalOutputPort();
121 | Thread.Sleep(50);
122 |
123 | _display = new St7789(
124 | spiBus: DisplayHeader.SpiBusDisplay,
125 | chipSelectPort: chipSelectPort,
126 | dataCommandPort: dcPort,
127 | resetPort: resetPort,
128 | width: 240, height: 240,
129 | colorMode: ColorMode.Format16bppRgb565)
130 | {
131 | SpiBusMode = SpiClockConfiguration.Mode.Mode3,
132 | SpiBusSpeed = new Frequency(24000, Frequency.UnitType.Kilohertz)
133 | };
134 | ((St7789)_display).SetRotation(RotationType._270Degrees);
135 |
136 | Logger?.Trace("Display up");
137 | }
138 |
139 | return _display;
140 | }
141 |
142 | private IToneGenerator? GetSpeaker()
143 | {
144 | if (_speaker == null)
145 | {
146 | try
147 | {
148 | Logger?.Trace("Instantiating speaker");
149 | _speaker = new PiezoSpeaker(_device.Pins.D11);
150 | Logger?.Trace("Speaker up");
151 | }
152 | catch (Exception ex)
153 | {
154 | Logger?.Error($"Unable to create the Piezo Speaker: {ex.Message}");
155 | }
156 | }
157 |
158 | return _speaker;
159 | }
160 |
161 | private IRgbPwmLed? GetRgbLed()
162 | {
163 | if (_rgbled == null)
164 | {
165 | try
166 | {
167 | Logger?.Trace("Instantiating RGB LED");
168 | _rgbled = new RgbPwmLed(
169 | redPwmPin: _device.Pins.OnboardLedRed,
170 | greenPwmPin: _device.Pins.OnboardLedGreen,
171 | bluePwmPin: _device.Pins.OnboardLedBlue,
172 | CommonType.CommonAnode);
173 | Logger?.Trace("RGB LED up");
174 | }
175 | catch (Exception ex)
176 | {
177 | Logger?.Error($"Unable to create the RGB LED: {ex.Message}");
178 | }
179 | }
180 |
181 | return _rgbled;
182 | }
183 |
184 | internal override MikroBusConnector CreateMikroBus1()
185 | {
186 | Logger?.Trace("Creating MikroBus1 connector");
187 | Debug.Assert(Mcp_2 != null, nameof(Mcp_2) + " != null");
188 | return new MikroBusConnector(
189 | "MikroBus1",
190 | new PinMapping
191 | {
192 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.A02),
193 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, Mcp_2.Pins.GP4),
194 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, Mcp_2.Pins.GP5),
195 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SCK),
196 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.CIPO),
197 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.COPI),
198 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.D03),
199 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, Mcp_2.Pins.GP6),
200 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, _device.Pins.D13),
201 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, _device.Pins.D12),
202 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C_SCL),
203 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C_SDA),
204 | },
205 | _device.PlatformOS.GetSerialPortName("com1")!,
206 | new I2cBusMapping(_device, 1),
207 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO)
208 | );
209 | }
210 |
211 | internal override MikroBusConnector CreateMikroBus2()
212 | {
213 | Logger?.Trace("Creating MikroBus2 connector");
214 | Debug.Assert(Mcp_2 != null, nameof(Mcp_2) + " != null");
215 | return new MikroBusConnector(
216 | "MikroBus2",
217 | new PinMapping
218 | {
219 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.A03),
220 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, Mcp_2.Pins.GP1),
221 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, Mcp_2.Pins.GP2),
222 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SCK),
223 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.CIPO),
224 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.COPI),
225 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.D04),
226 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, Mcp_2.Pins.GP3),
227 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, _device.Pins.D13),
228 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, _device.Pins.D12),
229 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C_SCL),
230 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C_SDA),
231 | },
232 | _device.PlatformOS.GetSerialPortName("com1")!,
233 | new I2cBusMapping(_device, 1),
234 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO)
235 | );
236 | }
237 |
238 | internal override GroveDigitalConnector CreateGroveAnalogConnector()
239 | {
240 | Logger?.Trace("Creating Grove analog connector");
241 |
242 | return new GroveDigitalConnector(
243 | nameof(GroveAnalog),
244 | new PinMapping
245 | {
246 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.A00),
247 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, _device.Pins.A01),
248 | });
249 | }
250 |
251 | internal override UartConnector CreateGroveUartConnector()
252 | {
253 | Logger?.Trace("Creating Grove UART connector");
254 |
255 | return new UartConnector(
256 | nameof(GroveUart),
257 | new PinMapping
258 | {
259 | new PinMapping.PinAlias(UartConnector.PinNames.RX, _device.Pins.D13),
260 | new PinMapping.PinAlias(UartConnector.PinNames.TX, _device.Pins.D12),
261 | },
262 | _device.PlatformOS.GetSerialPortName("com1")!);
263 | }
264 |
265 | internal override I2cConnector CreateQwiicConnector()
266 | {
267 | Logger?.Trace("Creating Qwiic I2C connector");
268 |
269 | return new I2cConnector(
270 | nameof(Qwiic),
271 | new PinMapping
272 | {
273 | new PinMapping.PinAlias(I2cConnector.PinNames.SCL, _device.Pins.D08),
274 | new PinMapping.PinAlias(I2cConnector.PinNames.SDA, _device.Pins.D07),
275 | },
276 | new I2cBusMapping(_device, 1));
277 | }
278 |
279 | internal override IOTerminalConnector CreateIOTerminalConnector()
280 | {
281 | Logger?.Trace("Creating IO terminal connector");
282 |
283 | return new IOTerminalConnector(
284 | nameof(IOTerminal),
285 | new PinMapping
286 | {
287 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.A1, _device.Pins.A04),
288 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D2, _device.Pins.D03),
289 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D3, _device.Pins.D04),
290 | });
291 | }
292 |
293 | internal override DisplayConnector CreateDisplayConnector()
294 | {
295 | Logger?.Trace("Creating display connector");
296 |
297 | return new DisplayConnector(
298 | nameof(Display),
299 | new PinMapping
300 | {
301 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CS, Mcp_1.Pins.GP5),
302 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_RST, Mcp_1.Pins.GP7),
303 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_DC, Mcp_1.Pins.GP6),
304 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CLK, _device.Pins.SCK),
305 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_COPI, _device.Pins.COPI),
306 | },
307 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO));
308 | }
309 |
310 | private byte? _revisionNumber;
311 | ///
312 | /// The hardware revision number, read from the on-board MCP
313 | ///
314 | protected byte RevisionNumber
315 | {
316 | get
317 | {
318 | _revisionNumber ??= Mcp_Version?.ReadFromPorts(Mcp23xxx.PortBank.A) ?? 0;
319 | return _revisionNumber.Value;
320 | }
321 | }
322 |
323 | private string? _revisionString;
324 | ///
325 | public override string RevisionString
326 | {
327 | get
328 | {
329 | return _revisionString ??= $"v2.{(Mcp_Version == null ? "x" : RevisionNumber)}";
330 | }
331 | }
332 |
333 |
334 | ///
335 | public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
336 | {
337 | if (Resolver.Device is not F7FeatherBase device) throw new NotSupportedException();
338 |
339 | var portName = device.PlatformOS.GetSerialPortName("com4")!;
340 | var port = device.CreateSerialPort(portName, baudRate, dataBits, parity, stopBits);
341 | port.WriteTimeout = port.ReadTimeout = TimeSpan.FromSeconds(5);
342 | Debug.Assert(Mcp_2 != null, nameof(Mcp_2) + " != null");
343 | var serialEnable = Mcp_2.CreateDigitalOutputPort(Mcp_2.Pins.GP0, false);
344 |
345 | return new ProjectLabModbusRtuClient(port, serialEnable);
346 | }
347 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabHardwareV3.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.Audio;
2 | using Meadow.Foundation.Displays;
3 | using Meadow.Foundation.ICs.IOExpanders;
4 | using Meadow.Foundation.Leds;
5 | using Meadow.Foundation.Sensors.Buttons;
6 | using Meadow.Hardware;
7 | using Meadow.Modbus;
8 | using Meadow.Peripherals.Displays;
9 | using Meadow.Peripherals.Leds;
10 | using Meadow.Peripherals.Sensors.Buttons;
11 | using Meadow.Peripherals.Speakers;
12 | using Meadow.Units;
13 | using System;
14 | using System.Threading;
15 |
16 | namespace Meadow.Devices;
17 |
18 | ///
19 | /// Represents Project Lab V3 hardware and exposes its peripherals
20 | ///
21 | public class ProjectLabHardwareV3 : ProjectLabHardwareBase
22 | {
23 | private readonly IF7CoreComputeMeadowDevice _device;
24 | private readonly IConnectorProvider _connectors;
25 | private IToneGenerator? _speaker;
26 | private IRgbPwmLed? _rgbled;
27 | private IPixelDisplay? _display;
28 |
29 | ///
30 | /// The MCP23008 IO expander connected to internal peripherals on Project Lab
31 | ///
32 | public Mcp23008? Mcp_1 { get; protected set; }
33 |
34 | ///
35 | /// The MCP23008 IO expander connected to IO headers and terminals on Project Lab
36 | ///
37 | public Mcp23008? Mcp_2 { get; protected set; }
38 |
39 | ///
40 | /// The MCP23008 IO expander that contains the ProjectLab hardware version
41 | ///
42 | private Mcp23008? Mcp_Version { get; set; }
43 |
44 | ///
45 | public override IButton? UpButton { get; }
46 |
47 | ///
48 | public override IButton? DownButton { get; }
49 |
50 | ///
51 | public override IButton? LeftButton { get; }
52 |
53 | ///
54 | public override IButton? RightButton { get; }
55 |
56 | ///
57 | public override IToneGenerator? Speaker => GetSpeaker();
58 |
59 | ///
60 | public override IRgbPwmLed? RgbLed => GetRgbLed();
61 |
62 | ///
63 | /// Display enable port for backlight control
64 | ///
65 | public IDigitalOutputPort? DisplayEnablePort { get; protected set; }
66 |
67 | internal ProjectLabHardwareV3(IF7CoreComputeMeadowDevice device, II2cBus i2cBus)
68 | : base(device, i2cBus)
69 | {
70 | _device = device;
71 |
72 | IDigitalInterruptPort? mcp1Interrupt = null;
73 | IDigitalOutputPort? mcp1Reset = null;
74 |
75 | try
76 | {
77 | mcp1Interrupt = device.CreateDigitalInterruptPort(
78 | device.Pins.A05,
79 | InterruptMode.EdgeRising,
80 | ResistorMode.InternalPullDown);
81 |
82 | mcp1Reset = device.CreateDigitalOutputPort(device.Pins.PB4);
83 |
84 | Mcp_1 = new Mcp23008(i2cBus, address: 0x20, mcp1Interrupt, mcp1Reset);
85 |
86 | Logger?.Trace("Mcp_1 up");
87 | }
88 | catch (Exception e)
89 | {
90 | Logger?.Trace($"Failed to create MCP1: {e.Message}");
91 | mcp1Interrupt?.Dispose();
92 | }
93 |
94 | IDigitalInterruptPort? mcp2Interrupt = null;
95 |
96 | try
97 | {
98 | mcp2Interrupt = device.CreateDigitalInterruptPort(device.Pins.PC8, InterruptMode.EdgeRising);
99 |
100 | Mcp_2 = new Mcp23008(i2cBus, address: 0x21, mcp2Interrupt);
101 |
102 | Logger?.Trace("Mcp_2 up");
103 | }
104 | catch (Exception e)
105 | {
106 | Logger?.Trace($"Failed to create MCP2: {e.Message}");
107 | mcp2Interrupt?.Dispose();
108 | }
109 |
110 | try
111 | {
112 | Mcp_Version = new Mcp23008(i2cBus, address: 0x27);
113 | Logger?.Trace("Mcp_Version up");
114 | }
115 | catch (Exception e)
116 | {
117 | Logger?.Trace($"ERR creating the MCP that has version information: {e.Message}");
118 | }
119 |
120 | Logger?.Trace("Instantiating buttons");
121 | var leftPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP2, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
122 | if (leftPort != null) LeftButton = new PushButton(leftPort);
123 | var rightPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP1, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
124 | if (rightPort != null) RightButton = new PushButton(rightPort);
125 | var upPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP0, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
126 | if (upPort != null) UpButton = new PushButton(upPort);
127 | var downPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP3, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
128 | if (downPort != null) DownButton = new PushButton(downPort);
129 | Logger?.Trace("Buttons up");
130 |
131 | if (RevisionNumber < 15) // before 3.e
132 | {
133 | Logger?.Trace("Hardware is 3.d or earlier");
134 | _connectors = new ConnectorProviderV3();
135 | }
136 | else
137 | {
138 | Logger?.Trace("Hardware is 3.e or later");
139 | _connectors = new ConnectorProviderV3e(this, i2cBus);
140 | }
141 | }
142 |
143 | ///
144 | protected override IPixelDisplay? GetDefaultDisplay()
145 | {
146 | DisplayEnablePort ??= Mcp_1?.CreateDigitalOutputPort(Mcp_1.Pins.GP4, false);
147 |
148 | if (_display == null)
149 | {
150 | Logger?.Trace("Instantiating display");
151 |
152 | var chipSelectPort = DisplayHeader.Pins.DISPLAY_CS.CreateDigitalOutputPort();
153 | var dcPort = DisplayHeader.Pins.DISPLAY_DC.CreateDigitalOutputPort();
154 | var resetPort = DisplayHeader.Pins.DISPLAY_RST.CreateDigitalOutputPort();
155 |
156 | Thread.Sleep(50);
157 |
158 | _display = new Ili9341(
159 | spiBus: DisplayHeader.SpiBusDisplay,
160 | chipSelectPort: chipSelectPort,
161 | dataCommandPort: dcPort,
162 | resetPort: resetPort,
163 | width: 240, height: 320,
164 | colorMode: ColorMode.Format12bppRgb444)
165 | {
166 | SpiBusMode = SpiClockConfiguration.Mode.Mode3,
167 | SpiBusSpeed = new Frequency(24000, Frequency.UnitType.Kilohertz)
168 | };
169 |
170 | ((Ili9341)_display).SetRotation(RotationType._270Degrees);
171 |
172 | Logger?.Trace("Display up");
173 | }
174 |
175 | return _display;
176 | }
177 |
178 | private IToneGenerator? GetSpeaker()
179 | {
180 | if (_speaker == null)
181 | {
182 | try
183 | {
184 | Logger?.Trace("Instantiating speaker");
185 | _speaker = new PiezoSpeaker(_device.Pins.PA0);
186 | Logger?.Trace("Speaker up");
187 | }
188 | catch (Exception ex)
189 | {
190 | Logger?.Error($"Unable to create the Piezo Speaker: {ex.Message}");
191 | }
192 | }
193 |
194 | return _speaker;
195 | }
196 |
197 | private IRgbPwmLed? GetRgbLed()
198 | {
199 | if (_rgbled == null)
200 | {
201 | try
202 | {
203 | Logger?.Trace("Instantiating RGB LED");
204 | _rgbled = new RgbPwmLed(
205 | redPwmPin: _device.Pins.PC6,
206 | greenPwmPin: _device.Pins.PC7,
207 | bluePwmPin: _device.Pins.PC9,
208 | CommonType.CommonAnode);
209 | Logger?.Trace("RGB LED up");
210 | }
211 | catch (Exception ex)
212 | {
213 | Logger?.Error($"Unable to create the RGB LED: {ex.Message}");
214 | }
215 | }
216 |
217 | return _rgbled;
218 | }
219 |
220 | internal override MikroBusConnector CreateMikroBus1()
221 | {
222 | Logger?.Trace("Creating MikroBus1 connector");
223 | return _connectors.CreateMikroBus1(_device, Mcp_2!);
224 | }
225 |
226 | internal override MikroBusConnector CreateMikroBus2()
227 | {
228 | Logger?.Trace("Creating MikroBus2 connector");
229 | return _connectors.CreateMikroBus2(_device, Mcp_2!);
230 | }
231 |
232 | internal override GroveDigitalConnector? CreateGroveDigitalConnector()
233 | {
234 | Logger?.Trace("Creating Grove digital connector");
235 |
236 | return new GroveDigitalConnector(
237 | nameof(GroveDigital),
238 | new PinMapping
239 | {
240 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.D16),
241 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, _device.Pins.D17),
242 | });
243 | }
244 |
245 | internal override GroveDigitalConnector CreateGroveAnalogConnector()
246 | {
247 | Logger?.Trace("Creating Grove analog connector");
248 |
249 | return new GroveDigitalConnector(
250 | nameof(GroveAnalog),
251 | new PinMapping
252 | {
253 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.PA4),
254 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, _device.Pins.PA5),
255 | });
256 | }
257 |
258 | internal override UartConnector CreateGroveUartConnector()
259 | {
260 | Logger?.Trace("Creating Grove UART connector");
261 |
262 | return new UartConnector(
263 | nameof(GroveUart),
264 | new PinMapping
265 | {
266 | new PinMapping.PinAlias(UartConnector.PinNames.RX, _device.Pins.PI9),
267 | new PinMapping.PinAlias(UartConnector.PinNames.TX, _device.Pins.PH13),
268 | },
269 | _device.PlatformOS.GetSerialPortName("com4")!);
270 | }
271 |
272 | internal override I2cConnector CreateQwiicConnector()
273 | {
274 | Logger?.Trace("Creating Qwiic I2C connector");
275 |
276 | return new I2cConnector(
277 | nameof(Qwiic),
278 | new PinMapping
279 | {
280 | new PinMapping.PinAlias(I2cConnector.PinNames.SCL, _device.Pins.PB6),
281 | new PinMapping.PinAlias(I2cConnector.PinNames.SDA, _device.Pins.PB7),
282 | },
283 | new I2cBusMapping(_device, 1));
284 | }
285 |
286 | internal override IOTerminalConnector CreateIOTerminalConnector()
287 | {
288 | Logger?.Trace("Creating IO terminal connector");
289 |
290 | return new IOTerminalConnector(
291 | nameof(IOTerminal),
292 | new PinMapping
293 | {
294 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.A1, _device.Pins.PB1),
295 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D2, Mcp_2!.Pins.GP6),
296 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D3, Mcp_2.Pins.GP5),
297 | });
298 | }
299 |
300 | internal override DisplayConnector CreateDisplayConnector()
301 | {
302 | Logger?.Trace("Creating display connector");
303 |
304 | return new DisplayConnector(
305 | nameof(Display),
306 | new PinMapping
307 | {
308 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CS, Mcp_1!.Pins.GP5),
309 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_RST, Mcp_1.Pins.GP7),
310 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_DC, Mcp_1.Pins.GP6),
311 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CLK, _device.Pins.SCK),
312 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_COPI, _device.Pins.COPI),
313 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_LED, Mcp_1!.Pins.GP4),
314 | },
315 | new SpiBusMapping(_device, _device.Pins.SCK, _device.Pins.COPI, _device.Pins.CIPO));
316 | }
317 |
318 | private byte? _revisionNumber;
319 | ///
320 | /// The hardware revision number, read from the on-board MCP
321 | ///
322 | protected byte RevisionNumber
323 | {
324 | get
325 | {
326 | _revisionNumber ??= Mcp_Version?.ReadFromPorts(Mcp23xxx.PortBank.A) ?? 0;
327 | return _revisionNumber.Value;
328 | }
329 | }
330 |
331 | private string? _revisionString;
332 | ///
333 | public override string RevisionString
334 | {
335 | get
336 | {
337 | return _revisionString ??= $"v3.{(Mcp_Version == null ? "x" : RevisionNumber)}";
338 | }
339 | }
340 |
341 | ///
342 | public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
343 | {
344 | return _connectors.GetModbusRtuClient(this, baudRate, dataBits, parity, stopBits);
345 | }
346 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabHardwareV4.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Foundation.Audio;
2 | using Meadow.Foundation.Displays;
3 | using Meadow.Foundation.ICs.IOExpanders;
4 | using Meadow.Foundation.Leds;
5 | using Meadow.Foundation.Sensors.Buttons;
6 | using Meadow.Foundation.Sensors.Hid;
7 | using Meadow.Hardware;
8 | using Meadow.Modbus;
9 | using Meadow.Peripherals.Displays;
10 | using Meadow.Peripherals.Leds;
11 | using Meadow.Peripherals.Sensors.Buttons;
12 | using Meadow.Peripherals.Speakers;
13 | using Meadow.Units;
14 | using System;
15 | using System.Diagnostics;
16 | using System.Threading;
17 |
18 | namespace Meadow.Devices;
19 |
20 | ///
21 | /// Represents Project Lab V4 hardware and exposes its peripherals
22 | ///
23 | public class ProjectLabHardwareV4 : ProjectLabHardwareBase
24 | {
25 | private readonly IF7CoreComputeMeadowDevice _device;
26 | private IToneGenerator? _speaker;
27 | private IRgbPwmLed? _rgbled;
28 | private IPixelDisplay? _display;
29 | private ITouchScreen? _touchscreen;
30 |
31 | ///
32 | /// The MCP23008 IO expander connected to internal peripherals on Project Lab
33 | ///
34 | public Mcp23008? Mcp_1 { get; protected set; }
35 |
36 | ///
37 | /// The MCP23008 IO expander connected to IO headers and terminals on Project Lab
38 | ///
39 | public Mcp23008? Mcp_2 { get; protected set; }
40 |
41 | ///
42 | /// The MCP23008 IO expander that contains the ProjectLab hardware version
43 | ///
44 | private Mcp23008? Mcp_Version { get; set; }
45 |
46 | ///
47 | public override IButton? UpButton { get; }
48 |
49 | ///
50 | public override IButton? DownButton { get; }
51 |
52 | ///
53 | public override IButton? LeftButton { get; }
54 |
55 | ///
56 | public override IButton? RightButton { get; }
57 |
58 | ///
59 | public override IToneGenerator? Speaker => GetSpeaker();
60 |
61 | ///
62 | public override IRgbPwmLed? RgbLed => GetRgbLed();
63 |
64 | private readonly Sc16is752 _uartExpander;
65 |
66 | ///
67 | /// Display enable port
68 | ///
69 | public IDigitalOutputPort? DisplayEnablePort { get; protected set; }
70 |
71 | ///
72 | /// Display backliight port for backlight control
73 | ///
74 | public IDigitalOutputPort? DisplayLedPort { get; protected set; }
75 |
76 | internal ProjectLabHardwareV4(IF7CoreComputeMeadowDevice device, II2cBus i2cBus)
77 | : base(device, i2cBus)
78 | {
79 | _device = device;
80 |
81 | IDigitalInterruptPort? mcp1Interrupt = null;
82 | IDigitalOutputPort? mcp1Reset = null;
83 |
84 | try
85 | {
86 | mcp1Interrupt = device.CreateDigitalInterruptPort(device.Pins.PC0, InterruptMode.EdgeRising);
87 |
88 | mcp1Reset = device.CreateDigitalOutputPort(device.Pins.PA10);
89 |
90 | Mcp_1 = new Mcp23008(i2cBus, address: 0x20, mcp1Interrupt, mcp1Reset);
91 |
92 | Logger?.Trace("Mcp_1 up");
93 | }
94 | catch (Exception e)
95 | {
96 | Logger?.Trace($"Failed to create MCP1: {e.Message}");
97 | mcp1Interrupt?.Dispose();
98 | }
99 |
100 | IDigitalInterruptPort? mcp2Interrupt = null;
101 |
102 | try
103 | {
104 | mcp2Interrupt = device.CreateDigitalInterruptPort(device.Pins.PC8, InterruptMode.EdgeRising);
105 |
106 | Mcp_2 = new Mcp23008(i2cBus, address: 0x21, mcp2Interrupt);
107 |
108 | Logger?.Trace("Mcp_2 up");
109 | }
110 | catch (Exception e)
111 | {
112 | Logger?.Trace($"Failed to create MCP2: {e.Message}");
113 | mcp2Interrupt?.Dispose();
114 | }
115 |
116 | try
117 | {
118 | Mcp_Version = new Mcp23008(i2cBus, address: 0x27);
119 | Logger?.Trace("Mcp_Version up");
120 | }
121 | catch (Exception e)
122 | {
123 | Logger?.Trace($"ERR creating the MCP that has version information: {e.Message}");
124 | }
125 |
126 | Logger?.Trace("Instantiating buttons");
127 | var leftPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP2, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
128 | if (leftPort != null) LeftButton = new PushButton(leftPort);
129 | var rightPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP1, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
130 | if (rightPort != null) RightButton = new PushButton(rightPort);
131 | var upPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP0, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
132 | if (upPort != null) UpButton = new PushButton(upPort);
133 | var downPort = Mcp_1?.CreateDigitalInterruptPort(Mcp_1.Pins.GP3, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp);
134 | if (downPort != null) DownButton = new PushButton(downPort);
135 | Logger?.Trace("Buttons up");
136 |
137 | _uartExpander = new Sc16is752(i2cBus, new Frequency(1.8432, Frequency.UnitType.Megahertz), Sc16is7x2.Addresses.Address_0x4D);
138 | }
139 |
140 | ///
141 | protected override IPixelDisplay? GetDefaultDisplay()
142 | {
143 | DisplayEnablePort ??= Mcp_1?.CreateDigitalOutputPort(Mcp_1.Pins.GP4, false);
144 | DisplayLedPort ??= Mcp_1?.CreateDigitalOutputPort(DisplayHeader.Pins.DISPLAY_LED, true);
145 |
146 | if (_display == null)
147 | {
148 | Logger?.Trace("Instantiating display");
149 |
150 | var chipSelectPort = DisplayHeader.Pins.DISPLAY_CS.CreateDigitalOutputPort();
151 | var dcPort = DisplayHeader.Pins.DISPLAY_DC.CreateDigitalOutputPort();
152 | var resetPort = DisplayHeader.Pins.DISPLAY_RST.CreateDigitalOutputPort();
153 | Thread.Sleep(50);
154 |
155 | var spiBus5 = _device.CreateSpiBus(
156 | _device.Pins.SPI5_SCK,
157 | _device.Pins.SPI5_COPI,
158 | _device.Pins.SPI5_CIPO,
159 | new Frequency(24000, Frequency.UnitType.Kilohertz));
160 |
161 | _display = new Ili9341(
162 | spiBus: spiBus5,
163 | chipSelectPort: chipSelectPort,
164 | dataCommandPort: dcPort,
165 | resetPort: resetPort,
166 | width: 240, height: 320,
167 | colorMode: ColorMode.Format12bppRgb444)
168 | {
169 | SpiBusMode = SpiClockConfiguration.Mode.Mode3,
170 | SpiBusSpeed = new Frequency(24000, Frequency.UnitType.Kilohertz)
171 | };
172 |
173 | ((Ili9341)_display).SetRotation(RotationType._270Degrees);
174 | ((Ili9341)_display).InvertDisplayColor(true);
175 |
176 | Logger?.Trace("Display up");
177 | }
178 |
179 | return _display;
180 | }
181 |
182 | private IToneGenerator? GetSpeaker()
183 | {
184 | if (_speaker == null)
185 | {
186 | try
187 | {
188 | Logger?.Trace("Instantiating speaker");
189 | _speaker = new PiezoSpeaker(_device.Pins.PA0);
190 | Logger?.Trace("Speaker up");
191 | }
192 | catch (Exception ex)
193 | {
194 | Logger?.Error($"Unable to create the Piezo Speaker: {ex.Message}");
195 | }
196 | }
197 |
198 | return _speaker;
199 | }
200 |
201 | private IRgbPwmLed? GetRgbLed()
202 | {
203 | if (_rgbled == null)
204 | {
205 | try
206 | {
207 | Logger?.Trace("Instantiating RGB LED");
208 | _rgbled = new RgbPwmLed(
209 | redPwmPin: _device.Pins.PC6,
210 | greenPwmPin: _device.Pins.PC7,
211 | bluePwmPin: _device.Pins.PC9,
212 | CommonType.CommonAnode);
213 | Logger?.Trace("RGB LED up");
214 | }
215 | catch (Exception ex)
216 | {
217 | Logger?.Error($"Unable to create the RGB LED: {ex.Message}");
218 | }
219 | }
220 |
221 | return _rgbled;
222 | }
223 |
224 | internal override MikroBusConnector CreateMikroBus1()
225 | {
226 | Logger?.Trace("Creating MikroBus1 connector");
227 | Debug.Assert(Mcp_2 != null, nameof(Mcp_2) + " != null");
228 | return new MikroBusConnector(
229 | "MikroBus1",
230 | new PinMapping
231 | {
232 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.PA3),
233 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, _device.Pins.PH10),
234 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, _device.Pins.PB12),
235 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SPI5_SCK),
236 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.SPI5_CIPO),
237 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.SPI5_COPI),
238 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.PB8),
239 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, _device.Pins.PC2),
240 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, _device.Pins.PB15),
241 | new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, _device.Pins.PB14),
242 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C3_SCL),
243 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C3_SDA),
244 | },
245 | _device.PlatformOS.GetSerialPortName("com1")!,
246 | new I2cBusMapping(_device, 3),
247 | new SpiBusMapping(_device, _device.Pins.SPI5_SCK, _device.Pins.SPI5_COPI, _device.Pins.SPI5_CIPO)
248 | );
249 | }
250 |
251 | internal override MikroBusConnector CreateMikroBus2()
252 | {
253 | Logger?.Trace("Creating MikroBus2 connector");
254 | Debug.Assert(Mcp_2 != null, nameof(Mcp_2) + " != null");
255 | return new MikroBusConnector(
256 | "MikroBus2",
257 | new PinMapping
258 | {
259 | new PinMapping.PinAlias(MikroBusConnector.PinNames.AN, _device.Pins.PB0),
260 | new PinMapping.PinAlias(MikroBusConnector.PinNames.RST, Mcp_2.Pins.GP1),
261 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CS, Mcp_2.Pins.GP2),
262 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCK, _device.Pins.SPI3_SCK),
263 | new PinMapping.PinAlias(MikroBusConnector.PinNames.CIPO, _device.Pins.SPI3_CIPO),
264 | new PinMapping.PinAlias(MikroBusConnector.PinNames.COPI, _device.Pins.SPI3_COPI),
265 | new PinMapping.PinAlias(MikroBusConnector.PinNames.PWM, _device.Pins.PB9),
266 | new PinMapping.PinAlias(MikroBusConnector.PinNames.INT, Mcp_2.Pins.GP3),
267 | // new PinMapping.PinAlias(MikroBusConnector.PinNames.RX, uart1rx), // on the I2C uart and not usable for anything else
268 | // new PinMapping.PinAlias(MikroBusConnector.PinNames.TX, uart1tx), // on the I2C uart and not usable for anything else
269 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SCL, _device.Pins.I2C1_SCL),
270 | new PinMapping.PinAlias(MikroBusConnector.PinNames.SDA, _device.Pins.I2C1_SDA),
271 | },
272 | _device.PlatformOS.GetSerialPortName("com1")!,
273 | new I2cBusMapping(_device, 1),
274 | new SpiBusMapping(_device, _device.Pins.SPI3_SCK, _device.Pins.SPI3_COPI, _device.Pins.SPI3_CIPO)
275 | );
276 | }
277 |
278 | internal override GroveDigitalConnector? CreateGroveDigitalConnector()
279 | {
280 | Logger?.Trace("Creating Grove digital connector");
281 |
282 | return new GroveDigitalConnector(
283 | nameof(GroveDigital),
284 | new PinMapping
285 | {
286 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.PB4),
287 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, Mcp_2!.Pins.GP4),
288 | });
289 | }
290 |
291 | internal override GroveDigitalConnector CreateGroveAnalogConnector()
292 | {
293 | Logger?.Trace("Creating Grove analog connector");
294 |
295 | return new GroveDigitalConnector(
296 | nameof(GroveAnalog),
297 | new PinMapping
298 | {
299 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D0, _device.Pins.PA4),
300 | new PinMapping.PinAlias(GroveDigitalConnector.PinNames.D1, _device.Pins.PA5),
301 | });
302 | }
303 |
304 | internal override UartConnector CreateGroveUartConnector()
305 | {
306 | Logger?.Trace("Creating Grove UART connector");
307 |
308 | return new UartConnector(
309 | nameof(GroveUart),
310 | new PinMapping
311 | {
312 | new PinMapping.PinAlias(UartConnector.PinNames.RX, _device.Pins.PI9),
313 | new PinMapping.PinAlias(UartConnector.PinNames.TX, _device.Pins.PH13),
314 | },
315 | _device.PlatformOS.GetSerialPortName("com4")!);
316 | }
317 |
318 | internal override I2cConnector CreateQwiicConnector()
319 | {
320 | Logger?.Trace("Creating Qwiic I2C connector");
321 |
322 | return new I2cConnector(
323 | nameof(Qwiic),
324 | new PinMapping
325 | {
326 | new PinMapping.PinAlias(I2cConnector.PinNames.SCL, _device.Pins.PB6),
327 | new PinMapping.PinAlias(I2cConnector.PinNames.SDA, _device.Pins.PB7),
328 | },
329 | new I2cBusMapping(_device, 1));
330 | }
331 |
332 | internal override IOTerminalConnector CreateIOTerminalConnector()
333 | {
334 | Logger?.Trace("Creating IO terminal connector");
335 |
336 | return new IOTerminalConnector(
337 | nameof(IOTerminal),
338 | new PinMapping
339 | {
340 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.A1, _device.Pins.PB1),
341 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D2, Mcp_2!.Pins.GP6),
342 | new PinMapping.PinAlias(IOTerminalConnector.PinNames.D3, Mcp_2.Pins.GP5),
343 | });
344 | }
345 |
346 | internal override DisplayConnector CreateDisplayConnector()
347 | {
348 | Logger?.Trace("Creating display connector");
349 |
350 | return new DisplayConnector(
351 | nameof(Display),
352 | new PinMapping
353 | {
354 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CS, _device.Pins.PD5),
355 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_RST, _device.Pins.PB13),
356 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_DC, _device.Pins.PI11),
357 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_CLK, _device.Pins.SPI5_SCK),
358 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_COPI, _device.Pins.SPI5_COPI),
359 | new PinMapping.PinAlias(DisplayConnector.PinNames.DISPLAY_LED, Mcp_1!.Pins.GP5),
360 | new PinMapping.PinAlias(DisplayConnector.PinNames.TOUCH_INT, Mcp_2!.Pins.GP0),
361 | new PinMapping.PinAlias(DisplayConnector.PinNames.TOUCH_CS, Mcp_1.Pins.GP6),
362 | new PinMapping.PinAlias(DisplayConnector.PinNames.TOUCH_CLK, _device.Pins.SPI3_SCK),
363 | new PinMapping.PinAlias(DisplayConnector.PinNames.TOUCH_COPI, _device.Pins.SPI3_COPI),
364 | new PinMapping.PinAlias(DisplayConnector.PinNames.TOUCH_CIPO, _device.Pins.SPI3_CIPO),
365 | },
366 | new SpiBusMapping(_device, _device.Pins.SPI5_SCK, _device.Pins.SPI5_COPI, _device.Pins.SPI5_CIPO),
367 | new SpiBusMapping(_device, _device.Pins.SPI3_SCK, _device.Pins.SPI3_COPI, _device.Pins.SPI3_CIPO));
368 | }
369 |
370 | private byte? _revisionNumber;
371 | ///
372 | /// The hardware revision number, read from the on-board MCP
373 | ///
374 | protected byte RevisionNumber
375 | {
376 | get
377 | {
378 | _revisionNumber ??= Mcp_Version?.ReadFromPorts(Mcp23xxx.PortBank.A) ?? 0;
379 | return _revisionNumber.Value;
380 | }
381 | }
382 |
383 | private string? _revisionString;
384 | ///
385 | public override string RevisionString
386 | {
387 | get
388 | {
389 | return _revisionString ??= $"v4.{(Mcp_Version == null ? "x" : RevisionNumber)}";
390 | }
391 | }
392 |
393 | private ModbusRtuClient? _client;
394 |
395 | ///
396 | public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One)
397 | {
398 | if (_client == null)
399 | {
400 | try
401 | {
402 | Resolver.Log.Info($"Creating 485 port...", Constants.LogGroup);
403 |
404 | // v3.e+ uses an SC16is I2C UART expander for the RS485
405 | var port = _uartExpander.PortB.CreateRs485SerialPort(baudRate, dataBits, parity, stopBits, false);
406 | Resolver.Log.Trace($"485 port created", Constants.LogGroup);
407 | _client = new ModbusRtuClient(port);
408 | }
409 | catch (Exception ex)
410 | {
411 | Resolver.Log.Warn($"Error creating 485 port: {ex.Message}", Constants.LogGroup);
412 | throw new Exception("Unable to connect to UART expander");
413 | }
414 | }
415 | return _client;
416 | }
417 |
418 | ///
419 | public override ITouchScreen? Touchscreen
420 | {
421 | get
422 | {
423 | return _touchscreen ??= new Xpt2046(
424 | DisplayHeader.SpiBusDisplay,
425 | DisplayHeader.Pins.TOUCH_INT.CreateDigitalInterruptPort(InterruptMode.EdgeBoth, ResistorMode.Disabled),
426 | DisplayHeader.Pins.TOUCH_CS.CreateDigitalOutputPort(true),
427 | RotationType.Normal
428 | );
429 | }
430 | }
431 | }
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/ProjectLabModbusRtuClient.cs:
--------------------------------------------------------------------------------
1 | using Meadow.Hardware;
2 | using Meadow.Modbus;
3 | using System.Threading;
4 |
5 | namespace Meadow.Devices;
6 |
7 | ///
8 | /// Represents a Modbus RTU client customized for ProjectLab.
9 | ///
10 | public class ProjectLabModbusRtuClient : ModbusRtuClient
11 | {
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// The serial port for communication.
16 | /// The digital output port used for enable control.
17 | public ProjectLabModbusRtuClient(ISerialPort port, IDigitalOutputPort enablePort)
18 | : base(port, enablePort)
19 | {
20 | // this forces meadow to compile the serial pipeline. Without it, there's a big delay on sending the first byte
21 | PostOpenAction = () => { port.Write(new byte[] { 0x00 }); };
22 |
23 | // meadow is not-so-fast, and data will not all get transmitted before the call to the port Write() returns
24 | PostWriteDelayAction = (m) =>
25 | {
26 | var delay = (int)(1d / port.BaudRate * port.DataBits * 1000d * m.Length) + 3; // +3 to add just a little extra for clients who are a little slow to turn off the enable pin
27 | Thread.Sleep(delay);
28 | };
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/Meadow.ProjectLab/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildernessLabs/Meadow.ProjectLab/9ab658716c63b681e298b3fcb7ad5041677d1d7a/Source/Meadow.ProjectLab/icon.png
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/.vscode/launch.config:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Deploy",
9 | "type": "meadow",
10 | "request": "launch",
11 | "preLaunchTask": "meadow: Build"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/DisplayController.cs:
--------------------------------------------------------------------------------
1 | using Meadow;
2 | using Meadow.Foundation.Graphics;
3 | using Meadow.Foundation.Graphics.MicroLayout;
4 | using Meadow.Peripherals.Displays;
5 | using Meadow.Units;
6 |
7 | namespace ProjectLab_Demo;
8 |
9 | public class DisplayController
10 | {
11 | private readonly int rowOffset = 29;
12 | private readonly int rowHeight = 21;
13 | private readonly int rowMargin = 2;
14 |
15 | private Color foregroundColor = Color.White;
16 | private Color atmosphericColor = Color.White;
17 | private Color motionColor = Color.FromHex("23ABE3");
18 | private Color buttonColor = Color.FromHex("EF7D3B");
19 |
20 | private readonly Font12x20 font12X20 = new();
21 |
22 | private readonly DisplayScreen displayScreen;
23 |
24 | private readonly Label temperature;
25 | private readonly Label humidity;
26 | private readonly Label pressure;
27 | private readonly Label iluminance;
28 | private readonly Label acceleration3D;
29 | private readonly Label angularVelocity3D;
30 | private readonly Label buttonUp;
31 | private readonly Label buttonDown;
32 | private readonly Label buttonLeft;
33 | private readonly Label buttonRight;
34 |
35 | public DisplayController(IPixelDisplay display, string revisionVersion)
36 | {
37 | displayScreen = new DisplayScreen(display, RotationType._270Degrees)
38 | {
39 | BackgroundColor = Color.FromHex("0B3749")
40 | };
41 |
42 | displayScreen.Controls.Add(new Label(rowMargin, 4, displayScreen.Width, rowHeight)
43 | {
44 | Text = $"Hello PROJ LAB {revisionVersion}!",
45 | TextColor = foregroundColor,
46 | Font = font12X20,
47 | HorizontalAlignment = HorizontalAlignment.Center
48 | });
49 |
50 | displayScreen.Controls.Add(CreateLeftLabel("Temperature:", atmosphericColor, rowMargin, rowOffset, displayScreen.Width, rowHeight));
51 | displayScreen.Controls.Add(CreateLeftLabel("Pressure:", atmosphericColor, rowMargin, rowOffset + rowHeight, displayScreen.Width, rowHeight));
52 | displayScreen.Controls.Add(CreateLeftLabel("Humidity:", atmosphericColor, rowMargin, rowOffset + rowHeight * 2, displayScreen.Width, rowHeight));
53 | displayScreen.Controls.Add(CreateLeftLabel("Illuminance:", atmosphericColor, rowMargin, rowOffset + rowHeight * 3, displayScreen.Width, rowHeight));
54 | displayScreen.Controls.Add(CreateLeftLabel("Accel:", motionColor, rowMargin, rowOffset + rowHeight * 4, displayScreen.Width, rowHeight));
55 | displayScreen.Controls.Add(CreateLeftLabel("Gyro:", motionColor, rowMargin, rowOffset + rowHeight * 5, displayScreen.Width, rowHeight));
56 | displayScreen.Controls.Add(CreateLeftLabel("Up:", buttonColor, rowMargin, rowOffset + rowHeight * 6, displayScreen.Width, rowHeight));
57 | displayScreen.Controls.Add(CreateLeftLabel("Down:", buttonColor, rowMargin, rowOffset + rowHeight * 7, displayScreen.Width, rowHeight));
58 | displayScreen.Controls.Add(CreateLeftLabel("Left:", buttonColor, rowMargin, rowOffset + rowHeight * 8, displayScreen.Width, rowHeight));
59 | displayScreen.Controls.Add(CreateLeftLabel("Right:", buttonColor, rowMargin, rowOffset + rowHeight * 9, displayScreen.Width, rowHeight));
60 |
61 | temperature = CreateRightLabel("0ºC", atmosphericColor, rowMargin, rowOffset, displayScreen.Width - rowMargin * 2, rowHeight);
62 | pressure = CreateRightLabel("0atm", atmosphericColor, rowMargin, rowOffset + rowHeight, displayScreen.Width - rowMargin * 2, rowHeight);
63 | humidity = CreateRightLabel("0%", atmosphericColor, rowMargin, rowOffset + rowHeight * 2, displayScreen.Width - rowMargin * 2, rowHeight);
64 | iluminance = CreateRightLabel("0Lux", atmosphericColor, rowMargin, rowOffset + rowHeight * 3, displayScreen.Width - rowMargin * 2, rowHeight);
65 | acceleration3D = CreateRightLabel("0,0,0g", motionColor, rowMargin, rowOffset + rowHeight * 4, displayScreen.Width - rowMargin * 2, rowHeight);
66 | angularVelocity3D = CreateRightLabel("0,0,0rpm", motionColor, rowMargin, rowOffset + rowHeight * 5, displayScreen.Width - rowMargin * 2, rowHeight);
67 | buttonUp = CreateRightLabel("Released", buttonColor, rowMargin, rowOffset + rowHeight * 6, displayScreen.Width - rowMargin * 2, rowHeight);
68 | buttonDown = CreateRightLabel("Released", buttonColor, rowMargin, rowOffset + rowHeight * 7, displayScreen.Width - rowMargin * 2, rowHeight);
69 | buttonLeft = CreateRightLabel("Released", buttonColor, rowMargin, rowOffset + rowHeight * 8, displayScreen.Width - rowMargin * 2, rowHeight);
70 | buttonRight = CreateRightLabel("Released", buttonColor, rowMargin, rowOffset + rowHeight * 9, displayScreen.Width - rowMargin * 2, rowHeight);
71 |
72 | displayScreen.Controls.Add(new[] { temperature, pressure, humidity, iluminance, acceleration3D, angularVelocity3D, buttonUp, buttonDown, buttonLeft, buttonRight });
73 | }
74 |
75 | private Label CreateLeftLabel(string text, Color color, int left, int top, int width, int height)
76 | {
77 | return new Label(left, top, width, height)
78 | {
79 | Text = text,
80 | TextColor = color,
81 | Font = font12X20,
82 | HorizontalAlignment = HorizontalAlignment.Left
83 | };
84 | }
85 |
86 | private Label CreateRightLabel(string text, Color color, int left, int top, int width, int height)
87 | {
88 | return new Label(left, top, width, height)
89 | {
90 | Text = text,
91 | TextColor = color,
92 | Font = font12X20,
93 | HorizontalAlignment = HorizontalAlignment.Right
94 | };
95 | }
96 |
97 | public void UpdateTemperatureValue(Temperature temperature, Temperature temperature2)
98 | {
99 | this.temperature.Text = $"{temperature2.Celsius:N1}ºC/{temperature.Celsius:N1}ºC";
100 | }
101 |
102 | public void UpdatePressureValue(Pressure pressure)
103 | {
104 | this.pressure.Text = $"{pressure.StandardAtmosphere:N1}atm";
105 | }
106 |
107 | public void UpdateHumidityValue(RelativeHumidity humidity)
108 | {
109 | this.humidity.Text = $"{humidity.Percent:N1}%";
110 | }
111 |
112 | public void UpdateIluminanceValue(Illuminance iluminance)
113 | {
114 | this.iluminance.Text = $"{iluminance.Lux:N1}Lux";
115 | }
116 |
117 | public void UpdateAcceleration3DValue(Acceleration3D acceleration3D)
118 | {
119 | this.acceleration3D.Text = $"{acceleration3D.X.Gravity:N1},{acceleration3D.Y.Gravity:N1},{acceleration3D.Z.Gravity:N1}g";
120 | }
121 |
122 | public void UpdateAngularVelocity3DValue(AngularVelocity3D angularVelocity3D)
123 | {
124 | this.angularVelocity3D.Text = $"{angularVelocity3D.X.DegreesPerSecond:N0},{angularVelocity3D.Y.DegreesPerSecond:N0},{angularVelocity3D.Z.DegreesPerSecond:N0}º/s";
125 | }
126 |
127 | public void UpdateButtonUp(bool isPressed)
128 | {
129 | Resolver.Log.Info($"Button Up: {isPressed}");
130 | buttonUp.Text = isPressed ? "Pressed" : "Released";
131 | }
132 |
133 | public void UpdateButtonDown(bool isPressed)
134 | {
135 | Resolver.Log.Info($"Button Down: {isPressed}");
136 | buttonDown.Text = isPressed ? "Pressed" : "Released";
137 | }
138 |
139 | public void UpdateButtonLeft(bool isPressed)
140 | {
141 | Resolver.Log.Info($"Button Left: {isPressed}");
142 | buttonLeft.Text = isPressed ? "Pressed" : "Released";
143 | }
144 |
145 | public void UpdateButtonRight(bool isPressed)
146 | {
147 | Resolver.Log.Info($"Button Right: {isPressed}");
148 | buttonRight.Text = isPressed ? "Pressed" : "Released";
149 | }
150 | }
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/MeadowApp.cs:
--------------------------------------------------------------------------------
1 | using Meadow;
2 | using Meadow.Devices;
3 | using Meadow.Foundation;
4 | using Meadow.Foundation.Audio;
5 | using Meadow.Units;
6 | using System;
7 | using System.Threading.Tasks;
8 |
9 | namespace ProjectLab_Demo;
10 |
11 | // Change to ProjectLabFeatherApp for Project Lab V1 or V2
12 | // Change to ProjectLabCoreComputeApp for Project Lab V3+
13 | public class MeadowApp : ProjectLabCoreComputeApp
14 | {
15 | private DisplayController? displayController;
16 |
17 | private MicroAudio? audio;
18 |
19 | public override Task Initialize()
20 | {
21 | Resolver.Log.LogLevel = Meadow.Logging.LogLevel.Trace;
22 |
23 | Resolver.Log.Info($"Running on ProjectLab Hardware {Hardware.RevisionString}");
24 |
25 | if (Hardware.RgbLed is { } rgbLed)
26 | {
27 | rgbLed.SetColor(Color.Blue);
28 | }
29 |
30 | if (Hardware.Display is { } display)
31 | {
32 | Resolver.Log.Trace("Creating DisplayController");
33 | displayController = new DisplayController(display, Hardware.RevisionString);
34 | Resolver.Log.Trace("DisplayController up");
35 | }
36 |
37 | if (Hardware.Speaker is { } speaker)
38 | {
39 | speaker.SetVolume(0.2f);
40 | audio = new MicroAudio(speaker);
41 | }
42 |
43 | if (Hardware.TemperatureSensor is { } temperatureSensor)
44 | {
45 | temperatureSensor.Updated += OnTemperatureSensorUpdated;
46 | }
47 | if (Hardware.BarometricPressureSensor is { } pressureSensor)
48 | {
49 | pressureSensor.Updated += OnPressureSensorUpdated;
50 | }
51 | if (Hardware.HumiditySensor is { } humiditySensor)
52 | {
53 | humiditySensor.Updated += OnHumiditySensorUpdated;
54 | }
55 | if (Hardware.LightSensor is { } lightSensor)
56 | {
57 | lightSensor.Updated += OnLightSensorUpdated;
58 | }
59 |
60 | if (Hardware.Accelerometer is { } accelerometer)
61 | {
62 | accelerometer.Updated += OnAccelerometerUpdated;
63 | }
64 | if (Hardware.Gyroscope is { } gyroscope)
65 | {
66 | gyroscope.Updated += OnGyroscopeUpdated;
67 | }
68 |
69 | if (Hardware.UpButton is { } upButton)
70 | {
71 | upButton.PressStarted += (s, e) => displayController!.UpdateButtonUp(true);
72 | upButton.PressEnded += (s, e) => displayController!.UpdateButtonUp(false);
73 | }
74 | if (Hardware.DownButton is { } downButton)
75 | {
76 | downButton.PressStarted += (s, e) => displayController!.UpdateButtonDown(true);
77 | downButton.PressEnded += (s, e) => displayController!.UpdateButtonDown(false);
78 | }
79 | if (Hardware.LeftButton is { } leftButton)
80 | {
81 | leftButton.PressStarted += (s, e) => displayController!.UpdateButtonLeft(true);
82 | leftButton.PressEnded += (s, e) => displayController!.UpdateButtonLeft(false);
83 | }
84 | if (Hardware.RightButton is { } rightButton)
85 | {
86 | rightButton.PressStarted += (s, e) => displayController!.UpdateButtonRight(true);
87 | rightButton.PressEnded += (s, e) => displayController!.UpdateButtonRight(false);
88 | }
89 |
90 | if (Hardware.Touchscreen is { } touchScreen)
91 | {
92 | touchScreen.TouchDown += (s, e) =>
93 | {
94 | Resolver.Log.Info("touch screen down");
95 | };
96 | touchScreen.TouchUp += (s, e) =>
97 | {
98 | Resolver.Log.Info("touch screen up");
99 | };
100 | }
101 |
102 | Resolver.Log.Info("Initialization complete");
103 |
104 | return base.Initialize();
105 | }
106 |
107 | private void OnTemperatureSensorUpdated(object sender, IChangeResult e)
108 | {
109 | Resolver.Log.Info($"TEMPERATURE: {e.New.Celsius:N1}C");
110 | displayController!.UpdateTemperatureValue(e.New, Hardware.TemperatureSensor2?.Temperature ?? new Temperature(0));
111 | }
112 |
113 | private void OnPressureSensorUpdated(object sender, IChangeResult e)
114 | {
115 | Resolver.Log.Info($"PRESSURE: {e.New.Millibar:N1}mbar");
116 | displayController!.UpdatePressureValue(e.New);
117 | }
118 |
119 | private void OnHumiditySensorUpdated(object sender, IChangeResult e)
120 | {
121 | Resolver.Log.Info($"HUMIDITY: {e.New.Percent:N1}%");
122 | displayController!.UpdateHumidityValue(e.New);
123 | }
124 |
125 | private void OnLightSensorUpdated(object sender, IChangeResult e)
126 | {
127 | Resolver.Log.Info($"LIGHT: {e.New.Lux:N1}lux");
128 | displayController!.UpdateIluminanceValue(e.New);
129 | }
130 |
131 | private void OnAccelerometerUpdated(object sender, IChangeResult e)
132 | {
133 | Resolver.Log.Info($"ACCEL: {e.New.X.Gravity:N1}, {e.New.Y.Gravity:N1}, {e.New.Z.Gravity:N1}g");
134 | displayController!.UpdateAcceleration3DValue(e.New);
135 | }
136 |
137 | private void OnGyroscopeUpdated(object sender, IChangeResult e)
138 | {
139 | Resolver.Log.Info($"GYRO: {e.New.X.DegreesPerSecond:N0}, {e.New.Y.DegreesPerSecond:N0}, {e.New.Z.DegreesPerSecond:N0}deg/s");
140 | displayController!.UpdateAngularVelocity3DValue(e.New);
141 | }
142 |
143 | public override async Task Run()
144 | {
145 | Resolver.Log.Info("Run...");
146 |
147 | var updateInterveral = TimeSpan.FromSeconds(5);
148 |
149 | if (audio != null)
150 | {
151 | await audio.PlaySystemSound(SystemSoundEffect.Success);
152 | }
153 |
154 | if (Hardware?.TemperatureSensor is { } temperature)
155 | {
156 | temperature.StartUpdating(updateInterveral);
157 | }
158 | if (Hardware?.BarometricPressureSensor is { } barometer)
159 | {
160 | barometer.StartUpdating(updateInterveral);
161 | }
162 | if (Hardware?.HumiditySensor is { } humidity)
163 | {
164 | humidity.StartUpdating(updateInterveral);
165 | }
166 | if (Hardware?.LightSensor is { } luminance)
167 | {
168 | luminance.StartUpdating(updateInterveral);
169 | }
170 |
171 | if (Hardware?.Accelerometer is { } accelerometer)
172 | {
173 | accelerometer.StartUpdating(updateInterveral);
174 | }
175 | if (Hardware?.Gyroscope is { } gyroscope)
176 | {
177 | gyroscope.StartUpdating(updateInterveral);
178 | }
179 |
180 | if (Hardware?.RgbLed is { } rgbLed)
181 | {
182 | Resolver.Log.Info("starting blink");
183 | _ = rgbLed.StartBlink(WildernessLabsColors.PearGreen, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(2000), 0.5f);
184 | }
185 | }
186 | }
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/ProjectLab_Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.1
4 | true
5 | Library
6 | App
7 | Wilderness Labs, Inc
8 | Wilderness Labs, Inc
9 | Apache-2.0
10 | enable
11 | 10.0
12 |
13 |
14 |
15 | Always
16 |
17 |
18 | PreserveNewest
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/app.build.yaml:
--------------------------------------------------------------------------------
1 | Deploy:
2 | NoLink: [ ProjectLab ]
--------------------------------------------------------------------------------
/Source/ProjectLab_Demo/app.config.yaml:
--------------------------------------------------------------------------------
1 | # Uncomment additional options as needed.
2 | # To learn more about these config options, including custom application configuration settings, check out the Application Settings Configuration documentation.
3 | # http://developer.wildernesslabs.co/Meadow/Meadow.OS/Configuration/Application_Settings_Configuration/
4 |
5 | # App lifecycle configuration.
6 | Lifecycle:
7 |
8 | # Control whether Meadow will restart when an unhandled app exception occurs. Combine with Lifecycle > AppFailureRestartDelaySeconds to control restart timing.
9 | RestartOnAppFailure: false
10 |
11 | # When app set to restart automatically on app failure,
12 | # AppFailureRestartDelaySeconds: 15
13 |
14 | # Logging configuration.
15 | Logging:
16 |
17 | # Adjust the level of logging detail.
18 | LogLevel:
19 |
20 | # Trace, Debug, Information, Warning, or Error
21 | Default: Trace
22 |
--------------------------------------------------------------------------------