From: Ummon Date: Sun, 3 Jul 2016 19:58:12 +0000 (+0200) Subject: First commit. X-Git-Url: http://git.euphorik.ch/?a=commitdiff_plain;ds=sidebyside;p=PiNet.git First commit. --- 19a33a580f8948f3c8e00f62ff40496bda34ae31 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a89803 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.fake/ +.paket/ +paket.lock +packages/ +*.so +obj +bin +build/ \ No newline at end of file diff --git a/PiNet/App.config b/PiNet/App.config new file mode 100644 index 0000000..3661651 --- /dev/null +++ b/PiNet/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PiNet/AssemblyInfo.fs b/PiNet/AssemblyInfo.fs new file mode 100644 index 0000000..108b5ac --- /dev/null +++ b/PiNet/AssemblyInfo.fs @@ -0,0 +1,41 @@ +namespace PiNet.AssemblyInfo + +open System.Reflection +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[] +[] +[] +[] +[] +[] +[] +[] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [] +[] +[] + +do + () \ No newline at end of file diff --git a/PiNet/EtoUtils.fs b/PiNet/EtoUtils.fs new file mode 100644 index 0000000..f6a9427 --- /dev/null +++ b/PiNet/EtoUtils.fs @@ -0,0 +1,40 @@ +module EtoUtils + +open System +open Eto +open Eto.Forms +open Eto.Drawing + +type TCell = +| El of Control +| StretchedEl of Control +| EmptyElement +| TableEl of Table + +and TRow = +| Row of TCell list +| StretchedRow of TCell list +| Spacing of Size +| Pad of Padding + +and Table = Tbl of TRow list + +let rec makeLayout (Tbl t) = + let ret = new TableLayout() + for r in t do + // Build one row of the table. + let makeTd (tds: TCell list) = + let row = TableRow() + for td in tds do + match td with + | El c -> row.Cells.Add(TableCell(c, false)) + | StretchedEl c -> row.Cells.Add(TableCell(c, true)) + | EmptyElement -> row.Cells.Add(TableCell(null, true)) + | TableEl t -> row.Cells.Add(TableCell(makeLayout t, true)) + row + match r with + | Row tds -> let r = makeTd tds in ret.Rows.Add(r) + | StretchedRow tds -> let r = makeTd tds in r.ScaleHeight <- true; ret.Rows.Add(r) + | Spacing sz -> ret.Spacing <- sz + | Pad pad -> ret.Padding <- pad + ret \ No newline at end of file diff --git a/PiNet/PiNet.fsproj b/PiNet/PiNet.fsproj new file mode 100644 index 0000000..0b16902 --- /dev/null +++ b/PiNet/PiNet.fsproj @@ -0,0 +1,108 @@ + + + + PiNet + PiNet + PiNet + Debug + AnyCPU + 2.0 + 274c6bcd-9088-463a-8725-d23b7f60de89 + + Exe + v4.5 + + true + 4.3.1.0 + + + + true + Full + false + false + bin\Debug\ + DEBUGTRACE + 3 + AnyCPU + true + + + + + PdbOnly + true + true + bin\Release\ + TRACE + 3 + AnyCPU + true + + + + + + True + + + + + + + ..\packages\Eto.Forms\lib\net45\Eto.dll + + + ..\packages\Eto.Platform.Gtk3\lib\net45\Eto.Gtk3.dll + + + + ..\packages\GtkSharp\lib\net45\atk-sharp.dll + + + ..\packages\GtkSharp\lib\net45\cairo-sharp.dll + + + ..\packages\GtkSharp\lib\net45\gdk-sharp.dll + + + ..\packages\GtkSharp\lib\net45\gio-sharp.dll + + + ..\packages\GtkSharp\lib\net45\glib-sharp.dll + + + ..\packages\GtkSharp\lib\net45\gtk-sharp.dll + + + ..\packages\GtkSharp\lib\net45\pango-sharp.dll + + + ..\packages\npgsql\lib\net45\npgsql.dll + + + ..\packages\FsControl\lib\net40\FsControl.dll + + + + + + + + + + + + + $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets + + + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets + + + + + + \ No newline at end of file diff --git a/PiNet/Program.fs b/PiNet/Program.fs new file mode 100644 index 0000000..5650def --- /dev/null +++ b/PiNet/Program.fs @@ -0,0 +1,46 @@ +module PiNet + +open System +open System.Collections.Generic +open Eto +open Eto.Forms +open Eto.Drawing +open EtoUtils +open FsControl.Operators + +type Tree<'t> = + | Tree of 't * Tree<'t> * Tree<'t> + | Leaf of 't + static member Map (x:Tree<'a>, f) = + let rec loop f = function + | Leaf x -> Leaf (f x) + | Tree (x, t1, t2) -> Tree (f x, loop f t1, loop f t2) + loop f x + +[] +let main argv = + printfn "PiNet starting ..." + + let myTree = Tree(6, Tree(2, Leaf 1, Leaf 3), Leaf 9) + printfn "tree: %A" <| map float myTree + + use app = new Application() + use form = new Form(Title = "Hello world", Topmost = true, Size = Size(320, 240)) + let mutable counter = 0 + let button = new Button(Text = "+1") + let display = new Label(Text = string counter) + let table = Tbl [ Row [ El display ]; Row [ El button ] ] + let updateCounter c = counter <- c; display.Text <- string c + button.Click.Add(fun _ -> updateCounter (counter + 1)) + form.Content <- table |> makeLayout + form.Show() + + app.Run(form) + + // let asyncBuilder = Sensor.start () + // asyncBuilder |> Async.RunSynchronously + + printfn "PiNet stopped" + + 0 + diff --git a/PiNet/Sensor.fs b/PiNet/Sensor.fs new file mode 100644 index 0000000..8ae206f --- /dev/null +++ b/PiNet/Sensor.fs @@ -0,0 +1,72 @@ +module Sensor + +open System +open System.Runtime.InteropServices +open Npgsql + +module Data = + [] + extern void getHumidityAndTemperature(double& h, double& t) + + [] + extern bool init() + +let interval = 10000. // [ms]. + +let start () = + printfn "Sensor service starting ..." + + // Initialize the sensor. + if not <| Data.init() + then + failwith "Unable to initialize sensor" + + let conn = new NpgsqlConnection("Host=192.168.1.6;Username=pinet;Password=nidKuds7;Database=pinet") + conn.Open() + + let cmdInsert = + new NpgsqlCommand( + """INSERT INTO sensor_measure + (datetime, humidity, temperature) + VALUES (@d, @h, @t)""", conn) + + async { + while true do + let time = DateTime.UtcNow + + let humidity, temp = + let mutable h = 0.0 + let mutable t = 0.0 + Data.getHumidityAndTemperature(&h, &t) + h, t + + cmdInsert.Parameters.Clear() + cmdInsert.Parameters.AddWithValue("@d", DateTime.UtcNow) |> ignore + cmdInsert.Parameters.AddWithValue("@h", humidity) |> ignore + cmdInsert.Parameters.AddWithValue("@t", temp) |> ignore + + if cmdInsert.ExecuteNonQuery() <> 1 + then + printfn "Unable to insert values into the DB" + + let delta = (DateTime.UtcNow - time).TotalMilliseconds + let toWait = + let t = interval - delta + int <| if t < 0. then 0. else t + + do! Async.Sleep(toWait) + } + + (*use cmd = new NpgsqlCommand("SELECT id, datetime, humidity, temperature FROM sensor_measure", conn) + + use reader = cmd.ExecuteReader() + while reader.Read() do + printfn + "id: %d, datetime: %A, humidity: %.1f, temperature: %.1f" + (reader.GetInt32(0)) (reader.GetDateTime(1)) (reader.GetFloat(2)) (reader.GetFloat(3)) + 0 + + + printfn "Humidity: %.1f, Temperature: %.1f" humidity temp + + 0*) \ No newline at end of file diff --git a/Sensor/AM2302.pdf b/Sensor/AM2302.pdf new file mode 100644 index 0000000..a2e3d52 Binary files /dev/null and b/Sensor/AM2302.pdf differ diff --git a/Sensor/build.sh b/Sensor/build.sh new file mode 100644 index 0000000..0017f6d --- /dev/null +++ b/Sensor/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +g++ --std=c++14 -O2 -shared -o libsensor.so main.cpp -l bcm2835 +cp libsensor.so ../PiNet/bin/Release/ diff --git a/Sensor/main.cpp b/Sensor/main.cpp new file mode 100644 index 0000000..ec6b98a --- /dev/null +++ b/Sensor/main.cpp @@ -0,0 +1,132 @@ +/* + * Author: greg.burri@gmail.com + * libbcm2835 documentation : http://www.airspayce.com/mikem/bcm2835/index.html + */ + +#include +#include +#include +using namespace std; + +const auto pin = RPI_GPIO_P1_07; +const double temperatureMax = 60; +const double temperatureMin = -20; +const double humidityMax = 100; +const double humidityMin = 0; + +class ReadException {}; + +inline uint64_t timeFrom(clock_t t) +{ + return uint64_t(clock() - t) / (CLOCKS_PER_SEC / 1000 / 1000); +} + +void sync(uint64_t timeout, bool toUp) +{ + auto last = bcm2835_gpio_lev(pin); + bool synced = false; + + clock_t t = clock(); + + while (!synced && timeFrom(t) < timeout) + { + auto current = bcm2835_gpio_lev(pin); + synced = toUp ? (last == LOW && current == HIGH) : (last == HIGH && current == LOW); + last = current; + } + + if (!synced) + { + // uint64_t delta = timeFrom(t); + // cout << "Unable to sync " << (toUp ? "up" : "down") << " Time: " << delta << endl; + throw ReadException(); + } +} + +inline void syncToUp(long timeout) +{ + sync(timeout, true); +} + +inline void syncToDown(long timeout) +{ + sync(timeout, false); +} + +bool readNextBit() +{ + syncToUp(300); // Should be 50 us. + clock_t t = clock(); + syncToDown(300); // Should be 70 us. + return timeFrom(t) > 50; +} + +uint8_t readNextByte() +{ + uint8_t result = 0; + for (int i = 0; i < 8; i++) + if (readNextBit()) + result |= (1 << (7 - i)); + return result; +} + +extern "C" +bool init() +{ + if (!bcm2835_init()) + { + cerr << "Unable to init the BCM 2835" << endl; + return false; + } + return true; +} + +extern "C" +void getHumidityAndTemperature(double& h, double& t) +{ + bool dataOK = false; + while (!dataOK) + { + try + { + bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP); + + bcm2835_gpio_write(pin, LOW); + bcm2835_delayMicroseconds(30000); // 30 ms. + bcm2835_gpio_write(pin, HIGH); + bcm2835_delayMicroseconds(30); + + bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT); + + syncToUp(200); // Should be 80 us. + syncToDown(200); // Should be 80 us. + + int rh1 = readNextByte(); + int rh2 = readNextByte(); + int t1 = readNextByte(); + int t2 = readNextByte(); + int checksum = readNextByte(); + + if (((rh1 + rh2 + t1 + t2) & 0xFF) != checksum) + throw ReadException(); + + h = double((rh1 << 8) | rh2) / 10.0; + t = double(((t1 & 0x7F) << 8) | t2) / 10.0; + + if (t1 & 0x80) + t *= -1.0; + + if (h >= humidityMin && h <= humidityMax && t >= temperatureMin && t <= temperatureMax) + { + dataOK = true; + } + } + catch(ReadException ex) + { + cerr << "Read error, retrying ..." << endl; + } + + if (!dataOK) + bcm2835_delay(2000); + } +} diff --git a/build.fsx b/build.fsx new file mode 100755 index 0000000..a048f02 --- /dev/null +++ b/build.fsx @@ -0,0 +1,58 @@ +#!/usr/bin/fsharpi + +#I "packages/FAKE/tools/" +#r @"packages/FSharp.Compiler.Service/lib/net45/FSharp.Compiler.Service.dll" +#r @"packages/FAKE/tools/FakeLib.dll" + +open System.Diagnostics +open Fake +open Fake.EnvironmentHelper + +let buildDir = "./build/" + +// To match the beginning of a string and extract the rest. +let (|Prefix|_|) (p: string) (s: string) = + if s.StartsWith(p) then + Some(s.Substring(p.Length)) + else + None + +let target = + match Array.tryPick (fun a -> match a with Prefix "target=" target -> Some target | _ -> None) fsi.CommandLineArgs with + | Some target -> target + | _ -> "Debug" + +let shellExecute program args = + let startInfo = new ProcessStartInfo() + startInfo.FileName <- program + startInfo.Arguments <- args + startInfo.UseShellExecute <- true + + let proc = Process.Start(startInfo) + proc.WaitForExit() + () + +Paket.Restore (fun parameters -> parameters) + +Target "Clean" (fun _ -> + trace "Cleaning..." + CleanDir buildDir +) + +Target "Debug" (fun _ -> + trace "Building in Debug mode..." + !! "**/*.fsproj" |> MSBuildDebug buildDir "Build" |> Log "Debug-Output:" +) + +Target "Release" (fun _ -> + trace "Building in Release mode..." +) + +Target "Deploy" (fun _ -> + trace "Deployement..." +) + +// "Clean" ==> "Debug" +"Clean" ==> "Release" ==> "Deploy" + +Run target diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..5d80e23 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +./build.fsx diff --git a/build_deploy.sh b/build_deploy.sh new file mode 100755 index 0000000..230aa7c --- /dev/null +++ b/build_deploy.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +./build.fsx target=Release + diff --git a/build_run.sh b/build_run.sh new file mode 100755 index 0000000..b9c7a64 --- /dev/null +++ b/build_run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +./build.fsx target=Debug && mono build/PiNet.exe + diff --git a/paket.dependencies b/paket.dependencies new file mode 100644 index 0000000..d10d468 --- /dev/null +++ b/paket.dependencies @@ -0,0 +1,9 @@ +source https://www.nuget.org/api/v2 + +nuget FSharp.Compiler.Service +nuget Npgsql +nuget FAKE +nuget Eto.Forms +nuget Eto.Platform.Gtk3 +nuget GtkSharp +nuget FsControl >= 2.0.0-CI00087