├── .gitignore ├── Clients ├── CSharpClient │ └── sharp-arduino-serial-packet-lib │ │ ├── WpfTester │ │ ├── App.config │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── Properties │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resources.Designer.cs │ │ │ ├── Resources.resx │ │ │ ├── Settings.Designer.cs │ │ │ └── Settings.settings │ │ └── WpfTester.csproj │ │ ├── seriallibUnitTests │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── UnitTest1.cs │ │ └── seriallibUnitTests.csproj │ │ ├── seriallibtester │ │ ├── App.config │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ └── seriallibtester.csproj │ │ ├── sharp-arduino-serial-packet-lib.gpState │ │ ├── sharp-arduino-serial-packet-lib.sln │ │ └── sharp-arduino-serial-packet-lib │ │ ├── Defaults.cs │ │ ├── ExtensionsMethods.cs │ │ ├── HelpStuff.txt │ │ ├── Packet.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── SerialPortReaderWriter │ │ ├── SerialPortManager.cs │ │ └── SerialSettings.cs │ │ ├── SerialReaderWriter.cs │ │ ├── Statistics.cs │ │ └── sharp-arduino-serial-packet-lib.csproj ├── Collectd │ ├── KCollectd.png │ ├── README.md │ ├── SerialLogger │ ├── SerialLogger.cpp │ ├── arduino_distance.log │ ├── arduino_humidity.log │ ├── arduino_temperature.log │ ├── arduinologger_distance.rb │ ├── arduinologger_humidity.rb │ ├── arduinologger_temperature.rb │ ├── collectd.conf │ └── collectd.png ├── Processing │ ├── PacketInspector_v1.pde │ ├── README.md │ └── ScreenShot.png └── Python │ ├── .gitignore │ ├── README.md │ ├── makeDebian.sh │ ├── setup.py │ └── sp_controller │ ├── __init__.py │ ├── __main__.py │ ├── controller.py │ ├── infoprinter.py │ ├── main.py │ ├── serialcommunication.py │ ├── serialparser.py │ ├── settings.py │ └── tests │ └── test.py ├── Documentation ├── Doxyfile └── latex │ └── refman.pdf ├── LICENSE ├── README.md └── SerialPacket ├── Protocol.txt ├── SerialPacket.cpp ├── SerialPacket.h ├── build.sh ├── defines.h ├── defines.h.orig ├── examples ├── ArduinoActions │ ├── ArduinoActions.ino │ └── SConstruct ├── ReceivePackets │ ├── ReceivePackets.ino │ └── SConstruct ├── SendAnalogInput │ ├── SConstruct │ └── SendAnalogInput.ino ├── SendPackets │ ├── SConstruct │ └── SendPackets.ino ├── SendPacketsOnRequest │ ├── SConstruct │ └── SendPacketsOnRequest.ino └── nose_test.py ├── keywords.txt └── resources ├── COPYING ├── COPYING.LESSER ├── bcpp_indenter.cfg ├── errors.log ├── lastbuild.log └── succes.log /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace WpfTester 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | using System.Windows.Threading; 17 | using sharp_arduino_serial_packet_lib; 18 | 19 | namespace WpfTester 20 | { 21 | /// 22 | /// Interaction logic for MainWindow.xaml 23 | /// 24 | public partial class MainWindow : Window 25 | { 26 | public MainWindow() 27 | { 28 | InitializeComponent(); 29 | wr = new SerialReaderWriter(comport: "COM4"); 30 | } 31 | 32 | private SerialReaderWriter wr; 33 | private bool listening = false; 34 | private void btnStartListening_Click(object sender, RoutedEventArgs e) 35 | { 36 | if (listening == false) 37 | { 38 | wr.SerialMessageReceived += wr_SerialMessageReceived; 39 | wr.StartListening(); 40 | listening = true; 41 | btnStartListening.Content = "Stop listening"; 42 | } 43 | else 44 | { 45 | wr.SerialMessageReceived -= wr_SerialMessageReceived; 46 | wr.StopListening(); 47 | listening = false; 48 | btnStartListening.Content = "Start listening"; 49 | } 50 | 51 | } 52 | 53 | private delegate void UpdateUiTextDelegate(Packet recPacket); 54 | void wr_SerialMessageReceived(object sender, SerialArduinoMessageEventArgs e) 55 | { 56 | Dispatcher.Invoke( 57 | DispatcherPriority.Send, 58 | new Action( 59 | () => 60 | { 61 | lbPackets.Items.Insert(0, e.Packet); 62 | } 63 | ) 64 | ); 65 | 66 | } 67 | 68 | } 69 | 70 | public class CommandToText : IValueConverter 71 | { 72 | public object Convert(object value, Type targetType, 73 | object parameter, CultureInfo culture) 74 | { 75 | var incCom = (Commands)value; 76 | 77 | return incCom.ToString(); 78 | } 79 | 80 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 81 | { 82 | throw new NotImplementedException(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("WpfTester")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("WpfTester")] 15 | [assembly: AssemblyCopyright("Copyright © 2013")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18033 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WpfTester.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfTester.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18033 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WpfTester.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/WpfTester/WpfTester.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921} 8 | WinExe 9 | Properties 10 | WpfTester 11 | WpfTester 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 4.0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | MSBuild:Compile 54 | Designer 55 | 56 | 57 | MSBuild:Compile 58 | Designer 59 | 60 | 61 | App.xaml 62 | Code 63 | 64 | 65 | MainWindow.xaml 66 | Code 67 | 68 | 69 | 70 | 71 | Code 72 | 73 | 74 | True 75 | True 76 | Resources.resx 77 | 78 | 79 | True 80 | Settings.settings 81 | True 82 | 83 | 84 | ResXFileCodeGenerator 85 | Resources.Designer.cs 86 | 87 | 88 | SettingsSingleFileGenerator 89 | Settings.Designer.cs 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {57d2e5ba-3b0b-4a73-8ae6-c19f1fd493fb} 99 | sharp-arduino-serial-packet-lib 100 | 101 | 102 | 103 | 110 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibUnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("seriallibUnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("seriallibUnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3b54f0eb-dd3e-47df-a73f-be555f10a3ec")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibUnitTests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using sharp_arduino_serial_packet_lib; 4 | using sharp_arduino_serial_packet_lib.SerialPortReaderWriter; 5 | 6 | namespace seriallibUnitTests 7 | { 8 | //More info: http://msdn.microsoft.com/en-us/library/hh694602.aspx 9 | [TestClass] 10 | public class PacketParsingTest 11 | { 12 | [TestMethod] 13 | public void SendPacketTest() 14 | { 15 | SerialReaderWriter rw = new SerialReaderWriter(new SerialSettings()); 16 | rw.ParseData("T01N01I00P32Q00"); 17 | 18 | Packet p = new Packet(); 19 | p.PacketType = (PacketTypes)"01".FromHexStringToInt(); 20 | 21 | p.NodeID = "01".FromHexStringToInt(); 22 | p.CommandID = (Commands)"40".FromHexStringToInt(); 23 | p.Payload = "32".FromHexStringToInt(); 24 | p.Parity = "00".FromHexStringToInt(); 25 | 26 | 27 | Assert.AreEqual(rw.incomingPacket, p); 28 | 29 | //TODO: expand test (test other fields, test with more strings) 30 | 31 | } 32 | //TODO: test other methods (if we are bored some day :) ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibUnitTests/seriallibUnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {2D51C53E-8AE0-44F1-954F-07C4B1CD9272} 7 | Library 8 | Properties 9 | seriallibUnitTests 10 | seriallibUnitTests 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ExtensionsMethods.cs 55 | 56 | 57 | 58 | 59 | 60 | 61 | {57d2e5ba-3b0b-4a73-8ae6-c19f1fd493fb} 62 | sharp-arduino-serial-packet-lib 63 | 64 | 65 | 66 | 67 | 68 | 69 | False 70 | 71 | 72 | False 73 | 74 | 75 | False 76 | 77 | 78 | False 79 | 80 | 81 | 82 | 83 | 84 | 85 | 92 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibtester/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibtester/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using sharp_arduino_serial_packet_lib; 3 | 4 | namespace seriallibtester 5 | { 6 | class Program 7 | { 8 | private static SerialReaderWriter r; 9 | static void Main(string[] args) 10 | { 11 | try 12 | { 13 | r = new SerialReaderWriter(comport: "COM4"); 14 | r.SerialMessageReceived += r_SerialDataReceived; 15 | r.StartListening(); 16 | while (true) 17 | { 18 | 19 | } 20 | } 21 | catch (Exception e) 22 | { 23 | Console.WriteLine(e.Message); 24 | } 25 | } 26 | 27 | static void r_SerialDataReceived(object sender, SerialArduinoMessageEventArgs e) 28 | { 29 | 30 | Console.WriteLine(e.Packet.ToString()); 31 | Console.WriteLine("Received:{0} Corrupt: {1}",r.Statistics.ReceivedPackets, r.Statistics.CorruptPackets); 32 | 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibtester/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("seriallibtester")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("seriallibtester")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("247c0880-8d21-41e1-a557-c344c353fc5a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/seriallibtester/seriallibtester.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A104ABD2-5D4A-423B-9467-D902C0AB56C6} 8 | Exe 9 | Properties 10 | seriallibtester 11 | seriallibtester 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | AllRules.ruleset 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {57d2e5ba-3b0b-4a73-8ae6-c19f1fd493fb} 54 | sharp-arduino-serial-packet-lib 55 | 56 | 57 | 58 | 65 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib.gpState: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sharp-arduino-serial-packet-lib", "sharp-arduino-serial-packet-lib\sharp-arduino-serial-packet-lib.csproj", "{57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seriallibtester", "seriallibtester\seriallibtester.csproj", "{A104ABD2-5D4A-423B-9467-D902C0AB56C6}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTester", "WpfTester\WpfTester.csproj", "{6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seriallibUnitTests", "seriallibUnitTests\seriallibUnitTests.csproj", "{2D51C53E-8AE0-44F1-954F-07C4B1CD9272}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {A104ABD2-5D4A-423B-9467-D902C0AB56C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {A104ABD2-5D4A-423B-9467-D902C0AB56C6}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {A104ABD2-5D4A-423B-9467-D902C0AB56C6}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {A104ABD2-5D4A-423B-9467-D902C0AB56C6}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {6F1EE2D0-22A6-4F88-8BB1-D3A52FCCC921}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {2D51C53E-8AE0-44F1-954F-07C4B1CD9272}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {2D51C53E-8AE0-44F1-954F-07C4B1CD9272}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {2D51C53E-8AE0-44F1-954F-07C4B1CD9272}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {2D51C53E-8AE0-44F1-954F-07C4B1CD9272}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/Defaults.cs: -------------------------------------------------------------------------------- 1 | namespace sharp_arduino_serial_packet_lib 2 | { 3 | //http://www.codeproject.com/Articles/75770/Basic-serial-port-listening-application 4 | public class Defaults 5 | { 6 | public const int DEFAULT_BAUDRATE = 115200; 7 | } 8 | public enum SensorTypes 9 | { 10 | 11 | TEMPERATURE = 0x10, 12 | HUMIDITY = 0x11, 13 | DISTANCE = 0x30, 14 | MOTORSTATUS = 0x50 15 | } 16 | public enum Commands 17 | { 18 | STOP_MOTOR_A = 0x10, 19 | START_MOTOR_A = 0x11, 20 | SET_SPEED_MOTOR_A = 0x12, 21 | BRAKE_MOTOR_A = 0x13, 22 | STOP_MOTOR_B = 0x15, 23 | START_MOTOR_B = 0x16, 24 | SET_SPEED_MOTOR_B = 0x17, 25 | BRAKE_MOTOR_B = 0x18 26 | } 27 | public enum PacketFields { Type, NodeID, SensorID, CommandID, Payload, Parity } 28 | public enum PacketTypes { Command = 0x01, Command_Reply = 0x02, Data_Request = 0x11, Data_Byte = 0x12, Data_Int = 0x13, Data_Array_Request = 0x21, Data_Array = 0x22 } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/ExtensionsMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace sharp_arduino_serial_packet_lib 4 | { 5 | static class ExtensionsMethods 6 | { 7 | 8 | public static int FromHexStringToInt(this string hexstr) 9 | { 10 | if (hexstr.Length == 2) 11 | { 12 | return Convert.ToInt32(hexstr, 16); 13 | } 14 | throw new IndexOutOfRangeException("Can only create int from 2-length hex arrays. String received: " + hexstr); 15 | } 16 | 17 | public static string FromIntToHexString(this int hexstr) 18 | { 19 | //TODO 20 | throw new NotImplementedException(); 21 | } 22 | 23 | public static T[] SubArray(this T[] data, int index, int length) 24 | { 25 | var result = new T[length]; 26 | Array.Copy(data, index, result, 0, length); 27 | return result; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/HelpStuff.txt: -------------------------------------------------------------------------------- 1 | http://stackoverflow.com/questions/10501376/thread-safe-buffer-for-net 2 | 3 | DOEN! http://stackoverflow.com/questions/8286503/c-sharp-how-to-place-serial-input-data-into-a-queue-and-de-que-using-a-backgroun 4 | 5 | http://stackoverflow.com/questions/7687379/c-sharp-usb-parsing-of-a-urb-bulk-or-interrupt-transfer-packet -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/Packet.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace sharp_arduino_serial_packet_lib 4 | { 5 | 6 | public class Packet 7 | { 8 | public PacketTypes PacketType { get; set; } 9 | public int NodeID { get; set; } 10 | public int SensorID { get; set; } 11 | public Commands CommandID { get; set; } 12 | public int Payload { get; set; } 13 | public int Parity { get; set; } 14 | 15 | public string RawString { get; set; } 16 | public override string ToString() 17 | { 18 | return string.Format("Raw string:{6} \nType:{0} " + 19 | "Node:{1} " + 20 | "Sensor:{2} Command: {3}"+ 21 | "Payload:{4} Parity:{5}\n",PacketType,NodeID,SensorID,CommandID,Payload, Parity, RawString.Trim()); 22 | 23 | } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | Packet inco = obj as Packet; 28 | if (inco != null) 29 | { 30 | if (inco.Parity == this.Parity) 31 | { 32 | if (inco.NodeID == this.NodeID && inco.PacketType == this.PacketType && inco.Payload == this.Payload && 33 | inco.SensorID == this.SensorID) 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | public string ToStringMessageArray() 41 | { 42 | StringBuilder res = new StringBuilder(); 43 | res.Append('T'); 44 | int type = (int) this.PacketType; 45 | res.Append(type.FromIntToHexString()); //TODO: make this more straightforward/faster 46 | res.Append('N'); 47 | res.Append(NodeID.FromIntToHexString()); 48 | res.Append('I'); 49 | if (this.PacketType == PacketTypes.Command || this.PacketType == PacketTypes.Command_Reply) 50 | { 51 | int com = (int) this.CommandID; 52 | res.Append(com.FromIntToHexString()); 53 | } 54 | else res.Append(this.SensorID.FromIntToHexString()); 55 | res.Append('P'); 56 | res.Append(this.Payload.FromIntToHexString()); 57 | res.Append('Q'); 58 | res.Append(this.Parity); 59 | return res.ToString(); 60 | 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("sharp-arduino-serial-packet-lib")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Artesis")] 11 | [assembly: AssemblyProduct("sharp-arduino-serial-packet-lib")] 12 | [assembly: AssemblyCopyright("Artesis © 2013")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("f4df84f4-db75-43f3-897b-7890b07100e3")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/SerialPortReaderWriter/SerialPortManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO.Ports; 3 | using System.Reflection; 4 | 5 | namespace sharp_arduino_serial_packet_lib.SerialPortReaderWriter 6 | { 7 | /// 8 | /// Manager for serial port data 9 | /// 10 | //Original source: http://www.codeproject.com/Articles/75770/Basic-serial-port-listening-application 11 | class SerialPortManager : IDisposable 12 | { 13 | public SerialPortManager() 14 | { 15 | // Finding installed serial ports on hardware 16 | _currentSerialSettings.PortNameCollection = SerialPort.GetPortNames(); 17 | _currentSerialSettings.PropertyChanged += _currentSerialSettings_PropertyChanged; 18 | 19 | // If serial ports is found, we select the first found 20 | if (_currentSerialSettings.PortNameCollection.Length > 0) 21 | _currentSerialSettings.PortName = _currentSerialSettings.PortNameCollection[0]; 22 | } 23 | 24 | 25 | ~SerialPortManager() 26 | { 27 | Dispose(false); 28 | } 29 | 30 | 31 | #region Fields 32 | private SerialPort _serialPort; 33 | private SerialSettings _currentSerialSettings = new SerialSettings(); 34 | public event EventHandler NewSerialDataReceived; 35 | 36 | #endregion 37 | 38 | #region Properties 39 | /// 40 | /// Gets or sets the current serial port settings 41 | /// 42 | public SerialSettings CurrentSerialSettings 43 | { 44 | get { return _currentSerialSettings; } 45 | set { _currentSerialSettings = value; } 46 | } 47 | 48 | #endregion 49 | 50 | #region Event handlers 51 | 52 | void _currentSerialSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 53 | { 54 | // if serial port is changed, a new baud query is issued 55 | if (e.PropertyName.Equals("PortName")) 56 | UpdateBaudRateCollection(); 57 | } 58 | 59 | 60 | void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) 61 | { 62 | string nbrDataRead = _serialPort.ReadLine(); 63 | if (nbrDataRead.Length == 0) 64 | return; 65 | 66 | // Send data to whom ever interested 67 | if (NewSerialDataReceived != null) 68 | NewSerialDataReceived(this, new SerialDataEventArgs(nbrDataRead)); 69 | } 70 | 71 | #endregion 72 | 73 | #region Methods 74 | 75 | /// 76 | /// Connects to a serial port defined through the current settings 77 | /// 78 | public void StartUsingPort() 79 | { 80 | // Closing serial port if it is open 81 | if (_serialPort != null && _serialPort.IsOpen) 82 | _serialPort.Close(); 83 | 84 | // Setting serial port settings 85 | _serialPort = new SerialPort( 86 | _currentSerialSettings.PortName, 87 | _currentSerialSettings.BaudRate, 88 | _currentSerialSettings.Parity, 89 | _currentSerialSettings.DataBits, 90 | _currentSerialSettings.StopBits); 91 | 92 | // Subscribe to event and open serial port for data 93 | _serialPort.DataReceived += _serialPort_DataReceived; 94 | _serialPort.Open(); 95 | } 96 | 97 | /// 98 | /// Closes the serial port 99 | /// 100 | public void StopUsingPort() 101 | { 102 | _serialPort.Close(); 103 | } 104 | 105 | /// 106 | /// Send serial byte array to serialport 107 | /// 108 | /// 109 | public void SendSerialData(string data) 110 | { 111 | if (_serialPort != null && _serialPort.IsOpen) 112 | { 113 | _serialPort.WriteLine(data); 114 | //TODO: http://www.ibiliskov.info/2011/05/net-serialport-pitfalls/ 115 | } 116 | else 117 | { 118 | throw new Exception("No serial port open. Did you call the StartUsingPort method?"); 119 | } 120 | } 121 | 122 | 123 | /// 124 | /// Retrieves the current selected device's COMMPROP structure, and extracts the dwSettableBaud property 125 | /// 126 | private void UpdateBaudRateCollection() 127 | { 128 | _serialPort = new SerialPort(_currentSerialSettings.PortName); 129 | _serialPort.Open(); 130 | var field = _serialPort.BaseStream.GetType().GetField("commProp", BindingFlags.Instance | BindingFlags.NonPublic); 131 | if (field != null) 132 | { 133 | var p = field.GetValue(_serialPort.BaseStream); 134 | 135 | if (p != null) 136 | { 137 | var fieldInfo = p.GetType().GetField("dwSettableBaud", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 138 | if (fieldInfo != null) 139 | { 140 | var dwSettableBaud = (Int32)fieldInfo.GetValue(p); 141 | 142 | _serialPort.Close(); 143 | _currentSerialSettings.UpdateBaudRateCollection(dwSettableBaud); 144 | } 145 | } 146 | 147 | } 148 | } 149 | 150 | // Call to release serial port 151 | public void Dispose() 152 | { 153 | Dispose(true); 154 | } 155 | 156 | // Part of basic design pattern for implementing Dispose 157 | protected virtual void Dispose(bool disposing) 158 | { 159 | if (disposing) 160 | { 161 | _serialPort.DataReceived -= _serialPort_DataReceived; 162 | } 163 | // Releasing serial port (and other unmanaged objects) 164 | if (_serialPort != null) 165 | { 166 | if (_serialPort.IsOpen) 167 | _serialPort.Close(); 168 | 169 | _serialPort.Dispose(); 170 | } 171 | } 172 | 173 | 174 | #endregion 175 | 176 | } 177 | 178 | /// 179 | /// EventArgs used to send bytes received on serial port 180 | /// 181 | public class SerialDataEventArgs : EventArgs 182 | { 183 | public SerialDataEventArgs(string dataInByteArray) 184 | { 185 | Data = dataInByteArray; 186 | } 187 | 188 | /// 189 | /// Byte array containing data from serial port 190 | /// 191 | public string Data; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/SerialPortReaderWriter/SerialSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO.Ports; 4 | 5 | namespace sharp_arduino_serial_packet_lib.SerialPortReaderWriter 6 | { 7 | 8 | /// 9 | /// Class containing properties related to a serial port 10 | /// 11 | //Original source: http://www.codeproject.com/Articles/75770/Basic-serial-port-listening-application 12 | public class SerialSettings : INotifyPropertyChanged 13 | { 14 | public event PropertyChangedEventHandler PropertyChanged; 15 | string _portName = ""; 16 | int _baudRate = 115200; 17 | readonly BindingList _baudRateCollection = new BindingList(); 18 | Parity _parity = Parity.None; 19 | int _dataBits = 8; 20 | int[] _dataBitsCollection = { 5, 6, 7, 8 }; 21 | StopBits _stopBits = StopBits.One; 22 | 23 | #region Properties 24 | /// 25 | /// The port to use (for example, COM1). 26 | /// 27 | public string PortName 28 | { 29 | get { return _portName; } 30 | set 31 | { 32 | if (!_portName.Equals(value)) 33 | { 34 | _portName = value; 35 | SendPropertyChangedEvent("PortName"); 36 | } 37 | } 38 | } 39 | /// 40 | /// The baud rate. 41 | /// 42 | public int BaudRate 43 | { 44 | get { return _baudRate; } 45 | set 46 | { 47 | if (_baudRate != value) 48 | { 49 | _baudRate = value; 50 | SendPropertyChangedEvent("BaudRate"); 51 | } 52 | } 53 | } 54 | 55 | /// 56 | /// One of the Parity values. 57 | /// 58 | public Parity Parity 59 | { 60 | get { return _parity; } 61 | set 62 | { 63 | if (_parity != value) 64 | { 65 | _parity = value; 66 | SendPropertyChangedEvent("Parity"); 67 | } 68 | } 69 | } 70 | /// 71 | /// The data bits value. 72 | /// 73 | public int DataBits 74 | { 75 | get { return _dataBits; } 76 | set 77 | { 78 | if (_dataBits != value) 79 | { 80 | _dataBits = value; 81 | SendPropertyChangedEvent("DataBits"); 82 | } 83 | } 84 | } 85 | /// 86 | /// One of the StopBits values. 87 | /// 88 | public StopBits StopBits 89 | { 90 | get { return _stopBits; } 91 | set 92 | { 93 | if (_stopBits != value) 94 | { 95 | _stopBits = value; 96 | SendPropertyChangedEvent("StopBits"); 97 | } 98 | } 99 | } 100 | 101 | /// 102 | /// Available ports on the computer 103 | /// 104 | public string[] PortNameCollection { get; set; } 105 | 106 | /// 107 | /// Available baud rates for current serial port 108 | /// 109 | public BindingList BaudRateCollection 110 | { 111 | get { return _baudRateCollection; } 112 | } 113 | 114 | /// 115 | /// Available databits setting 116 | /// 117 | public int[] DataBitsCollection 118 | { 119 | get { return _dataBitsCollection; } 120 | set { _dataBitsCollection = value; } 121 | } 122 | 123 | #endregion 124 | 125 | #region Methods 126 | /// 127 | /// Updates the range of possible baud rates for device 128 | /// 129 | /// dwSettableBaud parameter from the COMMPROP Structure 130 | /// An updated list of values 131 | public void UpdateBaudRateCollection(int possibleBaudRates) 132 | { 133 | const int BAUD_075 = 0x00000001; 134 | const int BAUD_110 = 0x00000002; 135 | const int BAUD_150 = 0x00000008; 136 | const int BAUD_300 = 0x00000010; 137 | const int BAUD_600 = 0x00000020; 138 | const int BAUD_1200 = 0x00000040; 139 | const int BAUD_1800 = 0x00000080; 140 | const int BAUD_2400 = 0x00000100; 141 | const int BAUD_4800 = 0x00000200; 142 | const int BAUD_7200 = 0x00000400; 143 | const int BAUD_9600 = 0x00000800; 144 | const int BAUD_14400 = 0x00001000; 145 | const int BAUD_19200 = 0x00002000; 146 | const int BAUD_38400 = 0x00004000; 147 | const int BAUD_56K = 0x00008000; 148 | const int BAUD_57600 = 0x00040000; 149 | const int BAUD_115200 = 0x00020000; 150 | const int BAUD_128K = 0x00010000; 151 | 152 | _baudRateCollection.Clear(); 153 | 154 | if ((possibleBaudRates & BAUD_075) > 0) 155 | _baudRateCollection.Add(75); 156 | if ((possibleBaudRates & BAUD_110) > 0) 157 | _baudRateCollection.Add(110); 158 | if ((possibleBaudRates & BAUD_150) > 0) 159 | _baudRateCollection.Add(150); 160 | if ((possibleBaudRates & BAUD_300) > 0) 161 | _baudRateCollection.Add(300); 162 | if ((possibleBaudRates & BAUD_600) > 0) 163 | _baudRateCollection.Add(600); 164 | if ((possibleBaudRates & BAUD_1200) > 0) 165 | _baudRateCollection.Add(1200); 166 | if ((possibleBaudRates & BAUD_1800) > 0) 167 | _baudRateCollection.Add(1800); 168 | if ((possibleBaudRates & BAUD_2400) > 0) 169 | _baudRateCollection.Add(2400); 170 | if ((possibleBaudRates & BAUD_4800) > 0) 171 | _baudRateCollection.Add(4800); 172 | if ((possibleBaudRates & BAUD_7200) > 0) 173 | _baudRateCollection.Add(7200); 174 | if ((possibleBaudRates & BAUD_9600) > 0) 175 | _baudRateCollection.Add(9600); 176 | if ((possibleBaudRates & BAUD_14400) > 0) 177 | _baudRateCollection.Add(14400); 178 | if ((possibleBaudRates & BAUD_19200) > 0) 179 | _baudRateCollection.Add(19200); 180 | if ((possibleBaudRates & BAUD_38400) > 0) 181 | _baudRateCollection.Add(38400); 182 | if ((possibleBaudRates & BAUD_56K) > 0) 183 | _baudRateCollection.Add(56000); 184 | if ((possibleBaudRates & BAUD_57600) > 0) 185 | _baudRateCollection.Add(57600); 186 | if ((possibleBaudRates & BAUD_115200) > 0) 187 | _baudRateCollection.Add(115200); 188 | if ((possibleBaudRates & BAUD_128K) > 0) 189 | _baudRateCollection.Add(128000); 190 | 191 | SendPropertyChangedEvent("BaudRateCollection"); 192 | } 193 | 194 | /// 195 | /// Send a PropertyChanged event 196 | /// 197 | /// Name of changed property 198 | private void SendPropertyChangedEvent(String propertyName) 199 | { 200 | if (PropertyChanged != null) 201 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 202 | } 203 | 204 | #endregion 205 | } 206 | 207 | 208 | } 209 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/SerialReaderWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using sharp_arduino_serial_packet_lib.SerialPortReaderWriter; 4 | 5 | namespace sharp_arduino_serial_packet_lib 6 | { 7 | public class SerialReaderWriter : IDisposable 8 | { 9 | 10 | public SerialSettings SerialSettings 11 | { 12 | get { return spManager.CurrentSerialSettings; } 13 | set { spManager.CurrentSerialSettings = value; } 14 | } 15 | public Statistics Statistics 16 | { 17 | get { return _statistics; } 18 | } 19 | 20 | 21 | 22 | #region Constructors 23 | public SerialReaderWriter(int baudrate = 115200, string comport = "COM2") 24 | { 25 | _statistics = new Statistics(); 26 | spManager.CurrentSerialSettings.BaudRate = baudrate; 27 | spManager.CurrentSerialSettings.PortName = comport; 28 | } 29 | 30 | public SerialReaderWriter(SerialSettings settings) 31 | { 32 | _statistics = new Statistics(); 33 | spManager.CurrentSerialSettings = settings; 34 | } 35 | 36 | private readonly SerialPortManager spManager = new SerialPortManager(); 37 | #endregion 38 | 39 | private int ComputeParity() 40 | { 41 | //TODO: compute parity (ask Jeroen) 42 | return incomingPacket.Parity; 43 | } 44 | 45 | #region Receiving methods 46 | 47 | public void StartListening() 48 | { 49 | if (spManager != null) 50 | { 51 | spManager.NewSerialDataReceived += OnNewSerialDataReceived; 52 | spManager.StartUsingPort(); 53 | } 54 | 55 | } 56 | public void StopListening() 57 | { 58 | if (spManager != null) 59 | { 60 | spManager.NewSerialDataReceived -= OnNewSerialDataReceived; 61 | spManager.StopUsingPort(); 62 | } 63 | } 64 | 65 | private readonly Statistics _statistics; 66 | void OnNewSerialDataReceived(object sender, SerialDataEventArgs e) 67 | { 68 | Statistics.ReceivedPackets++; 69 | 70 | try 71 | { 72 | ParseData(e.Data); 73 | } 74 | catch (Exception) 75 | { 76 | Debug.WriteLine("Corrupt packet: dropped + (" + (e.Data) + ")"); 77 | Statistics.CorruptPackets++; 78 | } 79 | 80 | } 81 | public event EventHandler SerialMessageReceived; 82 | 83 | 84 | 85 | public Packet incomingPacket = new Packet(); 86 | private PacketFields currentField; 87 | public void ParseData(string packetStr) 88 | { 89 | 90 | Debug.WriteLine("New packet:\t string:" + packetStr); 91 | 92 | for (int i = 0; i < packetStr.Length; i++) 93 | { 94 | //Simple state-machine 95 | if (packetStr[i] == 'T') 96 | { 97 | incomingPacket = new Packet { RawString = packetStr }; 98 | currentField = PacketFields.Type; 99 | } 100 | 101 | else if (packetStr[i] == 'N') 102 | currentField = PacketFields.NodeID; 103 | else if (packetStr[i] == 'I') 104 | { 105 | if (incomingPacket.PacketType == PacketTypes.Command || incomingPacket.PacketType == PacketTypes.Command_Reply) 106 | currentField = PacketFields.CommandID; 107 | else if (incomingPacket.PacketType == PacketTypes.Data_Array_Request || incomingPacket.PacketType == PacketTypes.Data_Int || incomingPacket.PacketType == PacketTypes.Data_Request) 108 | { 109 | currentField = PacketFields.SensorID; 110 | } 111 | } 112 | else if (packetStr[i] == 'P') 113 | currentField = PacketFields.Payload; 114 | else if (packetStr[i] == 'Q') 115 | currentField = PacketFields.Parity; 116 | else 117 | { 118 | switch (currentField) 119 | { 120 | case PacketFields.Type: 121 | incomingPacket.PacketType = (PacketTypes)packetStr.Substring(i, 2).FromHexStringToInt(); 122 | i++; 123 | break; 124 | case PacketFields.NodeID: 125 | incomingPacket.NodeID = packetStr.Substring(i, 2).FromHexStringToInt(); 126 | i++; 127 | break; 128 | case PacketFields.SensorID: 129 | incomingPacket.SensorID = packetStr.Substring(i, 2).FromHexStringToInt(); 130 | i++; 131 | break; 132 | case PacketFields.CommandID: 133 | incomingPacket.CommandID = (Commands)packetStr.Substring(i, 2).FromHexStringToInt(); 134 | i++; 135 | break; 136 | case PacketFields.Payload: 137 | incomingPacket.Payload = packetStr.Substring(i, 2).FromHexStringToInt(); 138 | i++; 139 | break; 140 | case PacketFields.Parity: 141 | incomingPacket.Parity = packetStr.Substring(i, 2).FromHexStringToInt(); 142 | i = packetStr.Length; //we're done with this packet 143 | 144 | if (SerialMessageReceived != null && ComputeParity() == incomingPacket.Parity) //&& parity klopt 145 | SerialMessageReceived(this, new SerialArduinoMessageEventArgs(incomingPacket)); 146 | else 147 | { 148 | Debug.WriteLine("Parity failed"); 149 | } 150 | break; 151 | default: 152 | throw new ArgumentOutOfRangeException(); 153 | } 154 | } 155 | 156 | } 157 | 158 | } 159 | #endregion 160 | 161 | #region Send methods 162 | 163 | public void SendPacket(PacketTypes ptype, int nodeId, int sensorID, Commands command, int payload) 164 | { 165 | Packet res= new Packet(); 166 | res.PacketType = ptype; 167 | res.NodeID = nodeId; 168 | res.SensorID = sensorID; 169 | res.CommandID = command; 170 | res.Payload = payload; 171 | res.Parity = ComputeParity(); //TODO 172 | 173 | spManager.SendSerialData(res.ToStringMessageArray()); 174 | 175 | } 176 | #endregion 177 | 178 | #region Dispose 179 | protected virtual void Dispose(bool disposing) 180 | { 181 | if (disposing) 182 | { 183 | spManager.StopUsingPort(); 184 | spManager.NewSerialDataReceived -= OnNewSerialDataReceived; 185 | spManager.Dispose(); 186 | } 187 | 188 | } 189 | public void Dispose() 190 | { 191 | Dispose(true); 192 | GC.SuppressFinalize(this); 193 | } 194 | #endregion 195 | 196 | 197 | } 198 | public class SerialArduinoMessageEventArgs : EventArgs 199 | { 200 | public Packet Packet { get; set; } 201 | 202 | public SerialArduinoMessageEventArgs(Packet pckt) 203 | { 204 | Packet = pckt; 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/Statistics.cs: -------------------------------------------------------------------------------- 1 | namespace sharp_arduino_serial_packet_lib 2 | { 3 | public class Statistics 4 | { 5 | public int ReceivedPackets { get; set; } 6 | public int CorruptPackets { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Clients/CSharpClient/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib/sharp-arduino-serial-packet-lib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {57D2E5BA-3B0B-4A73-8AE6-C19F1FD493FB} 8 | Library 9 | Properties 10 | sharp_arduino_serial_packet_lib 11 | sharp-arduino-serial-packet-lib 12 | v3.5 13 | 512 14 | Client 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /Clients/Collectd/KCollectd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeroendoggen/Arduino-serial-messaging/87bdc590bfb85e6d31165f1c8e87f0d09042c8cc/Clients/Collectd/KCollectd.png -------------------------------------------------------------------------------- /Clients/Collectd/README.md: -------------------------------------------------------------------------------- 1 | ## Arduino sensor logging with collectd & RRDtool 2 | 3 | Save Arduino sensor readings in a RRDtool database using 'collectd'. 4 | 5 | Program flow: 6 | 7 | 1. The Arduino reads its sensors. 8 | 2. The Arduino sends a serial data packet to the 'server'. 9 | 3. The server runs a c++ application to listen for serial packets. 10 | 4. The server writes the payloads of the incoming packets to logfiles. 11 | 5. Every 'x' seconds, the 'collectd' daemon runs a Ruby script to read the data from the logfiles. 12 | 6. You can inspect, monitor, graph the info with any RRDtool compatible application. (e.g. Cacti, Nagios, KCollectd) 13 | 14 | ## KCollectd Screenshots 15 | 16 | KCollectd is a RRDtool graphing frontend for KDE. 17 | 18 | Screenhot shows: (sensing interval: 10 seconds) 19 | 20 | * Orange line: CPU usage 21 | * Green line: temperature sensor data (fake data: 'up/down counter') 22 | * Blue line: distance sensor data (fake data: 'up/down counter x 2') 23 | * Pink line: humidity sensor data (fake data: 'up/down counter + 100') 24 | 25 | ![KCollectd](KCollectd.png?raw=true) 26 | 27 | ## Links 28 | 29 | * [RRDtool](http://oss.oetiker.ch/rrdtool/): Industry standard, high performance data logging and graphing system for time series data. 30 | * [Nagios](http://www.nagios.org/): IT Infrastructure Monitoring 31 | * [KCollectd](http://www.forwiss.uni-passau.de/~berberic/Linux/kcollectd.html): a KDE-based application for displaying RRD data collected by collectd 32 | * [writing collectd plugins](http://support.rightscale.com/12-Guides/RightScale_101/08-Management_Tools/Monitoring_System/Writing_custom_collectd_plugins/Custom_Collectd_Plug-ins_for_Linux) -------------------------------------------------------------------------------- /Clients/Collectd/SerialLogger: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeroendoggen/Arduino-serial-messaging/87bdc590bfb85e6d31165f1c8e87f0d09042c8cc/Clients/Collectd/SerialLogger -------------------------------------------------------------------------------- /Clients/Collectd/SerialLogger.cpp: -------------------------------------------------------------------------------- 1 | // SerialLogger.cpp - Read 'serialPacket' data and write logfiles for collectd 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // More info: 4 | // 5 | // Version History: 6 | // Version 0.0.1: Just a first quick and dirty first implementation !! 7 | // 8 | // This program is free software; you can redistribute it and/or 9 | // modify it under the terms of the GNU Lesser General Public 10 | // License as published by the Free Software Foundation; either 11 | // version 2.1 of the License, or (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | // Lesser General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Lesser General Public 19 | // License along with this program; if not, write to the Free Software 20 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | 23 | // TODO list: 24 | /// @todo: 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define TEMPERATURE 0x10 33 | #define HUMIDITY 0x11 34 | #define DISTANCE 0x30 35 | 36 | int hex_to_dec(int in); 37 | 38 | int main( int argc, char** argv ) 39 | { 40 | // 41 | // Open the serial port. 42 | // 43 | using namespace LibSerial ; 44 | using namespace std; 45 | SerialStream serial_port ; 46 | serial_port.Open( "/dev/ttyUSB0" ) ; 47 | if ( ! serial_port.good() ) 48 | { 49 | std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] " 50 | << "Error: Could not open serial port." 51 | << std::endl ; 52 | exit(1) ; 53 | } 54 | // 55 | // Set the baud rate of the serial port. 56 | // 57 | serial_port.SetBaudRate( SerialStreamBuf::BAUD_57600 ) ; 58 | if ( ! serial_port.good() ) 59 | { 60 | std::cerr << "Error: Could not set the baud rate." << std::endl ; 61 | exit(1) ; 62 | } 63 | // 64 | // Set the number of data bits. 65 | // 66 | serial_port.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ; 67 | if ( ! serial_port.good() ) 68 | { 69 | std::cerr << "Error: Could not set the character size." << std::endl ; 70 | exit(1) ; 71 | } 72 | // 73 | // Disable parity. 74 | // 75 | serial_port.SetParity( SerialStreamBuf::PARITY_NONE ) ; 76 | if ( ! serial_port.good() ) 77 | { 78 | std::cerr << "Error: Could not disable the parity." << std::endl ; 79 | exit(1) ; 80 | } 81 | // 82 | // Set the number of stop bits. 83 | // 84 | serial_port.SetNumOfStopBits( 1 ) ; 85 | if ( ! serial_port.good() ) 86 | { 87 | std::cerr << "Error: Could not set the number of stop bits." 88 | << std::endl ; 89 | exit(1) ; 90 | } 91 | // 92 | // Turn on hardware flow control. 93 | // 94 | serial_port.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_HARD ) ; 95 | if ( ! serial_port.good() ) 96 | { 97 | std::cerr << "Error: Could not use hardware flow control." 98 | << std::endl ; 99 | exit(1) ; 100 | } 101 | // 102 | // Do not skip whitespace characters while reading from the 103 | // serial port. 104 | // 105 | serial_port.unsetf( std::ios_base::skipws ) ; 106 | // 107 | // Keep reading data from serial port and print it to the screen. 108 | // 109 | 110 | ofstream distance,temperature,humidity; 111 | 112 | char next_byte1; 113 | char next_byte2; 114 | char next_byte; 115 | 116 | int packetType; 117 | int nodeID; 118 | int sensorID; 119 | int parity; 120 | int payload; 121 | 122 | //T12N00I00P01Q13 123 | while( true ) 124 | { 125 | serial_port.get(next_byte); 126 | if((char)next_byte == 'T') 127 | { 128 | serial_port.get(next_byte1); 129 | serial_port.get(next_byte2); 130 | packetType=hex_to_dec(next_byte1)*16 + hex_to_dec(next_byte2); 131 | if (packetType == 0x12) 132 | { 133 | serial_port.get(next_byte); 134 | if((char)next_byte == 'N') 135 | { 136 | serial_port.get(next_byte1); 137 | serial_port.get(next_byte2); 138 | nodeID=hex_to_dec(next_byte1)*16 + hex_to_dec(next_byte2); 139 | } 140 | 141 | serial_port.get(next_byte); 142 | if((char)next_byte == 'I') 143 | { 144 | serial_port.get(next_byte1); 145 | serial_port.get(next_byte2); 146 | sensorID=hex_to_dec(next_byte1)*16 + hex_to_dec(next_byte2); 147 | } 148 | serial_port.get(next_byte); 149 | 150 | serial_port.get(next_byte1); 151 | serial_port.get(next_byte2); 152 | payload=hex_to_dec(next_byte1)*16 + hex_to_dec(next_byte2); 153 | 154 | if((char)next_byte == 'P') 155 | { 156 | if(sensorID==TEMPERATURE) 157 | { 158 | distance.open ("arduino_distance.log"); 159 | distance << payload << "\n"; 160 | distance.close(); 161 | } 162 | 163 | else if(sensorID==HUMIDITY) 164 | { 165 | humidity.open ("arduino_humidity.log"); 166 | humidity << payload << "\n"; 167 | humidity.close(); 168 | } 169 | 170 | else if(sensorID==DISTANCE) 171 | { 172 | temperature.open ("arduino_temperature.log"); 173 | temperature << payload << "\n"; 174 | temperature.close(); 175 | } 176 | } 177 | } 178 | } 179 | } 180 | std::cerr << std::endl ; 181 | return EXIT_SUCCESS ; 182 | } 183 | 184 | /// Convert HEX to Decimal 185 | #define HEX_DEC_ERROR 42 186 | int hex_to_dec(int in) 187 | { 188 | if(((in >= '0') && (in <= '9'))) return in-'0'; 189 | in |= 0x20; 190 | if(((in >= 'a') && (in <= 'f'))) return in-'a' + 10; 191 | return HEX_DEC_ERROR; 192 | } 193 | 194 | -------------------------------------------------------------------------------- /Clients/Collectd/arduino_distance.log: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /Clients/Collectd/arduino_humidity.log: -------------------------------------------------------------------------------- 1 | 27 2 | -------------------------------------------------------------------------------- /Clients/Collectd/arduino_temperature.log: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /Clients/Collectd/arduinologger_distance.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'getoptlong' 3 | 4 | # The name of the collectd plugin, something like apache, memory, mysql, interface, ... 5 | PLUGIN_NAME = 'arduinologger-distance' 6 | 7 | def usage 8 | puts("#{$0} -h [-i ]") 9 | exit 10 | end 11 | 12 | # Main 13 | begin 14 | # Sync stdout so that it will flush to collectd properly. 15 | $stdout.sync = true 16 | 17 | # Parse command line options 18 | hostname = nil 19 | sampling_interval = 20 # sec, Default value 20 | opts = GetoptLong.new( 21 | [ '--hostid', '-h', GetoptLong::REQUIRED_ARGUMENT ], 22 | [ '--sampling-interval', '-i', GetoptLong::OPTIONAL_ARGUMENT ] 23 | ) 24 | opts.each do |opt, arg| 25 | case opt 26 | when '--hostid' 27 | hostname = arg 28 | when '--sampling-interval' 29 | sampling_interval = arg.to_i 30 | end 31 | end 32 | usage if !hostname 33 | 34 | # Collection loop 35 | while true do 36 | start_run = Time.now.to_i 37 | next_run = start_run + sampling_interval 38 | 39 | # collectd data and print the values 40 | data = `cat /usr/lib/collectd/plugins/arduino_distance.log` # get 5-minute load average 41 | puts("PUTVAL #{hostname}/#{PLUGIN_NAME}/gauge-distance #{start_run}:#{data}") 42 | 43 | # sleep to make the interval 44 | while((time_left = (next_run - Time.now.to_i)) > 0) do 45 | sleep(time_left) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /Clients/Collectd/arduinologger_humidity.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'getoptlong' 3 | 4 | # The name of the collectd plugin, something like apache, memory, mysql, interface, ... 5 | PLUGIN_NAME = 'arduinologger-humidity' 6 | 7 | def usage 8 | puts("#{$0} -h [-i ]") 9 | exit 10 | end 11 | 12 | # Main 13 | begin 14 | # Sync stdout so that it will flush to collectd properly. 15 | $stdout.sync = true 16 | 17 | # Parse command line options 18 | hostname = nil 19 | sampling_interval = 20 # sec, Default value 20 | opts = GetoptLong.new( 21 | [ '--hostid', '-h', GetoptLong::REQUIRED_ARGUMENT ], 22 | [ '--sampling-interval', '-i', GetoptLong::OPTIONAL_ARGUMENT ] 23 | ) 24 | opts.each do |opt, arg| 25 | case opt 26 | when '--hostid' 27 | hostname = arg 28 | when '--sampling-interval' 29 | sampling_interval = arg.to_i 30 | end 31 | end 32 | usage if !hostname 33 | 34 | # Collection loop 35 | while true do 36 | start_run = Time.now.to_i 37 | next_run = start_run + sampling_interval 38 | 39 | # collectd data and print the values 40 | data = `cat /usr/lib/collectd/plugins/arduino_humidity.log` # get 5-minute load average 41 | puts("PUTVAL #{hostname}/#{PLUGIN_NAME}/gauge-humidity #{start_run}:#{data}") 42 | 43 | # sleep to make the interval 44 | while((time_left = (next_run - Time.now.to_i)) > 0) do 45 | sleep(time_left) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /Clients/Collectd/arduinologger_temperature.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'getoptlong' 3 | 4 | # The name of the collectd plugin, something like apache, memory, mysql, interface, ... 5 | PLUGIN_NAME = 'arduinologger-temperature' 6 | 7 | def usage 8 | puts("#{$0} -h [-i ]") 9 | exit 10 | end 11 | 12 | # Main 13 | begin 14 | # Sync stdout so that it will flush to collectd properly. 15 | $stdout.sync = true 16 | 17 | # Parse command line options 18 | hostname = nil 19 | sampling_interval = 20 # sec, Default value 20 | opts = GetoptLong.new( 21 | [ '--hostid', '-h', GetoptLong::REQUIRED_ARGUMENT ], 22 | [ '--sampling-interval', '-i', GetoptLong::OPTIONAL_ARGUMENT ] 23 | ) 24 | opts.each do |opt, arg| 25 | case opt 26 | when '--hostid' 27 | hostname = arg 28 | when '--sampling-interval' 29 | sampling_interval = arg.to_i 30 | end 31 | end 32 | usage if !hostname 33 | 34 | # Collection loop 35 | while true do 36 | start_run = Time.now.to_i 37 | next_run = start_run + sampling_interval 38 | 39 | # collectd data and print the values 40 | data = `cat /usr/lib/collectd/plugins/arduino_temperature.log` # get 5-minute load average 41 | puts("PUTVAL #{hostname}/#{PLUGIN_NAME}/gauge-temperature #{start_run}:#{data}") 42 | 43 | # sleep to make the interval 44 | while((time_left = (next_run - Time.now.to_i)) > 0) do 45 | sleep(time_left) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /Clients/Collectd/collectd.conf: -------------------------------------------------------------------------------- 1 | ## ADD these lines at the end of your existing : "/etc/collect/collect.conf" (only tested on Ubuntu 12.10) 2 | 3 | ## This is not totally correct (syslog shows warnings) 4 | LoadPlugin exec 5 | 6 | # userid plugin executable plugin args 7 | Exec "jeroen" "/usr/lib/collectd/plugins/arduinologger_distance.rb" "-h" "ArduinoLogger" "-i" "1" 8 | 9 | 10 | LoadPlugin exec 11 | 12 | # userid plugin executable plugin args 13 | Exec "jeroen" "/usr/lib/collectd/plugins/arduinologger_temperature.rb" "-h" "ArduinoLogger" "-i" "1" 14 | 15 | 16 | LoadPlugin exec 17 | 18 | # userid plugin executable plugin args 19 | Exec "jeroen" "/usr/lib/collectd/plugins/arduinologger_humidity.rb" "-h" "ArduinoLogger" "-i" "1" 20 | -------------------------------------------------------------------------------- /Clients/Collectd/collectd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeroendoggen/Arduino-serial-messaging/87bdc590bfb85e6d31165f1c8e87f0d09042c8cc/Clients/Collectd/collectd.png -------------------------------------------------------------------------------- /Clients/Processing/PacketInspector_v1.pde: -------------------------------------------------------------------------------- 1 | String typedText = ""; 2 | 3 | PFont font; 4 | import processing.serial.*; 5 | 6 | Serial myPort; // Create object from Serial class 7 | 8 | int portNumber = 0; 9 | byte[] inBuffer = new byte[17]; 10 | 11 | byte msgType; 12 | byte nodeID; 13 | byte sensorID; 14 | byte payload; 15 | byte parity; 16 | byte command; 17 | 18 | int lf=10; 19 | 20 | void setup() { 21 | size(440, 80); 22 | font = createFont("Arial-Black-48.vlw", 10); 23 | 24 | String portName = Serial.list()[portNumber]; 25 | myPort = new Serial(this, portName, 115200); 26 | myPort.bufferUntil(lf); 27 | myPort.clear(); 28 | 29 | background(245); 30 | } 31 | 32 | 33 | void draw() { 34 | drawduobutton(10,10,220,0,"","Hex","Decimal"); 35 | drawduobutton(80,10,220,0,"MsgType",msgType,int(msgType)); 36 | drawduobutton(150,10,220,0,"NodeID",nodeID,int(nodeID)); 37 | drawduobutton(220,10,220,0,"SensorID",sensorID,int(sensorID)); 38 | drawduobutton(290,10,220,0,"Payload",payload,int(payload)); 39 | drawduobutton(360,10,220,0,"Parity",parity,int(parity)); 40 | } 41 | 42 | void drawduobutton(int right, int down, int bgcolor, int textcolor, String buttontext, byte dataByte,int buttondata){ 43 | drawbutton(right, down, bgcolor, textcolor, buttontext,70); 44 | drawbutton(right, down+20, bgcolor+30, textcolor, dataByte,70); 45 | drawbutton(right, down+40, bgcolor+30, textcolor, buttondata,70); 46 | } 47 | 48 | void drawduobutton(int right, int down, int bgcolor, int textcolor, String buttontext1, String buttontext2, String buttontext3){ 49 | drawbutton(right, down, bgcolor, textcolor, buttontext1,70); 50 | drawbutton(right, down+20, bgcolor+30, textcolor, buttontext2,70); 51 | drawbutton(right, down+40, bgcolor+30, textcolor, buttontext3,70); 52 | } 53 | 54 | void drawbutton(int right, int down, int bgcolor, int textcolor, String buttontext, int width){ 55 | int height=20; 56 | if(bgcolor==1) fill(255,0,0); 57 | else if(bgcolor==2)fill(0,255,0); 58 | else if(bgcolor==3)fill(0,0,255); 59 | else fill(bgcolor); 60 | 61 | rect(right, down, width, height); 62 | textAlign(CENTER); 63 | fill(textcolor); 64 | text(buttontext, right+(width/2), down+(height/1.2)); 65 | } 66 | 67 | void drawbutton(int right, int down, int bgcolor, int textcolor, int buttondata, int width){ 68 | int height=20; 69 | if(bgcolor==1) fill(255,0,0); 70 | else if(bgcolor==2)fill(0,255,0); 71 | else if(bgcolor==3)fill(0,0,255); 72 | else fill(bgcolor); 73 | 74 | rect(right, down, width, height); 75 | textAlign(CENTER); 76 | fill(textcolor); 77 | text(int(buttondata), right+(width/2), down+(height/1.2)); 78 | } 79 | 80 | void drawbutton(int right, int down, int bgcolor, int textcolor, byte buttondata, int width){ 81 | int height=20; 82 | if(bgcolor==1) fill(255,0,0); 83 | else if(bgcolor==2)fill(0,255,0); 84 | else if(bgcolor==3)fill(0,0,255); 85 | else fill(bgcolor); 86 | 87 | rect(right, down, width, height); 88 | textAlign(CENTER); 89 | fill(textcolor); 90 | text(hex(buttondata), right+(width/2), down+(height/1.2)); 91 | } 92 | 93 | void serialEvent(Serial thisPort) { 94 | 95 | while (thisPort.available() > 0) { 96 | int byteCount = thisPort.readBytesUntil(lf, inBuffer); 97 | } 98 | 99 | msgType=byte(Character.getNumericValue(inBuffer[1])*16 + Character.getNumericValue(inBuffer[2])); 100 | nodeID=byte(Character.getNumericValue(inBuffer[4])*16 + Character.getNumericValue(inBuffer[5])); 101 | sensorID=byte(Character.getNumericValue(inBuffer[7])*16 + Character.getNumericValue(inBuffer[8])); 102 | payload=byte(Character.getNumericValue(inBuffer[10])*16 + Character.getNumericValue(inBuffer[11])); 103 | parity=byte(Character.getNumericValue(inBuffer[13])*16 + Character.getNumericValue(inBuffer[14])); 104 | } 105 | -------------------------------------------------------------------------------- /Clients/Processing/README.md: -------------------------------------------------------------------------------- 1 | ## Arduino sensor logging with collectd & RRDtool 2 | 3 | Small application written in the processing programming language (~Java) that shows the contents of the last incoming packet in a GUI. 4 | 5 | Screenshot: 6 | 7 | ![Processing](ScreenShot.png?raw=true) 8 | 9 | ## Links 10 | 11 | * [http://processing.org](http://processing.org) -------------------------------------------------------------------------------- /Clients/Processing/ScreenShot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeroendoggen/Arduino-serial-messaging/87bdc590bfb85e6d31165f1c8e87f0d09042c8cc/Clients/Processing/ScreenShot.png -------------------------------------------------------------------------------- /Clients/Python/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | bin/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | eggs/ 14 | lib/ 15 | lib64/ 16 | parts/ 17 | sdist/ 18 | var/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .tox/ 28 | .coverage 29 | nosetests.xml 30 | coverage.xml 31 | 32 | # Translations 33 | *.mo 34 | 35 | # Mr Developer 36 | .mr.developer.cfg 37 | .project 38 | .pydevproject 39 | -------------------------------------------------------------------------------- /Clients/Python/README.md: -------------------------------------------------------------------------------- 1 | SerialPacket Controller: Controller for the SerialPacket protocol 2 | ================================================================= 3 | A controller application to show Python to Arduino communication using the SerialPacket protocol 4 | 5 | Program flow: 6 | 1. Connect to the Arduino over the serial port 7 | 2. Start the "SerialPacket Controller" 8 | 3. The controller reads incoming data 9 | 4. The controller starts polling for commands 10 | 11 | Installation: 12 | ------------- 13 | * Install the Debian package: ``sudo dpkg -i python-sp-controller_0.x.x-x_all.deb`` 14 | * Download the source and run ``sudo python setup.py install`` 15 | 16 | Usage: 17 | ------ 18 | * Start the program with: ``python -m sp_controller`` 19 | 20 | 21 | Requirements: 22 | ------------- 23 | * Python 2.6+ 24 | * python-serial (e.g. Ubuntu package) 25 | 26 | 27 | Limitations: 28 | ------------ 29 | * probably still some bugs 30 | 31 | License: 32 | -------- 33 | If not stated otherwise sp_controller is distributed in terms of the GPLv2 software license. 34 | See COPYING in the distribution for details. 35 | 36 | Bug reports: 37 | ------------ 38 | * Jeroen Doggen 39 | 40 | Roadmap: 41 | -------- 42 | 43 | 0.3: ?? 44 | 45 | Changelog: 46 | ---------- 47 | 48 | 0.0.2: First threaded version 49 | * Threads started from controller 50 | * Thread 1: Read data from serial port (SerialCommunication class) 51 | * Thread 2: Poll the database for commands (DatabaseCommunication class) 52 | * Sleeptime for all thread can be changed at runtime 53 | 54 | 0.0.1: Initial version: 55 | * startup using cli arguments 56 | * working PyPI compatible python package 57 | * connect to serial 58 | * print info on cli + write to logfile 59 | -------------------------------------------------------------------------------- /Clients/Python/makeDebian.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Small script to create the Debian package & install it when it is done 4 | 5 | echo "Starting package build process" 6 | 7 | python setup.py --command-packages=stdeb.command sdist_dsc 8 | 9 | cd deb_dist/sp-controller-0.0.1/ 10 | 11 | dpkg-buildpackage -rfakeroot -uc -us 12 | 13 | cd .. 14 | 15 | sudo dpkg -i python-sp-controller_0.0.1-1_all.deb 16 | 17 | -------------------------------------------------------------------------------- /Clients/Python/setup.py: -------------------------------------------------------------------------------- 1 | """Setup file for sp 2 | 3 | Define the options for the "sp_controller" package 4 | Create source Python packages (python setup.py sdist) 5 | Create binary Python packages (python setup.py bdist) 6 | 7 | """ 8 | from distutils.core import setup 9 | 10 | from sp_controller import __version__ 11 | 12 | 13 | with open('README.md') as readme_file: 14 | LONG_DESCRIPTION = readme_file.read() 15 | 16 | setup(name='sp_Controller', 17 | version=__version__, 18 | description='Controller for the SerialPacket protocol', 19 | long_description=LONG_DESCRIPTION, 20 | author='Jeroen Doggen', 21 | author_email='jeroendoggen@gmail.com', 22 | url='none', 23 | packages=['sp_controller'], 24 | package_data={'sp_controller': ['*.py', '*.conf']}, 25 | license='LGPL-v2', 26 | platforms=['Linux'], 27 | ) 28 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/__init__.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: Initialize the package 2 | 3 | This file is needed to import the module properly 4 | The version number is used to generate the PyPI package 5 | 6 | """ 7 | __version__ = "0.0.2" -------------------------------------------------------------------------------- /Clients/Python/sp_controller/__main__.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: Main file to run 2 | 3 | This file is needed to be able to run a Python program in a folder directly 4 | by calling "Python foldername" 5 | 6 | """ 7 | 8 | from sp_controller.main import run 9 | 10 | if __name__ == '__main__': 11 | run() 12 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/controller.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: core code 2 | 3 | TODO write some comments 4 | TODO try to restart the threads when they exit 5 | - when disconnecting the usb the serial thread stops 6 | - when reconnecting, the thread should try to restart (after a timeout) 7 | 8 | """ 9 | from __future__ import print_function, division # We require Python 2.6+ 10 | import time 11 | import sys 12 | from Queue import Queue 13 | 14 | 15 | from sp_controller.settings import Settings 16 | 17 | 18 | class QueueSetting: 19 | """The different queues for input/output""" 20 | def __init__(self, sensordata_queue, cmd_reply_queue, cmd_queue): 21 | self.sensordata_queue = sensordata_queue 22 | self.cmd_reply_queue = cmd_reply_queue 23 | self.cmd_queue = cmd_queue 24 | 25 | 26 | class Controller: 27 | """Controller class: does the core of the work""" 28 | sensordata_queue = Queue() 29 | cmd_reply_queue = Queue() 30 | cmd_queue = Queue() 31 | payload_counter = 0 32 | 33 | def __init__(self): 34 | """ Initialize the controller """ 35 | self.queue_settings = QueueSetting(self.sensordata_queue, 36 | self.cmd_reply_queue, 37 | self.cmd_queue) 38 | 39 | self.config = Settings(self.queue_settings) 40 | self.serial_read_thread = self.config.get_serial_read() 41 | self.serial_write_thread = self.config.get_serial_write() 42 | self.errors = 0 43 | 44 | def run(self): 45 | """The main thread for the controller""" 46 | self.start_serial_communication_threads() 47 | while True: 48 | try: 49 | time.sleep(2) 50 | self.send_command() 51 | except KeyboardInterrupt: 52 | print("Program stopped by keyboard interrupt") 53 | sys.exit(1) 54 | 55 | def send_command(self): 56 | # Just send some dummy packets (with a counter for the payload) 57 | self.cmd_queue.put((1, self.payload_counter, 2)) 58 | print("A command has been placed in the queue") 59 | 60 | self.payload_counter += 1 61 | if (self.payload_counter is 255): 62 | self.payload_counter = 0 63 | 64 | def start_serial_communication_threads(self): 65 | """Start serial communication thread""" 66 | self.serial_write_thread.daemon = True 67 | self.serial_write_thread.start() 68 | self.serial_read_thread.daemon = True 69 | self.serial_read_thread.start() 70 | 71 | def exit_value(self): 72 | """TODO: Generate the exit value for the application.""" 73 | if (self.errors == 0): 74 | return 0 75 | else: 76 | return 42 77 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/infoprinter.py: -------------------------------------------------------------------------------- 1 | """ Print information messages 2 | 3 | This is currently used to keep the info messages out of the other code 4 | 5 | """ 6 | 7 | from __future__ import print_function, division # We require Python 2.6+ 8 | 9 | 10 | def double_line(): 11 | """Print a double line""" 12 | print ("=============================================================") 13 | 14 | 15 | def single_line(): 16 | """Print a single line""" 17 | print ("-------------------------------------------------------------") 18 | 19 | 20 | def top(): 21 | """Print the top of the cli message""" 22 | print ("") 23 | double_line() 24 | print ("Starting sp_controller...") 25 | 26 | 27 | def programflow(serial_port): 28 | """Print the program flow""" 29 | print ("") 30 | print ("Program flow: ") 31 | print (" 1. Connect to the Arduino on port: " + serial_port) 32 | print (" 2. Start polling for commands") 33 | print (" 3. Start writing incoming data to the terminal") 34 | print (" repeat forever... ") 35 | print ("") 36 | 37 | 38 | def startup_info(serial_port): 39 | """Print an overview of the startup info""" 40 | top() 41 | programflow(serial_port) 42 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/main.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: core code 2 | 3 | This file is needed to import the module properly 4 | Copyright (C) 2013 Jeroen Doggen 5 | 6 | """ 7 | 8 | import sys 9 | 10 | from sp_controller.controller import Controller 11 | 12 | 13 | def run(): 14 | """Run the main program""" 15 | controller = Controller() 16 | controller.run() 17 | return(controller.exit_value()) 18 | 19 | 20 | if __name__ == "__main__": 21 | sys.exit(run()) 22 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/serialcommunication.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: serial communication 2 | 3 | Serial communication class 4 | - Connect to the serial port 5 | - Allow a thread to be started to read data from the serial port 6 | 7 | """ 8 | 9 | from __future__ import print_function # We require Python 2.6+ 10 | 11 | import sys 12 | import threading 13 | import time 14 | 15 | try: 16 | import serial 17 | except ImportError as exc: 18 | print("Error: failed to import pyserial module") 19 | print("Solution: you probably need to install the pyserial module") 20 | sys.exit(0) 21 | 22 | from sp_controller.serialparser import SerialParser 23 | 24 | 25 | class SerialCommunication(threading.Thread): 26 | """SerialCommunication: handling all serial communication in a thread""" 27 | def __init__(self, 28 | identification, 29 | serialport_settings, 30 | logger, 31 | sleeptime, 32 | queue_settings): 33 | """Initialize the serial port object.""" 34 | self.logger = logger 35 | self.sleeptime = sleeptime 36 | self.sensordata_queue = queue_settings.sensordata_queue 37 | self.cmd_reply_queue = queue_settings.cmd_reply_queue 38 | self.cmd_queue = queue_settings.cmd_queue 39 | self.identification = identification 40 | self.serial_connect(serialport_settings.serial_port, 41 | serialport_settings.baudrate) 42 | self.parser = SerialParser() 43 | threading.Thread.__init__(self) 44 | 45 | def run(self): 46 | """This function will be called when the thread starts""" 47 | while True: 48 | time.sleep(self.sleeptime) 49 | # print(self.identification) 50 | if self.identification == "Packet_receiver": 51 | self.get_packet() 52 | if self.identification == "Command_transmitter": 53 | self.send_commands() 54 | 55 | def check_baudrate(self, baudrate): 56 | """TODO: implement this (now the program hangs on invalid baudrates)""" 57 | pass 58 | # if baudrate != 115200: 59 | # print("Baudrate error") 60 | # sys.exit() 61 | 62 | def serial_connect(self, serial_port, baudrate): 63 | """Connect to serial port""" 64 | try: 65 | self.check_baudrate(baudrate) 66 | self.ser = serial.Serial(serial_port, baudrate) 67 | self.ser.flush() 68 | self.logger.info(self.identification 69 | + " : Connected to serial port: " 70 | + serial_port 71 | + " with speed:" + str(baudrate)) 72 | print(self.identification 73 | + " : connected to serial port: ", end="") 74 | print(serial_port, end="") 75 | print(" with speed: ", end="") 76 | print(baudrate) 77 | except: 78 | self.logger.critical("Unable to connect to serial port: " 79 | + serial_port 80 | + " with speed:" 81 | + str(baudrate)) 82 | print("Unable to connect to serial port: ", end="") 83 | print(serial_port, end="") 84 | print(" with speed: ", end="") 85 | print(baudrate) 86 | sys.exit(1) 87 | 88 | def read_line(self): 89 | """Read one line of text over the serial port""" 90 | try: 91 | line = self.ser.readline()[:-1] 92 | # line = self.ser.readline().decode('utf-8')[:-1] 93 | return(line) 94 | except IOError: 95 | self.logger.critical("Lost serial connection") 96 | print ("Lost serial connection") 97 | #self.failed_test_list.append(current_test) 98 | sys.exit(1) 99 | 100 | def set_sleeptime(self, sleeptime): 101 | """Set the sleeptime for the thread""" 102 | self.sleeptime = sleeptime 103 | 104 | def get_packet(self): 105 | """Get one serial packet (one line of data)""" 106 | packet = self.read_line()[:-1] 107 | print("Incoming packet: " + packet) # Print packet (HEX format) 108 | packet = self.parser.parse(packet) 109 | print(packet) # Print out all info about the packet (human readable) 110 | print("") # Print empty line 111 | if packet != 0: 112 | self.sensordata_queue.put(packet) 113 | 114 | def send_commands(self): 115 | """Send commands from the queue to the serial ports""" 116 | if not self.cmd_queue.empty(): 117 | command = self.cmd_queue.get() 118 | #print(command) 119 | #self.cmd_queue.join 120 | command_id = command[0] 121 | payload = command[1] 122 | node_id = command[2] 123 | self.send_command(command_id, payload, node_id) 124 | 125 | # print(command) 126 | 127 | def send_old_command(self, value): 128 | """Send a command packet: compatible with command queue (deprecated: june 2013)""" 129 | # print(value) 130 | value = map(int, value) # convert command elements in list to int 131 | # print(value) 132 | value = value[0] # get first int from list 133 | print("Command in db: ", value) 134 | if (value < 256): 135 | #value = self.converter.db_to_serial(value) 136 | value = hex(value) # convert to hex string 137 | # print(value) 138 | value = value[2:4] # trow away 0x in front of hex string 139 | # print(value) 140 | parity = 0x01 ^ 0x00 ^ 0x12 ^ int(value, 16) # calculate parity 141 | parity = hex(parity) # convert to hex string 142 | parity = parity[2:4] # throw away 0x in front of sting 143 | ## parity = "EC" 144 | self.ser.write("T01N00I12P" + str(value) + "Q" 145 | + str(parity) + "\r") 146 | print("Command for Arduino: " + str(value), "HEX") 147 | 148 | def send_command(self, command_id, payload, node_id): 149 | """Send a command packet""" 150 | # Debug info: 151 | print("Command: ", self.hex_converter(command_id)) 152 | print("Payload: ", self.hex_converter(payload)) 153 | print("Node_id: ", self.hex_converter(node_id)) 154 | 155 | # Calculate parity field: 156 | parity = 0x01 ^ node_id ^ command_id ^ payload 157 | parity = self.hex_converter(parity) 158 | 159 | # Convert to hex 160 | command_id = self.hex_converter(command_id) 161 | payload = self.hex_converter(payload) 162 | node_id = self.hex_converter(node_id) 163 | 164 | # Create packet 165 | packet = "T01" + "N" + str(node_id) + "I" + str(command_id) + "P" + str(payload) + "Q" + str(parity) + "\r" 166 | print(packet) 167 | 168 | # Send packet 169 | self.ser.write(packet) 170 | print("") 171 | 172 | def hex_converter(self, value): 173 | # print("Input: ", end="") 174 | # print(value) 175 | value = hex(value) 176 | value = value[2:4] 177 | if (int(value,16) < 16): 178 | value = "0" + value 179 | # print("Output: ", end="") 180 | # print(value) 181 | return(value) 182 | 183 | 184 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/serialparser.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: serial parser 2 | 3 | Serial parser class 4 | 5 | """ 6 | 7 | from __future__ import print_function # We require Python 2.6+ 8 | import datetime 9 | 10 | 11 | class SerialParser(): 12 | """SerialParser: parser for SerialPacket data""" 13 | def __init__(self): 14 | pass 15 | #self.converter = DataConverter() 16 | 17 | def parse(self, packet): 18 | """Parse a packet""" 19 | self.now = datetime.datetime.now() 20 | if self.validate_packet(packet): 21 | if self.get_packet_type(packet) == 0x01: # 22 | return(self.parse_data(packet)) 23 | if self.get_packet_type(packet) == 0x02: # COMMAND_REPLY 24 | return(self.parse_data(packet)) 25 | else: 26 | return 0 27 | 28 | def parse_data(self, packet): 29 | """Parse the data""" 30 | # print (self.get_sensor_id(packet), 31 | # " becomes ", 32 | # self.converter.serial_to_db(self.get_sensor_id(packet))) 33 | return(self.get_node_id(packet), 34 | self.get_sensor_id(packet), 35 | self.get_payload(packet), 36 | str(self.now)) 37 | 38 | def validate_packet(self, packet): 39 | """Validate an incoming packet using parity control""" 40 | if len(packet) == 15: 41 | self.received_parity = self.get_quality_check(packet) 42 | self.calculated_parity = (int(packet[1:3], 16) 43 | ^ int(packet[4:6], 16) 44 | ^ int(packet[7:9], 16) 45 | ^ int(packet[10:12], 16)) 46 | # print(self.received_parity) 47 | # print(self.calculated_parity) 48 | if self.received_parity == self.calculated_parity: 49 | return True 50 | else: 51 | return False 52 | 53 | def get_packet_type(self, packet): 54 | """Get the packet type""" 55 | if self.validate_packet(packet): 56 | if packet[0] == 'T': 57 | return self.hex_to_dec(packet[1:3]) 58 | else: 59 | return 0 60 | 61 | def get_node_id(self, packet): 62 | """Get the node id""" 63 | if packet[3] == 'N': 64 | return self.hex_to_dec(packet[4:6]) 65 | else: 66 | return 0 67 | 68 | def get_sensor_id(self, packet): 69 | """Get the sensor id""" 70 | if packet[6] == 'I': 71 | return self.hex_to_dec(packet[7:9]) 72 | else: 73 | return 0 74 | 75 | def get_payload(self, packet): 76 | """Get the payload""" 77 | if packet[9] == 'P': 78 | return self.hex_to_dec(packet[10:12]) 79 | else: 80 | return 0 81 | 82 | def get_quality_check(self, packet): 83 | """Get the parity 'quality check'""" 84 | if packet[12] == 'Q': 85 | return self.hex_to_dec(packet[13:15]) 86 | else: 87 | return 0 88 | 89 | def hex_to_dec(self, hexvalue): 90 | """Convert hex value to decimal""" 91 | return int(hexvalue, 16) 92 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/settings.py: -------------------------------------------------------------------------------- 1 | """ sp_controller: Settings class 2 | 3 | get the cli arguments 4 | set the logfile 5 | set the serial port 6 | 7 | """ 8 | 9 | from __future__ import print_function, division # We require Python 2.6+ 10 | 11 | import argparse 12 | import logging 13 | import os 14 | import sys 15 | 16 | import infoprinter 17 | from sp_controller.serialcommunication import SerialCommunication 18 | from sp_controller.__init__ import __version__ 19 | 20 | 21 | DEFAULT_PORT = "/dev/ttyUSB0" 22 | DEFAULT_BAUDRATE = 115200 23 | DEFAULT_LOGFILE = "sp_controller.log" 24 | DEFAULT_SERIAL_READ_SLEEPTIME = 0.1 25 | DEFAULT_SERIAL_WRITE_SLEEPTIME = 0.1 26 | #keep this around 0.5 (Arduino gets confused!! (buffer overflow?) 27 | DEFAULT_PATH = os.getcwd() + "/" 28 | 29 | 30 | class SerialportSetting: 31 | """The serial port settings""" 32 | def __init__(self, serial_port, baudrate): 33 | self.serial_port = serial_port 34 | self.baudrate = baudrate 35 | 36 | 37 | class Settings: 38 | """Configure the settings of the program""" 39 | path = DEFAULT_PATH 40 | logfile = path + DEFAULT_LOGFILE 41 | 42 | serial_read_sleeptime = DEFAULT_SERIAL_READ_SLEEPTIME 43 | serial_write_sleeptime = DEFAULT_SERIAL_WRITE_SLEEPTIME 44 | 45 | parser = argparse.ArgumentParser( 46 | prog="sp_controller", 47 | formatter_class=argparse.RawDescriptionHelpFormatter, 48 | description="sp_controller commandline arguments:", 49 | epilog="Report bugs to jeroendoggen@gmail.com.") 50 | 51 | def __init__(self, queue_settings): 52 | """Initialize""" 53 | self.serialport_settings = SerialportSetting(DEFAULT_PORT, 54 | DEFAULT_BAUDRATE) 55 | self.queue_settings = queue_settings 56 | self.cli_arguments() 57 | infoprinter.startup_info(self.serialport_settings.serial_port) 58 | self.set_logfile() 59 | self.set_serialport() 60 | 61 | def cli_arguments(self): 62 | """Configure a read all the cli arguments.""" 63 | self.configure_cli_arguments() 64 | self.get_cli_arguments() 65 | 66 | def configure_cli_arguments(self): 67 | """Configure all the cli arguments.""" 68 | self.parser.add_argument("-p", metavar="port", 69 | help="Set the name of the serial port") 70 | self.parser.add_argument("-f", metavar="file", 71 | help="Set the name of the logfile") 72 | self.parser.add_argument("-b", metavar="baudrate", 73 | help="Set the baudrate of the serial port") 74 | 75 | def get_cli_arguments(self): 76 | """Read all the cli arguments.""" 77 | args = self.parser.parse_args() 78 | if (args.p is not None): 79 | self.serialport_settings.serial_port = args.p 80 | if (args.b is not None): 81 | self.serialport_settings.baudrate = args.b 82 | if (args.f is not None): 83 | self.logfile = self.path + args.f 84 | 85 | def set_logfile(self): 86 | """Set the logfile where we will write error & info messages""" 87 | try: 88 | logging.basicConfig(filename=self.logfile, 89 | level=logging.DEBUG, 90 | format="%(asctime)s %(name)s %(levelname)s %(message)s") 91 | self.logger = logging.getLogger(__name__) 92 | except IOError: 93 | print("Unable to open logfile") 94 | print("Do you have write access in the current folder?") 95 | sys.exit(0) 96 | 97 | def set_serialport(self): 98 | """Set the serial port""" 99 | #TODO: they should only get one queue (not two) 100 | self.sp_read = SerialCommunication("Packet_receiver ", 101 | self.serialport_settings, 102 | self.logger, 103 | self.serial_read_sleeptime, 104 | self.queue_settings) 105 | self.sp_write = SerialCommunication("Command_transmitter", 106 | self.serialport_settings, 107 | self.logger, 108 | self.serial_write_sleeptime, 109 | self.queue_settings) 110 | 111 | def get_serial_read(self): 112 | """Get the serialcommunication object (used in controller)""" 113 | return(self.sp_read) 114 | 115 | def get_serial_write(self): 116 | """Get the serialcommunication object (used in controller)""" 117 | return(self.sp_write) 118 | -------------------------------------------------------------------------------- /Clients/Python/sp_controller/tests/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class TestTheSuite(unittest.TestCase): 5 | """A placeholder for unit tests of this Python program""" 6 | 7 | def setUp(self): 8 | self.seq = range(10) 9 | 10 | def test_exitValueZero(self): 11 | self.assertEqual(0, 0) 12 | 13 | if __name__ == '__main__': 14 | unittest.main() 15 | -------------------------------------------------------------------------------- /Documentation/latex/refman.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeroendoggen/Arduino-serial-messaging/87bdc590bfb85e6d31165f1c8e87f0d09042c8cc/Documentation/latex/refman.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Library to exchange short messages (sensordata, commands) between an Arduino and a software application running on a PC. (Linux, embedded Linux, Windows, OS X) (clients currently under development) 2 | 3 | Both sides are able send and receive a range of "standardised" messages over the serial port. All communication is done by sending short human readable ASCII messages. We define several standard command and data packet IDs to provide interoperability between different applications. 4 | 5 | The protocol was designed to be relatively easy to comprehend and process by both human and computer. 6 | * A standardised message structure (more info below) 7 | * All fields in a message are separated by delimiters (just a letter indicating what the next field will be) 8 | * All communication is in HEX ASCII values (to allow human and computer to understand the packets) 9 | * Invalid messages are detected by calculating the parity (XOR all serial bytes) 10 | 11 | ## The Message Types 12 | 13 | The library support seven basic packet types. 14 | 15 | * "Command": start motor, blink LED, go to sleep mode,... 16 | * "Command Reply": e.g. motor started, LED blinking, going to sleep mode now,... 17 | * "8-bit Data": (standard Arduino Byte type): e.g. temperature is 25 C, distance is 50 cm, humidity is 56% 18 | * "16-bit Data": (standard Arduino int type): e.g. temperature is -25 C, distance is 310 cm, time is 16200 seconds, ... 19 | * "Data array": send multiple sensor measurements in one burst (useful when sampling very rapidly) 20 | * "Data request": e.g. send me the temperature, distance, humidity, ... 21 | * "Data array request": e.g. send me a burst of measurements 22 | 23 | More info in [`defines.h`](https://github.com/jeroendoggen/Arduino-serial-messaging/blob/master/SerialPacket/defines.h) 24 | 25 | ## Standard Messages 26 | 27 | *Data messages* are used when we want to send sensor data from the Arduino to applications running on a PC. [More info](https://github.com/jeroendoggen/Arduino-serial-messaging/wiki/Sensordata-messages) 28 | 29 | *Command messages* are used when we want to send instructions from one application to the Arduino module. [More info](https://github.com/jeroendoggen/Arduino-serial-messaging/wiki/Command-messages) 30 | 31 | We define several standard command and data message IDs. The actual meaning of the payload of these messages is standardised to provide interoperability between different applications (00h -> 7Fh). Half of the packet IDs are undefined (80h -> FFh). These IDs can be chosen based on the needs of your own application. 32 | 33 | 34 | ## Example Messages 35 | 36 | Command message **T01N00I12PFFQ21** : "set motor speed of 'Arduino zero' to +100%: 37 | 38 | * **T01**: Type 01: Command message 39 | * **N00**: Number 00: Node number 00 (is the destination) 40 | * **I12**: CommandID 12: Set motor speed 41 | * **PFF**: Payload FF: full speed (range: 0 (reverse) -> 80 (stopped) -> FF (forward)) 42 | * **Q21**: Quality 21: parity byte is 21 43 | 44 | Data message **T12N00I10P08Q0A** : "temperature of 'Arduino zero' is 8 degrees" 45 | 46 | * **T12**: Type 12: Data message (1 byte payload) 47 | * **N00**: Number 00: Node number 00 (is the source) 48 | * **I10**: SensorID 10: Temperature 49 | * **P08**: Payload 08: 8 degrees 50 | * **Q0A**: Quality 0A: parity byte is 0A 51 | 52 | 53 | ## Sending Messages from Arduino Code 54 | 55 | * sendCommand(commandID,payload) 56 | * sendCommandReply(commandID,payload) 57 | 58 | * sendData(sensorID,payload) 59 | * sendDataRequest(sensorID,payload) 60 | 61 | * sendDataArray(sensorID,payload) 62 | * sendDataArrayRequest(sensorID,payload) 63 | 64 | Example sketch: [`SendPackets.ino`](https://github.com/jeroendoggen/Arduino-serial-messaging/blob/master/SerialPacket/examples/SendPackets/SendPackets.ino) 65 | 66 | ## PC Clients 67 | 68 | * [Python library](https://github.com/jeroendoggen/Arduino-serial-messaging/tree/master/Clients/Python): receive & send packets (using queues & threads) 69 | * [C# library](https://github.com/jeroendoggen/Arduino-serial-messaging/tree/master/Clients): send & receive messages (coming soon) 70 | * [RRDTool sensorlogging](https://github.com/jeroendoggen/Arduino-serial-messaging/tree/master/Clients/Collectd): write Arduino sensor data into an RRDtool database using collectd 71 | * [Packet Inspector](https://github.com/jeroendoggen/Arduino-serial-messaging/tree/master/Clients/Processing): a GUI written in the Processing language to show a incoming data packets 72 | -------------------------------------------------------------------------------- /SerialPacket/Protocol.txt: -------------------------------------------------------------------------------- 1 | Old info below!! 2 | 3 | Packet types: 4 | 1. Command + {get,set} 5 | Format: "Type:01 NodeID:02 CommandID:06 Data:00 Parity:03" 6 | 7 | 2. Command + {ack,reply} 8 | Format: "Type:02 NodeID:02 CommandID:06 Data:05 Parity:05" 9 | 10 | 3. Data request + {payload} 11 | (requests correspond to type4 packets) 12 | Format: "Type:03 NodeID:02 SensorID:04 Data:00 Parity:05" 13 | 14 | 4. Data + {payload} 15 | Format: "Type:04 NodeID:02 SensorID:04 Data:05 Parity:07" 16 | 17 | 5. Aggregated data + {array payload} 18 | Format: "Type:05 NodeID:02 SensorID:04 Data:0102030405 Parity:02" 19 | 20 | Older info below!! 21 | 22 | Sensor Pakket: 23 | -------------- 24 | 25 | Voorbeeld: 26 | TY0NI1SI1VA25PAxx : Sensor pakket, van node 1, afstandsensor, 25 cm 27 | TY0NI1SI8VA32PAxx : Sensor pakket, van node 1, temperatuurssensor, 32 graden 28 | TY0NI1SI32VA25.32.70PAxx : Sensor pakket, van node 1, 25 cm, 32 graden, 70% vocht 29 | 30 | SI: Sensor ID 31 | 0: state 32 | 1: afstand 33 | 8: temperatuur 34 | 16: vochtigheid 35 | 32: composite sensordata: afstand.temperatuur.vochtigheid 36 | 37 | VA: Value: de sensordata: tussen 0 en 255 38 | 39 | States: 40 | 0: Initialising system 41 | 1: Started 42 | 2: Stopped 43 | 3: Motor running 44 | 4: Motor stopped 45 | 5: Error 46 | 6: Lost uplink 47 | 48 | PA: Parity 49 | 50 | Commando Pakket: 51 | ---------------- 52 | 53 | Voorbeeld: 54 | TY1NI0CM0 : Commando pakket, voor node 0, stop motor 55 | TY1NI1CM2VA50 : Commando pakket, voor node 1, set motorspeed 50% 56 | 57 | CM: 58 | 0: Stop motor 59 | 1: Start motor 60 | 2: Set motorspeed + payload (0 - 100 %) 61 | 3: Set sensor samplerate + payload (100 ms - 10 s) 62 | 4: Set upload rate + payload (1 s -> 100 s) ? 63 | 5: 64 | -------------------------------------------------------------------------------- /SerialPacket/SerialPacket.cpp: -------------------------------------------------------------------------------- 1 | // SerialPacket.cpp - Library for sending serial data packets 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // For more information: variable declaration, changelog,... see SerialPacket.h 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | /// 20 | /// SerialPacket.cpp - Library for sending sensor data packets over UART. 21 | /// For more information: variable declaration, changelog,... see SerialPacket.h 22 | /// 23 | 24 | #include 25 | #include "SerialPacket.h" 26 | #include "defines.h" 27 | 28 | /// 29 | /// Constructor 30 | /// 31 | SerialPacket::SerialPacket() : _inputChar() 32 | { 33 | _inComingPacketComplete = false; 34 | _incomingCounter=0; 35 | incomingPacket.packetType=0; 36 | incomingPacket.nodeID=0; 37 | incomingPacket.sensorID=0; 38 | incomingPacket.commandID=0; 39 | incomingPacket.payload=0; 40 | incomingPacket.parity=0; 41 | newPacket = false; 42 | } 43 | 44 | /// 45 | /// Begin using default settings: 46 | /// - speed: 115200 baud 47 | /// - nodeID: 0 48 | /// 49 | void SerialPacket::begin() 50 | { 51 | begin (DEFAULT_BAUDRATE,0); 52 | } 53 | 54 | /// 55 | /// Begin using custom settings 56 | /// 57 | void SerialPacket::begin(long speed, uint8_t nodeID) 58 | { 59 | Serial.begin(speed); 60 | setNodeID(nodeID); 61 | } 62 | 63 | /// 64 | /// Send a single command 65 | /// 66 | void SerialPacket::sendCommand(uint8_t commandID, uint8_t payload) 67 | { 68 | setPacketType(COMMAND); 69 | setCommandID(commandID); 70 | sendPacket(payload); 71 | } 72 | 73 | /// 74 | /// Send a single command, reuses commandID from previous packets 75 | /// 76 | void SerialPacket::sendCommand(uint8_t payload) 77 | { 78 | setPacketType(COMMAND); 79 | sendPacket(payload); 80 | } 81 | 82 | /// 83 | /// Send a reply to a command 84 | /// 85 | void SerialPacket::sendCommandReply(uint8_t commandID, uint8_t payload) 86 | { 87 | setPacketType(COMMAND_REPLY); 88 | setCommandID(commandID); 89 | sendPacket(payload); 90 | } 91 | 92 | /// 93 | /// Request a single data value 94 | /// 95 | void SerialPacket::sendDataRequest(uint8_t sensorID, uint8_t payload) 96 | { 97 | setPacketType(DATA_REQUEST); 98 | setSensorID(sensorID); 99 | sendPacket(payload); 100 | } 101 | 102 | /// 103 | /// Request an array of data values 104 | /// 105 | void SerialPacket::sendDataArrayRequest(uint8_t arrayID, uint8_t payload) 106 | { 107 | setPacketType(DATA_ARRAY_REQUEST); 108 | setSensorID(arrayID); 109 | sendPacket(payload); 110 | } 111 | 112 | /// 113 | /// Send a single data value 114 | /// 115 | void SerialPacket::sendData(uint8_t sensorID, uint8_t payload) 116 | { 117 | setPacketType(DATA_BYTE); 118 | setSensorID(sensorID); 119 | sendPacket(payload); 120 | } 121 | 122 | /// 123 | /// Send a single data value 124 | /// 125 | void SerialPacket::sendData(uint8_t sensorID, int16_t payload) 126 | { 127 | setPacketType(DATA_INT); 128 | setSensorID(sensorID); 129 | sendPacket(payload); 130 | } 131 | 132 | /// 133 | /// Send a single 8-bit data value (Arduino 'byte' type), reuses sensorID from previous packets 134 | /// 135 | void SerialPacket::sendData(uint8_t payload) 136 | { 137 | setPacketType(DATA_BYTE); 138 | sendPacket(payload); 139 | } 140 | 141 | /// 142 | /// Send a single 16-bit data value (Arduino 'int' type), reuses sensorID from previous packets 143 | /// 144 | void SerialPacket::sendData(int16_t payload) 145 | { 146 | setPacketType(DATA_INT); 147 | sendPacket(payload); 148 | } 149 | 150 | /// 151 | /// Send out the actual 8-bit data packet (called from other 'send' functions) 152 | /// 153 | void SerialPacket::sendPacket(uint8_t& payload) 154 | { 155 | Serial.print("T"); 156 | hexPrinting(_packetType); 157 | Serial.print("N"); 158 | hexPrinting(_nodeID); 159 | Serial.print("I"); 160 | if ((_packetType == COMMAND) | (_packetType == COMMAND_REPLY)) { 161 | hexPrinting(_commandID); 162 | _parity=_packetType^_nodeID^_commandID^payload; 163 | } 164 | else if ((_packetType == DATA_ARRAY_REQUEST) | (_packetType == DATA_BYTE) | (_packetType == DATA_REQUEST)) { 165 | hexPrinting(_sensorID); 166 | _parity=_packetType^_nodeID^_sensorID^payload; 167 | } 168 | Serial.print("P"); 169 | hexPrinting(payload); 170 | Serial.print("Q"); 171 | hexPrinting(_parity); 172 | Serial.println(""); 173 | } 174 | 175 | /// 176 | /// Send out the actual 16-bit data packet (called from other 'send' functions) 177 | /// 178 | void SerialPacket::sendPacket(int16_t& payload) 179 | { 180 | _parity=_packetType^_nodeID^_sensorID^payload; 181 | Serial.print("T"); 182 | hexPrinting(_packetType); 183 | Serial.print("N"); 184 | hexPrinting(_nodeID); 185 | Serial.print("I"); 186 | if ((_packetType == COMMAND) | (_packetType == COMMAND_REPLY)) { 187 | hexPrinting(_commandID); 188 | } 189 | //_packetType == DATA_ARRAY_REQUEST (not yet implemented as a separate function) 190 | else if ((_packetType == DATA_ARRAY_REQUEST) | (_packetType == DATA_INT) | (_packetType == DATA_REQUEST)) { 191 | hexPrinting(_sensorID); 192 | } 193 | Serial.print("P"); 194 | hexPrinting(payload); 195 | Serial.print("Q"); 196 | hexPrinting(_parity); 197 | Serial.println(""); 198 | } 199 | 200 | /// 201 | /// Send multiple data samples in one packet by passing an array and its length 202 | /// 203 | void SerialPacket::sendDataArray(uint8_t *dataArray, uint8_t length) 204 | { 205 | setSensorID(length); //sensorID contains the length of the data array (can be used at receiving side) 206 | _parity=_packetType^_nodeID^_sensorID; 207 | Serial.print("T"); 208 | hexPrinting(_packetType); 209 | Serial.print("N"); 210 | hexPrinting(_nodeID); 211 | Serial.print("I"); 212 | hexPrinting(_sensorID); 213 | Serial.print("P"); 214 | 215 | for(int i=0 ; i 225 | /// Set commandID 226 | /// 227 | void SerialPacket::setCommandID(uint8_t& commandID) 228 | { 229 | _commandID=commandID; 230 | } 231 | 232 | /// 233 | /// Set packet type 234 | /// 235 | void SerialPacket::setPacketType(uint8_t type) 236 | { 237 | _packetType=type; 238 | } 239 | 240 | /// 241 | /// HexPrinting: helper function to print data with a constant field width (2 hex values) 242 | /// 243 | void SerialPacket::hexPrinting(uint8_t& data) 244 | { 245 | if(data<16) { 246 | Serial.print(0, HEX); 247 | } 248 | Serial.print(data, HEX); 249 | } 250 | 251 | /// 252 | /// HexPrinting: helper function to print data with a constant field width (2 hex values) 253 | /// 254 | void SerialPacket::hexPrinting(int16_t& data) 255 | { 256 | if(data<4096 && data>0) { 257 | Serial.print(0, HEX); 258 | } 259 | if(data<256 && data>0) { 260 | Serial.print(0, HEX); 261 | } 262 | if(data<16 && data>0) { 263 | Serial.print(0, HEX); 264 | } 265 | Serial.print(uint16_t(data), HEX); //casting to suppress FFFF for negative int values 266 | } 267 | 268 | /// 269 | /// Set nodeID 270 | /// 271 | void SerialPacket::setNodeID(uint8_t& nodeID) 272 | { 273 | _nodeID=nodeID; 274 | } 275 | 276 | /// 277 | /// Set sensorID 278 | /// 279 | void SerialPacket::setSensorID(uint8_t& sensorID) 280 | { 281 | _sensorID=sensorID; 282 | } 283 | 284 | /// 285 | /// Set readSerialData 286 | /// 287 | boolean SerialPacket::readSerialData() 288 | { 289 | while (Serial.available() && _inputChar[_incomingCounter] != '\n' ) { 290 | _inputChar[_incomingCounter]=(char)Serial.read(); 291 | _incomingCounter++; 292 | // This checks for a minimum lenght (longer is also ok.. problem?) 293 | if (_incomingCounter == 16) { 294 | newPacket = true; 295 | } 296 | } 297 | 298 | //Flush buffer 299 | while (Serial.read() >= 0){} 300 | 301 | // parseSerialData(); 302 | // Does not work when parsing is called in the return statement 303 | _incomingCounter=0; 304 | return (parseSerialData()); 305 | } 306 | 307 | /// 308 | /// Set parseSerialData 309 | /// 310 | /// @todo: error handling: illegal payloads is now handled by char position (G2 -> 02, 2G -> 20, GG -> 00), requires hextodec reimplementation (when HEX_DEC_ERROR=0) 311 | boolean SerialPacket::parseSerialData() 312 | { 313 | incomingPacket.packetType = hex_to_dec(_inputChar[1])*16 + hex_to_dec(_inputChar[2]); 314 | 315 | incomingPacket.nodeID = hex_to_dec(_inputChar[4])*16 + hex_to_dec(_inputChar[5]); 316 | incomingPacket.payload = hex_to_dec(_inputChar[10])*16 + hex_to_dec(_inputChar[11]); 317 | // casting error hex vs decimal (in if) 318 | if ((incomingPacket.packetType == COMMAND) | (incomingPacket.packetType == COMMAND_REPLY)) { 319 | //Serial.println("parseSerialData"); 320 | incomingPacket.commandID = hex_to_dec(_inputChar[7])*16 + hex_to_dec(_inputChar[8]); 321 | //Serial.println(incomingPacket.commandID); 322 | _checkedParity = incomingPacket.packetType^incomingPacket.nodeID^incomingPacket.commandID^incomingPacket.payload; 323 | } 324 | else if ((incomingPacket.packetType == DATA_INT) | (incomingPacket.packetType == DATA_BYTE) | (incomingPacket.packetType == DATA_REQUEST)) { 325 | incomingPacket.sensorID = hex_to_dec(_inputChar[7])*16 + hex_to_dec(_inputChar[8]);; 326 | _checkedParity = incomingPacket.packetType^incomingPacket.nodeID^incomingPacket.sensorID^incomingPacket.payload; 327 | } 328 | incomingPacket.parity = hex_to_dec(_inputChar[13])*16 + hex_to_dec(_inputChar[14]); 329 | 330 | #ifdef DEBUG_SERIAL 331 | printInfo(); 332 | #endif 333 | 334 | if (newPacket) { 335 | newPacket=false; 336 | return checkParity(); 337 | } 338 | else { 339 | return false; 340 | } 341 | } 342 | 343 | /// 344 | /// Check if all the field in the packet have acceptable value 345 | /// @TODO: implement this 346 | /// 347 | boolean SerialPacket::validatePacketFields() 348 | { 349 | if (true){ 350 | return true; 351 | } 352 | else{ 353 | return false; 354 | } 355 | } 356 | 357 | 358 | /// 359 | /// Convert HEX to Decimal 360 | /// 361 | #define HEX_DEC_ERROR 0 362 | uint8_t SerialPacket::hex_to_dec(uint8_t in) 363 | { 364 | if(((in >= '0') && (in <= '9'))) return in-'0'; 365 | in |= 0x20; 366 | if(((in >= 'a') && (in <= 'f'))) return in-'a' + 10; 367 | return HEX_DEC_ERROR; 368 | } 369 | 370 | /// 371 | /// printInfo: 372 | /// 373 | void SerialPacket::printInfo() 374 | { 375 | Serial.print("Type: "); 376 | Serial.println(incomingPacket.packetType,HEX); 377 | Serial.print("NodeID: "); 378 | Serial.println(incomingPacket.nodeID,HEX); 379 | Serial.print("SensorID: "); 380 | Serial.println(incomingPacket.sensorID,HEX); 381 | Serial.print("CommandID "); 382 | Serial.println(incomingPacket.commandID,HEX); 383 | Serial.print("Payload: "); 384 | Serial.println(incomingPacket.payload,HEX); 385 | Serial.print("Parity: "); 386 | Serial.println(incomingPacket.parity,HEX); 387 | Serial.println("------------"); 388 | Serial.print("Checked parity: "); 389 | Serial.println(_checkedParity,HEX); 390 | Serial.println("------------"); 391 | } 392 | 393 | /// 394 | /// Check parity 395 | /// 396 | boolean SerialPacket::checkParity() 397 | { 398 | if (_checkedParity == incomingPacket.parity){ 399 | #ifdef DEBUG_SERIAL 400 | Serial.println("Parity ok"); 401 | Serial.println("----------------"); 402 | #endif 403 | return true; 404 | } 405 | else{ 406 | #ifdef DEBUG_SERIAL 407 | Serial.println("Parity wrong"); 408 | #endif 409 | return false; 410 | } 411 | } 412 | 413 | /// 414 | /// Get commandID 415 | /// 416 | uint8_t SerialPacket::getCommandID() 417 | { 418 | return incomingPacket.commandID; 419 | } 420 | 421 | /// 422 | /// Get getPayload 423 | /// 424 | uint8_t SerialPacket::getPayload() 425 | { 426 | return incomingPacket.payload; 427 | } -------------------------------------------------------------------------------- /SerialPacket/SerialPacket.h: -------------------------------------------------------------------------------- 1 | // SerialPacket.h - Library for sending serial data packets 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // 4 | // Version History: 5 | // Version 0.1: Send single data sample in a packet 6 | // Version 0.2: Send arrays with multiple samples in a packet 7 | // Version 0.3: Conditional compilation: SERIAL_ASCII vs SERIAL_BINARY (includes.h) 8 | // Version 0.4: hexPrinting helper, changed packet types, commandID/packet 9 | // Version 0.5: added 'sendCommand', 'sendData', ... functions (replacing the generic 'sendPacket') 10 | // removed condition compilation from v0.3 11 | // shortened serial ASCII messages ('Type' -> 'T', 'NodeID' -> 'N') 12 | // Version 0.6: Added support for packets with 16-bit payload (renamed packet types -> hex values) 13 | // Added "dataArrayRequest" packet 14 | // Version 0.7: processing incoming packets 15 | // Roadmap: 16 | // Version 0.7: send 16-bit data arrays 17 | // Separate classes for commands vs data packets? 18 | // Version 0.8: ?? 19 | // 20 | // This library is free software; you can redistribute it and/or 21 | // modify it under the terms of the GNU Lesser General Public 22 | // License as published by the Free Software Foundation; either 23 | // version 2.1 of the License, or (at your option) any later version. 24 | // 25 | // This library is distributed in the hope that it will be useful, 26 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 28 | // Lesser General Public License for more details. 29 | // 30 | // You should have received a copy of the GNU Lesser General Public 31 | // License along with this library; if not, write to the Free Software 32 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 33 | 34 | #ifndef SerialPacket_h 35 | #define SerialPacket_h 36 | #include 37 | 38 | class SerialPacket 39 | { 40 | public: 41 | SerialPacket(); 42 | 43 | void begin(); 44 | void begin(long speed, uint8_t nodeID); 45 | 46 | void sendCommand(uint8_t commandID, uint8_t payload); 47 | void sendCommand(uint8_t payload); 48 | void sendCommandReply(uint8_t commandID, uint8_t payload); 49 | 50 | void sendDataRequest(uint8_t sensorID, uint8_t payload); 51 | void sendData(uint8_t sensorID, uint8_t payload); 52 | void sendData(uint8_t sensorID, int16_t payload); 53 | 54 | void sendData(uint8_t payload); 55 | void sendData(int16_t payload); 56 | 57 | void sendDataArrayRequest(uint8_t arrayID, uint8_t length); 58 | void sendDataArray(uint8_t *dataArray, uint8_t length); 59 | 60 | boolean readSerialData(); 61 | uint8_t getCommandID(); 62 | uint8_t getPayload(); 63 | 64 | private: 65 | struct packet 66 | { 67 | uint8_t packetType; 68 | uint8_t nodeID; 69 | uint8_t sensorID; 70 | uint8_t commandID; 71 | uint8_t payload; 72 | uint8_t parity; 73 | } incomingPacket, outgoingPacket; //TODO: also use this struct to send packets? (todo underscore) 74 | 75 | uint8_t _packetType; 76 | uint8_t _nodeID; 77 | uint8_t _sensorID; 78 | uint8_t _commandID; 79 | uint8_t _parity; 80 | uint8_t _checkedParity; 81 | 82 | boolean _inComingPacketComplete; 83 | char _inputChar[20]; 84 | uint8_t _incomingCounter; 85 | 86 | void sendPacket(uint8_t& payload); 87 | void sendPacket(int16_t& payload); 88 | void setPacketType(uint8_t type); 89 | void setCommandID(uint8_t& commandID); 90 | void setSensorID(uint8_t& sensorID); 91 | void setNodeID(uint8_t& nodeID); 92 | void hexPrinting(uint8_t& data); 93 | void hexPrinting(int16_t& data); 94 | uint8_t hex_to_dec(uint8_t in); 95 | boolean parseSerialData(); 96 | void printInfo(); 97 | boolean checkParity(); 98 | boolean newPacket; 99 | boolean validatePacketFields(); 100 | }; 101 | #endif 102 | -------------------------------------------------------------------------------- /SerialPacket/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## 3 | # build.sh - Script to build several Arduino .ino files at the same time 4 | # 1. Build the source 5 | # 2. Static code analysis using cppcheck 6 | # 3. Fix indentation using bcpp 7 | # 8 | # Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 9 | # 10 | # This program is free software; you can redistribute it and/or 11 | # modify it under the terms of the GNU Lesser General Public 12 | # License as published by the Free Software Foundation; either 13 | # version 2.1 of the License, or (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | # Lesser General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Lesser General Public 21 | # License along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | START=$(date +%s) 25 | START2=$(date) 26 | 27 | ################################################################## 28 | # SCRIPT SETTINGS # 29 | ################################################################## 30 | 31 | SCRIPTPATH="`pwd`" 32 | RESOURCESPATH=$SCRIPTPATH"/resources/" 33 | EXAMPLESPATH=$SCRIPTPATH"/examples/" 34 | CPPCHECKOPTIONS="--enable=all --error-exitcode=1 --std=c99 --std=posix --std=c++11 -v" 35 | 36 | BUILDSUCCESCOUNTER=0 37 | BUILDFAILURECOUNTER=0 38 | 39 | CODECHECKFAILURECOUNTER=0 40 | CODECHECKSUCCESCOUNTER=0 41 | 42 | INDENTSUCCESCOUNTER=0 43 | INDENTFAILURECOUNTER=0 44 | 45 | MAXDEPTH=1 46 | 47 | ################################################################## 48 | # SELECT FILES TO BUILD # 49 | ################################################################## 50 | 51 | cd examples 52 | 53 | # create the FILES[] array, filled with all the folder names in the examples folder 54 | FILES=( $(find . -maxdepth 2 -type d -printf '%P\n') ) 55 | 56 | # select the range of file you want to build (from FIRSTFILE up to LASTFILE) 57 | FIRSTFILE=0 58 | LASTFILE=${#FILES[@]}-1 #equals last element of the FILES[] array 59 | 60 | ################################################################## 61 | # FUNCTIONS # 62 | ################################################################## 63 | 64 | function buildFile 65 | { 66 | scons > /dev/null 67 | if [ $? -eq 0 ] 68 | then 69 | echo "Build OK in folder: '`pwd | awk -F/ '{print $(NF-1),$NF}'`' " 70 | echo "`date`: Build OK in folder: '`pwd | awk -F/ '{print $(NF-1),$NF}'`' " >> $RESOURCESPATH/succes.log 71 | let BUILDSUCCESCOUNTER++ 72 | 73 | else 74 | echo "Build errors in folder: '`pwd | awk -F/ '{print $(NF-1),$NF}'`' " 75 | echo "`date`: Build errors in folder: '`pwd | awk -F/ '{print $(NF-1),$NF}'`' " >> $RESOURCESPATH/errors.log 76 | let BUILDFAILURECOUNTER++ 77 | fi 78 | } 79 | 80 | function CreateLogfiles 81 | { 82 | if [ -f $RESOURCESPATH/succes.log ]; 83 | then 84 | echo -ne "" 85 | else 86 | echo "File succes.log does not exist, creating it now" 87 | touch $RESOURCESPATH/succes.log 88 | fi 89 | 90 | if [ -f $RESOURCESPATH/errors.log ]; 91 | then 92 | echo -ne "" 93 | else 94 | echo "File errors.log does not exist, creating it now" 95 | touch $RESOURCESPATH/errors.log 96 | fi 97 | } 98 | 99 | function PrintStats 100 | { 101 | echo "" 102 | echo "------------------------------" 103 | echo "| Succesfull builds : $BUILDSUCCESCOUNTER " 104 | echo "| Failed builds : $BUILDFAILURECOUNTER " 105 | echo "|-----------------------------" 106 | echo "| Succesfull code checks : $CODECHECKSUCCESCOUNTER " 107 | echo "| Failed code checks : $CODECHECKFAILURECOUNTER " 108 | echo "|-----------------------------" 109 | echo "| Succesfull indents : $INDENTSUCCESCOUNTER " 110 | echo "| Failed indents : $INDENTFAILURECOUNTER " 111 | echo "------------------------------" 112 | echo "" 113 | } 114 | 115 | function logStats 116 | { 117 | echo "--------------------------------" > $RESOURCESPATH/lastbuild.log 118 | echo "| `date` |" >> $RESOURCESPATH/lastbuild.log 119 | echo "--------------------------------" >> $RESOURCESPATH/lastbuild.log 120 | echo "| Succesfull builds : $BUILDSUCCESCOUNTER |" >> $RESOURCESPATH/lastbuild.log 121 | echo "| Failed builds : $BUILDFAILURECOUNTER |" >> $RESOURCESPATH/lastbuild.log 122 | echo "|------------------------------|" >> $RESOURCESPATH/lastbuild.log 123 | echo "| Succesfull code checks : $CODECHECKSUCCESCOUNTER |" >> $RESOURCESPATH/lastbuild.log 124 | echo "| Failed code checks : $CODECHECKFAILURECOUNTER |" >> $RESOURCESPATH/lastbuild.log 125 | echo "--------------------------------" >> $RESOURCESPATH/lastbuild.log 126 | 127 | END=$(date +%s) 128 | DIFF=$(( $END - $START )) 129 | echo "Build took $DIFF seconds." >> $RESOURCESPATH/lastbuild.log 130 | echo "Build took $DIFF seconds." 131 | } 132 | 133 | function buildFiles 134 | { 135 | for ((i=FIRSTFILE;i<=LASTFILE;i++)); do 136 | echo ${FILES[i]} | grep build > /dev/null # don't try a scons build in the build folder 137 | if [ $? -eq 1 ] 138 | then 139 | cd ${FILES[i]} 140 | if [ -f *.ino ]; # to ignore (toplevel) folders without .ino files 141 | then 142 | buildFile 143 | fi 144 | cd $EXAMPLESPATH 145 | fi 146 | done 147 | } 148 | 149 | function staticCodeCheck 150 | { 151 | if [ $BUILDFAILURECOUNTER -eq 0 ] 152 | then 153 | staticCodeCheckRun 154 | else 155 | echo "Build errors -> skipping static code analysis" 156 | fi 157 | } 158 | 159 | function staticCodeCheckRun 160 | { 161 | FILES=( $(find . -maxdepth 3 -type d -printf '%P\n') ) 162 | for ((i=FIRSTFILE;i<=LASTFILE;i++)); do 163 | cd ${FILES[i]} 164 | if [ -f *.ino ]; # to ignore (toplevel) folders without .ino files 165 | then 166 | staticCodeCheckFile 167 | fi 168 | cd $EXAMPLESPATH 169 | done 170 | 171 | cd $SCRIPTPATH 172 | cppcheck $CPPCHECKOPTIONS *.h > /dev/null 173 | if [ $? -eq 0 ] 174 | then 175 | echo "Cppcheck OK in header file(s)" 176 | echo "`date`: Cppcheck OK in header file(s)" >> $RESOURCESPATH/succes.log 177 | let CODECHECKSUCCESCOUNTER++ 178 | 179 | else 180 | echo "Cppcheck errors in header file(s)" 181 | echo "`date`: Cppcheck errors in header file(s)" >> $RESOURCESPATH/errors.log 182 | let CODECHECKFAILURECOUNTER++ 183 | fi 184 | 185 | cppcheck $CPPCHECKOPTIONS *.cpp > /dev/null 186 | if [ $? -eq 0 ] 187 | then 188 | echo "Cppcheck OK in cpp file(s)" 189 | echo "`date`: Cppcheck OK in cpp file(s)" >> $RESOURCESPATH/succes.log 190 | let CODECHECKSUCCESCOUNTER++ 191 | 192 | else 193 | echo "Cppcheck errors in cpp file(s)" 194 | echo "`date`: Cppcheck errors in cpp file(s)" >> $RESOURCESPATH/errors.log 195 | let CODECHECKFAILURECOUNTER++ 196 | fi 197 | } 198 | 199 | function staticCodeCheckFile 200 | { 201 | if [ -f *.cpp ]; # to ignore (toplevel) folders without .cpp files 202 | then 203 | cppcheck $CPPCHECKOPTIONS *.cpp > /dev/null 204 | if [ $? -eq 0 ] 205 | then 206 | echo "Cppcheck OK in folder: '`pwd | awk -F/ '{print $NF}'`' " 207 | echo "`date`: Cppcheck OK in folder: '`pwd | awk -F/ '{print $NF}'`' " >> $RESOURCESPATH/succes.log 208 | let CODECHECKSUCCESCOUNTER++ 209 | 210 | else 211 | echo "Cppcheck errors in folder: '`pwd | awk -F/ '{print $NF}'`' " 212 | echo "`date`: Cppcheck errors in folder: '`pwd | awk -F/ '{print $NF}'`' " >> $RESOURCESPATH/errors.log 213 | let CODECHECKFAILURECOUNTER++ 214 | fi 215 | fi 216 | } 217 | 218 | function indentFiles 219 | { 220 | if [ $BUILDFAILURECOUNTER -eq 0 ] 221 | then 222 | indentFilesRun 223 | else 224 | echo "Build errors -> skipping code indenter" 225 | fi 226 | } 227 | 228 | function indentFilesRun 229 | { 230 | filesuffix="h" 231 | indentFilesType 232 | filesuffix="cpp" 233 | indentFilesType 234 | filesuffix="ino" 235 | MAXDEPTH=5 236 | indentFilesType 237 | } 238 | 239 | function indentFilesType 240 | { 241 | file_list=`find -maxdepth $MAXDEPTH ${1} -name "*.${filesuffix}" -type f` 242 | for file2indent in $file_list 243 | do 244 | echo "Indenting file $file2indent" 245 | bcpp -fi "$file2indent" -fnc $RESOURCESPATH/"bcpp_indenter.cfg" -fo indentoutput.tmp 246 | if [ $? -eq 0 ] 247 | then 248 | let INDENTSUCCESCOUNTER++ 249 | else 250 | let INDENTFAILURECOUNTER++ 251 | fi 252 | mv indentoutput.tmp "$file2indent" 253 | done 254 | } 255 | 256 | function cleanPreviousBuilds 257 | { 258 | ls | grep .elf > /dev/null 259 | if [ $? -eq 0 ] 260 | then 261 | rm *.elf 262 | fi 263 | 264 | ls | grep .hex > /dev/null 265 | if [ $? -eq 0 ] 266 | then 267 | rm *.hex 268 | fi 269 | 270 | ls | grep build > /dev/null 271 | if [ $? -eq 0 ] 272 | then 273 | rm -rf build 274 | fi 275 | 276 | ls -lah | grep .sconsign.dblite > /dev/null 277 | if [ $? -eq 0 ] 278 | then 279 | rm .sconsign.dblite 280 | fi 281 | 282 | ls -lah | grep "~" > /dev/null 283 | if [ $? -eq 0 ] 284 | then 285 | rm *~ 286 | fi 287 | } 288 | 289 | function cleanFiles 290 | { 291 | for ((i=FIRSTFILE;i<=LASTFILE;i++)); do 292 | echo ${FILES[i]} | grep build > /dev/null # don't try a clean in the build folder 293 | if [ $? -eq 1 ] 294 | then 295 | cd ${FILES[i]} 296 | echo "Cleaning: ${FILES[i]}" 297 | cleanPreviousBuilds 298 | fi 299 | cd $EXAMPLESPATH 300 | done 301 | } 302 | 303 | ################################################################## 304 | # MAIN CODE STARTS HERE # 305 | ################################################################## 306 | 307 | if [ "$1" = "clean" ] 308 | then 309 | cleanFiles 310 | else 311 | CreateLogfiles 312 | buildFiles 313 | staticCodeCheck 314 | indentFiles 315 | PrintStats 316 | logStats 317 | fi -------------------------------------------------------------------------------- /SerialPacket/defines.h: -------------------------------------------------------------------------------- 1 | // Select either ASCII or the normal binary serial packet type 2 | 3 | #define SERIAL_ASCII 4 | //#define SERIAL_BINARY 5 | 6 | //#define DEBUG_SERIAL 7 | 8 | 9 | #define DEFAULT_BAUDRATE 115200 10 | 11 | #define COMMAND 0x01 12 | #define COMMAND_REPLY 0x02 13 | 14 | #define DATA_REQUEST 0x11 15 | #define DATA_BYTE 0x12 16 | #define DATA_INT 0x13 17 | 18 | #define DATA_ARRAY_REQUEST 0x21 19 | #define DATA_ARRAY 0x22 20 | 21 | /// Sensor Types: 22 | 23 | #define TEMPERATURE 0x10 24 | #define HUMIDITY 0x11 25 | 26 | #define DISTANCE 0x30 27 | #define MOTORSTATUS 0x50 28 | 29 | /// Command IDs 30 | 31 | #define STOP_MOTOR_A 0x10 32 | #define START_MOTOR_A 0x11 33 | #define SET_SPEED_MOTOR_A 0x12 34 | #define BRAKE_MOTOR_A 0x13 35 | 36 | #define STOP_MOTOR_B 0x15 37 | #define START_MOTOR_B 0x16 38 | #define SET_SPEED_MOTOR_B 0x17 39 | #define BRAKE_MOTOR_B 0x18 40 | -------------------------------------------------------------------------------- /SerialPacket/defines.h.orig: -------------------------------------------------------------------------------- 1 | // Select either ASCII or the normal binary serial packet type 2 | 3 | #define SERIAL_ASCII 4 | //#define SERIAL_BINARY 5 | 6 | #define COMMAND 0x01 7 | #define COMMAND_REPLY 0x02 8 | 9 | #define DATA_REQUEST 0x11 10 | #define DATA_BYTE 0x12 11 | #define DATA_INT 0x13 12 | 13 | #define DATA_ARRAY_REQUEST 0x21 14 | #define DATA_ARRAY 0x22 15 | 16 | /// Sensor Types: 17 | 18 | #define TEMPERATURE 0x10 19 | #define HUMIDITY 0x11 20 | 21 | #define DISTANCE 0x30 22 | 23 | /// Command IDs 24 | 25 | #define STOP_MOTOR_A 0x10 26 | #define START_MOTOR_A 0x11 27 | #define SET_SPEED_MOTOR_A 0x12 28 | #define BRAKE_MOTOR_A 0x13 29 | 30 | #define STOP_MOTOR_B 0x15 31 | #define START_MOTOR_B 0x16 32 | #define SET_SPEED_MOTOR_B 0x17 33 | #define BRAKE_MOTOR_B 0x18 34 | -------------------------------------------------------------------------------- /SerialPacket/examples/ArduinoActions/ArduinoActions.ino: -------------------------------------------------------------------------------- 1 | // ReceivePackets.ino - Demo application to receive data and command messages 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // 4 | // Warning: this code is untested (it compiles, but not tested on hardware) 5 | 6 | #include "SerialPacket.h" 7 | #include "defines.h" 8 | 9 | SerialPacket Packet; 10 | 11 | void setup() 12 | { 13 | Packet.begin(115200,0); //begin(speed,nodeID); 14 | } 15 | 16 | void loop() 17 | { 18 | delay(500); 19 | } 20 | 21 | /* 22 | SerialEvent occurs whenever a new data comes in the 23 | hardware serial RX. This routine is run between each 24 | time loop() runs, so using delay inside loop can delay 25 | response. Multiple bytes of data may be available. 26 | */ 27 | 28 | void serialEvent() 29 | { 30 | Packet.readSerialData(); 31 | serialActions(); 32 | } 33 | 34 | /// Take Actions based on incoming commands: 35 | void serialActions(){ 36 | Serial.println("Starting serialActions"); 37 | 38 | if (Packet.getCommandID() == SET_SPEED_MOTOR_A) { 39 | int motorSpeed = Packet.getPayload(); 40 | Serial.println("Set the motor speed to value 'motorSpeed'"); 41 | Packet.sendData(COMMAND_REPLY,uint8_t(SET_SPEED_MOTOR_A)); 42 | } 43 | } -------------------------------------------------------------------------------- /SerialPacket/examples/ArduinoActions/SConstruct: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # scons script for the Arduino sketch 4 | # http://github.com/suapapa/arscons 5 | # 6 | # Copyright (C) 2010-2012 by Homin Lee 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 3 of the License, or 11 | # (at your option) any later version. 12 | 13 | # You'll need the serial module: http://pypi.python.org/pypi/pyserial 14 | 15 | # Basic Usage: 16 | # 1. make a folder which have same name of the sketch (ex. Blink/ for Blink.pde) 17 | # 2. put the sketch and SConstruct(this file) under the folder. 18 | # 3. to make the HEX. do following in the folder. 19 | # $ scons 20 | # 4. to upload the binary, do following in the folder. 21 | # $ scons upload 22 | 23 | # Thanks to: 24 | # * Ovidiu Predescu and Lee Pike 25 | # for Mac port and bugfix. 26 | # 27 | # This script tries to determine the port to which you have an Arduino 28 | # attached. If multiple USB serial devices are attached to your 29 | # computer, you'll need to explicitly specify the port to use, like 30 | # this: 31 | # 32 | # $ scons ARDUINO_PORT=/dev/ttyUSB0 33 | # 34 | # To add your own directory containing user libraries, pass EXTRA_LIB 35 | # to scons, like this: 36 | # 37 | # $ scons EXTRA_LIB= 38 | # 39 | 40 | from glob import glob 41 | from itertools import ifilter, imap 42 | from subprocess import check_call, CalledProcessError 43 | import sys 44 | import re 45 | import os 46 | from os import path 47 | from pprint import pprint 48 | 49 | env = Environment() 50 | platform = env['PLATFORM'] 51 | 52 | VARTAB = {} 53 | 54 | def resolve_var(varname, default_value): 55 | global VARTAB 56 | # precedence: scons argument -> environment variable -> default value 57 | ret = ARGUMENTS.get(varname, None) 58 | VARTAB[varname] = ('arg', ret) 59 | if ret == None: 60 | ret = os.environ.get(varname, None) 61 | VARTAB[varname] = ('env', ret) 62 | if ret == None: 63 | ret = default_value 64 | VARTAB[varname] = ('dfl', ret) 65 | return ret 66 | 67 | def getUsbTty(rx): 68 | usb_ttys = glob(rx) 69 | return usb_ttys[0] if len(usb_ttys) == 1 else None 70 | 71 | AVR_BIN_PREFIX = None 72 | AVRDUDE_CONF = None 73 | 74 | if platform == 'darwin': 75 | # For MacOS X, pick up the AVR tools from within Arduino.app 76 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', 77 | '/Applications/Arduino.app/Contents/Resources/Java') 78 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', getUsbTty('/dev/tty.usbserial*')) 79 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', '') 80 | AVR_HOME = resolve_var('AVR_HOME', 81 | path.join(ARDUINO_HOME, 'hardware/tools/avr/bin')) 82 | elif platform == 'win32': 83 | # For Windows, use environment variables. 84 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', None) 85 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', '') 86 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', '') 87 | AVR_HOME = resolve_var('AVR_HOME', 88 | path.join(ARDUINO_HOME, 'hardware/tools/avr/bin')) 89 | else: 90 | # For Ubuntu Linux (9.10 or higher) 91 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', '/usr/share/arduino/') 92 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', getUsbTty('/dev/ttyUSB*')) 93 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', 94 | path.expanduser('~/share/arduino/sketchbook/')) 95 | AVR_HOME = resolve_var('AVR_HOME', '') 96 | 97 | 98 | ARDUINO_BOARD = resolve_var('ARDUINO_BOARD', 'atmega328') 99 | ARDUINO_VER = resolve_var('ARDUINO_VER', 0) # Default to 0 if nothing is specified 100 | RST_TRIGGER = resolve_var('RST_TRIGGER', None) # use built-in pulseDTR() by default 101 | EXTRA_LIB = resolve_var('EXTRA_LIB', None) # handy for adding another arduino-lib dir 102 | 103 | pprint(VARTAB, indent = 4) 104 | 105 | if not ARDUINO_HOME: 106 | print 'ARDUINO_HOME must be defined.' 107 | raise KeyError('ARDUINO_HOME') 108 | 109 | ARDUINO_CONF = path.join(ARDUINO_HOME, 'hardware/arduino/boards.txt') 110 | # check given board name, ARDUINO_BOARD is valid one 111 | arduino_boards = path.join(ARDUINO_HOME,'hardware/*/boards.txt') 112 | custom_boards = path.join(SKETCHBOOK_HOME,'hardware/*/boards.txt') 113 | board_files = glob(arduino_boards) + glob(custom_boards) 114 | ptnBoard = re.compile(r'^([^#]*)\.name=(.*)') 115 | boards = {} 116 | for bf in board_files: 117 | for line in open(bf): 118 | result = ptnBoard.match(line) 119 | if result: 120 | boards[result.group(1)] = (result.group(2), bf) 121 | 122 | if ARDUINO_BOARD not in boards: 123 | print "ERROR! the given board name, %s is not in the supported board list:" % ARDUINO_BOARD 124 | print "all available board names are:" 125 | for name, description in boards.iteritems(): 126 | print "\t%s for %s" % (name.ljust(14), description[0]) 127 | #print "however, you may edit %s to add a new board." % ARDUINO_CONF 128 | sys.exit(-1) 129 | 130 | ARDUINO_CONF = boards[ARDUINO_BOARD][1] 131 | 132 | def getBoardConf(conf, default = None): 133 | for line in open(ARDUINO_CONF): 134 | line = line.strip() 135 | if '=' in line: 136 | key, value = line.split('=') 137 | if key == '.'.join([ARDUINO_BOARD, conf]): 138 | return value 139 | ret = default 140 | if ret == None: 141 | print "ERROR! can't find %s in %s" % (conf, ARDUINO_CONF) 142 | assert(False) 143 | return ret 144 | 145 | ARDUINO_CORE = path.join(ARDUINO_HOME, path.dirname(ARDUINO_CONF), 146 | 'cores/', getBoardConf('build.core', 'arduino')) 147 | ARDUINO_SKEL = path.join(ARDUINO_CORE, 'main.cpp') 148 | 149 | if ARDUINO_VER == 0: 150 | arduinoHeader = path.join(ARDUINO_CORE, 'Arduino.h') 151 | print "No Arduino version specified. Discovered version", 152 | if path.exists(arduinoHeader): 153 | print "100 or above" 154 | ARDUINO_VER = 100 155 | else: 156 | print "0023 or below" 157 | ARDUINO_VER = 23 158 | else: 159 | print "Arduino version " + ARDUINO_VER + " specified" 160 | 161 | # Some OSs need bundle with IDE tool-chain 162 | if platform == 'darwin' or platform == 'win32': 163 | AVRDUDE_CONF = path.join(ARDUINO_HOME, 'hardware/tools/avr/etc/avrdude.conf') 164 | 165 | AVR_BIN_PREFIX = path.join(AVR_HOME, 'avr-') 166 | 167 | ARDUINO_LIBS = [path.join(ARDUINO_HOME, 'libraries')] 168 | if EXTRA_LIB: 169 | ARDUINO_LIBS.append(EXTRA_LIB) 170 | if SKETCHBOOK_HOME: 171 | ARDUINO_LIBS.append(path.join(SKETCHBOOK_HOME, 'libraries')) 172 | 173 | 174 | # Override MCU and F_CPU 175 | MCU = ARGUMENTS.get('MCU', getBoardConf('build.mcu')) 176 | F_CPU = ARGUMENTS.get('F_CPU', getBoardConf('build.f_cpu')) 177 | 178 | # There should be a file with the same name as the folder and 179 | # with the extension .pde or .ino 180 | TARGET = path.basename(path.realpath(os.curdir)) 181 | assert(path.exists(TARGET + '.ino') or path.exists(TARGET + '.pde')) 182 | sketchExt = '.ino' if path.exists(TARGET + '.ino') else '.pde' 183 | 184 | cFlags = ['-ffunction-sections', '-fdata-sections', '-fno-exceptions', 185 | '-funsigned-char', '-funsigned-bitfields', '-fpack-struct', 186 | '-fshort-enums', '-Os', '-Wall', '-mmcu=%s' % MCU] 187 | envArduino = Environment(CC = AVR_BIN_PREFIX + 'gcc', 188 | CXX = AVR_BIN_PREFIX + 'g++', 189 | AS = AVR_BIN_PREFIX + 'gcc', 190 | CPPPATH = ['build/core'], 191 | CPPDEFINES = {'F_CPU': F_CPU, 'ARDUINO': ARDUINO_VER}, 192 | CFLAGS = cFlags + ['-std=gnu99'], 193 | CCFLAGS = cFlags, 194 | ASFLAGS = ['-assembler-with-cpp','-mmcu=%s' % MCU], 195 | TOOLS = ['gcc','g++', 'as']) 196 | 197 | hwVariant = path.join(ARDUINO_HOME, 'hardware/arduino/variants', 198 | getBoardConf("build.variant", "")) 199 | if hwVariant: 200 | envArduino.Append(CPPPATH = hwVariant) 201 | 202 | def run(cmd): 203 | """Run a command and decipher the return code. Exit by default.""" 204 | print ' '.join(cmd) 205 | try: 206 | check_call(cmd) 207 | except CalledProcessError as cpe: 208 | print "Error: return code: " + str(cpe.returncode) 209 | sys.exit(cpe.returncode) 210 | 211 | # WindowXP not supported path.samefile 212 | def sameFile(p1, p2): 213 | if platform == 'win32': 214 | ap1 = path.abspath(p1) 215 | ap2 = path.abspath(p2) 216 | return ap1 == ap2 217 | return path.samefile(p1, p2) 218 | 219 | def fnProcessing(target, source, env): 220 | wp = open(str(target[0]), 'wb') 221 | wp.write(open(ARDUINO_SKEL).read()) 222 | 223 | types='''void 224 | int char word long 225 | float double byte long 226 | boolean 227 | uint8_t uint16_t uint32_t 228 | int8_t int16_t int32_t''' 229 | types=' | '.join(types.split()) 230 | re_signature = re.compile(r"""^\s* ( 231 | (?: (%s) \s+ )? 232 | \w+ \s* 233 | \( \s* ((%s) \s+ \*? \w+ (?:\s*,\s*)? )* \) 234 | ) \s* {? \s* $""" % (types, types), re.MULTILINE | re.VERBOSE) 235 | 236 | prototypes = {} 237 | 238 | for file in glob(path.realpath(os.curdir) + "/*" + sketchExt): 239 | for line in open(file): 240 | result = re_signature.search(line) 241 | if result: 242 | prototypes[result.group(1)] = result.group(2) 243 | 244 | for name in prototypes.iterkeys(): 245 | print "%s;" % name 246 | wp.write("%s;\n" % name) 247 | 248 | for file in glob(path.realpath(os.curdir) + "/*" + sketchExt): 249 | print file, TARGET 250 | if not sameFile(file, TARGET + sketchExt): 251 | wp.write('#line 1 "%s"\r\n' % file) 252 | wp.write(open(file).read()) 253 | 254 | # Add this preprocessor directive to localize the errors. 255 | sourcePath = str(source[0]).replace('\\', '\\\\') 256 | wp.write('#line 1 "%s"\r\n' % sourcePath) 257 | wp.write(open(str(source[0])).read()) 258 | 259 | def fnCompressCore(target, source, env): 260 | core_prefix = 'build/core/'.replace('/', os.path.sep) 261 | core_files = (x for x in imap(str, source) 262 | if x.startswith(core_prefix)) 263 | for file in core_files: 264 | run([AVR_BIN_PREFIX + 'ar', 'rcs', str(target[0]), file]) 265 | 266 | bldProcessing = Builder(action = fnProcessing) #, suffix = '.cpp', src_suffix = sketchExt) 267 | bldCompressCore = Builder(action = fnCompressCore) 268 | bldELF = Builder(action = AVR_BIN_PREFIX + 'gcc -mmcu=%s ' % MCU + 269 | '-Os -Wl,--gc-sections -lm -o $TARGET $SOURCES -lc') 270 | bldHEX = Builder(action = AVR_BIN_PREFIX + 'objcopy -O ihex -R .eeprom $SOURCES $TARGET') 271 | 272 | envArduino.Append(BUILDERS = {'Processing' : bldProcessing}) 273 | envArduino.Append(BUILDERS = {'CompressCore': bldCompressCore}) 274 | envArduino.Append(BUILDERS = {'Elf' : bldELF}) 275 | envArduino.Append(BUILDERS = {'Hex' : bldHEX}) 276 | 277 | ptnSource = re.compile(r'\.(?:c(?:pp)?|S)$') 278 | def gatherSources(srcpath): 279 | return [path.join(srcpath, f) for f 280 | in os.listdir(srcpath) if ptnSource.search(f)] 281 | 282 | # add arduino core sources 283 | VariantDir('build/core', ARDUINO_CORE) 284 | core_sources = gatherSources(ARDUINO_CORE) 285 | core_sources = [x.replace(ARDUINO_CORE, 'build/core/') for x 286 | in core_sources if path.basename(x) != 'main.cpp'] 287 | 288 | # add libraries 289 | libCandidates = [] 290 | ptnLib = re.compile(r'^[ ]*#[ ]*include [<"](.*)\.h[>"]') 291 | for line in open(TARGET + sketchExt): 292 | result = ptnLib.search(line) 293 | if not result: 294 | continue 295 | # Look for the library directory that contains the header. 296 | filename = result.group(1) + '.h' 297 | for libdir in ARDUINO_LIBS: 298 | for root, dirs, files in os.walk(libdir, followlinks=True): 299 | if filename in files: 300 | libCandidates.append(path.basename(root)) 301 | 302 | # Hack. In version 20 of the Arduino IDE, the Ethernet library depends 303 | # implicitly on the SPI library. 304 | if ARDUINO_VER >= 20 and 'Ethernet' in libCandidates: 305 | libCandidates.append('SPI') 306 | 307 | all_libs_sources = [] 308 | for index, orig_lib_dir in enumerate(ARDUINO_LIBS): 309 | lib_dir = 'build/lib_%02d' % index 310 | VariantDir(lib_dir, orig_lib_dir) 311 | for libPath in ifilter(path.isdir, glob(path.join(orig_lib_dir, '*'))): 312 | libName = path.basename(libPath) 313 | if not libName in libCandidates: 314 | continue 315 | envArduino.Append(CPPPATH = libPath.replace(orig_lib_dir, lib_dir)) 316 | lib_sources = gatherSources(libPath) 317 | utilDir = path.join(libPath, 'utility') 318 | if path.exists(utilDir) and path.isdir(utilDir): 319 | lib_sources += gatherSources(utilDir) 320 | envArduino.Append(CPPPATH = utilDir.replace(orig_lib_dir, lib_dir)) 321 | lib_sources = (x.replace(orig_lib_dir, lib_dir) for x in lib_sources) 322 | all_libs_sources.extend(lib_sources) 323 | 324 | # Add raw sources which live in sketch dir. 325 | build_top = path.realpath('.') 326 | VariantDir('build/local/', build_top) 327 | local_sources = gatherSources(build_top) 328 | local_sources = [x.replace(build_top, 'build/local/') for x in local_sources] 329 | if local_sources: 330 | envArduino.Append(CPPPATH = 'build/local') 331 | 332 | # Convert sketch(.pde) to cpp 333 | envArduino.Processing('build/' + TARGET + '.cpp', 'build/' + TARGET + sketchExt) 334 | VariantDir('build', '.') 335 | 336 | sources = ['build/' + TARGET + '.cpp'] 337 | #sources += core_sources 338 | sources += local_sources 339 | sources += all_libs_sources 340 | 341 | # Finally Build!! 342 | core_objs = envArduino.Object(core_sources) 343 | objs = envArduino.Object(sources) #, LIBS=libs, LIBPATH='.') 344 | objs = objs + envArduino.CompressCore('build/core.a', core_objs) 345 | envArduino.Elf(TARGET + '.elf', objs) 346 | envArduino.Hex(TARGET + '.hex', TARGET + '.elf') 347 | 348 | # Print Size 349 | # TODO: check binary size 350 | MAX_SIZE = getBoardConf('upload.maximum_size') 351 | print "maximum size for hex file: %s bytes" % MAX_SIZE 352 | envArduino.Command(None, TARGET + '.hex', AVR_BIN_PREFIX + 'size --target=ihex $SOURCE') 353 | 354 | # Reset 355 | def pulseDTR(target, source, env): 356 | import serial 357 | import time 358 | ser = serial.Serial(ARDUINO_PORT) 359 | ser.setDTR(1) 360 | time.sleep(0.5) 361 | ser.setDTR(0) 362 | ser.close() 363 | 364 | if RST_TRIGGER: 365 | reset_cmd = '%s %s' % (RST_TRIGGER, ARDUINO_PORT) 366 | else: 367 | reset_cmd = pulseDTR 368 | 369 | # Upload 370 | UPLOAD_PROTOCOL = getBoardConf('upload.protocol') 371 | UPLOAD_SPEED = getBoardConf('upload.speed') 372 | 373 | if UPLOAD_PROTOCOL == 'stk500': 374 | UPLOAD_PROTOCOL = 'stk500v1' 375 | 376 | 377 | avrdudeOpts = ['-V', '-F', '-c %s' % UPLOAD_PROTOCOL, '-b %s' % UPLOAD_SPEED, 378 | '-p %s' % MCU, '-P %s' % ARDUINO_PORT, '-U flash:w:$SOURCES'] 379 | if AVRDUDE_CONF: 380 | avrdudeOpts.append('-C %s' % AVRDUDE_CONF) 381 | 382 | fuse_cmd = '%s %s' % (path.join(path.dirname(AVR_BIN_PREFIX), 'avrdude'), 383 | ' '.join(avrdudeOpts)) 384 | 385 | upload = envArduino.Alias('upload', TARGET + '.hex', [reset_cmd, fuse_cmd]) 386 | AlwaysBuild(upload) 387 | 388 | # Clean build directory 389 | envArduino.Clean('all', 'build/') 390 | 391 | # vim: et sw=4 fenc=utf-8: 392 | -------------------------------------------------------------------------------- /SerialPacket/examples/ReceivePackets/ReceivePackets.ino: -------------------------------------------------------------------------------- 1 | // ReceivePackets.ino - Demo application to receive data and command messages 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // 4 | // Program flow: 5 | // - 6 | // Options: 7 | // - 8 | 9 | #include "SerialPacket.h" 10 | #include "defines.h" 11 | 12 | SerialPacket Packet; 13 | 14 | void setup() 15 | { 16 | Packet.begin(115200,0); //begin(speed,nodeID); 17 | } 18 | 19 | void loop() 20 | { 21 | delay(500); 22 | // Packet.sendData(1,uint8_t(6)); 23 | } 24 | 25 | /* 26 | SerialEvent occurs whenever a new data comes in the 27 | hardware serial RX. This routine is run between each 28 | time loop() runs, so using delay inside loop can delay 29 | response. Multiple bytes of data may be available. 30 | */ 31 | 32 | void serialEvent() 33 | { 34 | Packet.readSerialData(); 35 | } 36 | -------------------------------------------------------------------------------- /SerialPacket/examples/SendAnalogInput/SendAnalogInput.ino: -------------------------------------------------------------------------------- 1 | #include "SerialPacket.h" 2 | #include "defines.h" 3 | 4 | SerialPacket Packet; 5 | 6 | #define SENSORID 2 7 | int a=32760 ; 8 | uint8_t b=0; 9 | 10 | void setup() 11 | { 12 | Packet.begin(115200,1); //begin(speed,nodeID); 13 | } 14 | 15 | void loop() 16 | { 17 | 18 | /*Serial.println(a); 19 | Serial.println(a,HEX); 20 | Packet.sendData(SENSORID, a); 21 | 22 | Serial.println(b); 23 | Serial.println(b,HEX); 24 | Packet.sendData(SENSORID, b)*/ 25 | ; 26 | 27 | Packet.sendDataArrayRequest(10,20); 28 | delay(1000); // wait for 100 milliseconds 29 | a++; 30 | b++; 31 | } 32 | -------------------------------------------------------------------------------- /SerialPacket/examples/SendPackets/SConstruct: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # scons script for the Arduino sketch 4 | # http://github.com/suapapa/arscons 5 | # 6 | # Copyright (C) 2010-2012 by Homin Lee 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 3 of the License, or 11 | # (at your option) any later version. 12 | 13 | # You'll need the serial module: http://pypi.python.org/pypi/pyserial 14 | 15 | # Basic Usage: 16 | # 1. make a folder which have same name of the sketch (ex. Blink/ for Blink.pde) 17 | # 2. put the sketch and SConstruct(this file) under the folder. 18 | # 3. to make the HEX. do following in the folder. 19 | # $ scons 20 | # 4. to upload the binary, do following in the folder. 21 | # $ scons upload 22 | 23 | # Thanks to: 24 | # * Ovidiu Predescu and Lee Pike 25 | # for Mac port and bugfix. 26 | # 27 | # This script tries to determine the port to which you have an Arduino 28 | # attached. If multiple USB serial devices are attached to your 29 | # computer, you'll need to explicitly specify the port to use, like 30 | # this: 31 | # 32 | # $ scons ARDUINO_PORT=/dev/ttyUSB0 33 | # 34 | # To add your own directory containing user libraries, pass EXTRA_LIB 35 | # to scons, like this: 36 | # 37 | # $ scons EXTRA_LIB= 38 | # 39 | 40 | from glob import glob 41 | from itertools import ifilter, imap 42 | from subprocess import check_call, CalledProcessError 43 | import sys 44 | import re 45 | import os 46 | from os import path 47 | from pprint import pprint 48 | 49 | env = Environment() 50 | platform = env['PLATFORM'] 51 | 52 | VARTAB = {} 53 | 54 | def resolve_var(varname, default_value): 55 | global VARTAB 56 | # precedence: scons argument -> environment variable -> default value 57 | ret = ARGUMENTS.get(varname, None) 58 | VARTAB[varname] = ('arg', ret) 59 | if ret == None: 60 | ret = os.environ.get(varname, None) 61 | VARTAB[varname] = ('env', ret) 62 | if ret == None: 63 | ret = default_value 64 | VARTAB[varname] = ('dfl', ret) 65 | return ret 66 | 67 | def getUsbTty(rx): 68 | usb_ttys = glob(rx) 69 | return usb_ttys[0] if len(usb_ttys) == 1 else None 70 | 71 | AVR_BIN_PREFIX = None 72 | AVRDUDE_CONF = None 73 | 74 | if platform == 'darwin': 75 | # For MacOS X, pick up the AVR tools from within Arduino.app 76 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', 77 | '/Applications/Arduino.app/Contents/Resources/Java') 78 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', getUsbTty('/dev/tty.usbserial*')) 79 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', '') 80 | AVR_HOME = resolve_var('AVR_HOME', 81 | path.join(ARDUINO_HOME, 'hardware/tools/avr/bin')) 82 | elif platform == 'win32': 83 | # For Windows, use environment variables. 84 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', None) 85 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', '') 86 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', '') 87 | AVR_HOME = resolve_var('AVR_HOME', 88 | path.join(ARDUINO_HOME, 'hardware/tools/avr/bin')) 89 | else: 90 | # For Ubuntu Linux (9.10 or higher) 91 | ARDUINO_HOME = resolve_var('ARDUINO_HOME', '/usr/share/arduino/') 92 | ARDUINO_PORT = resolve_var('ARDUINO_PORT', getUsbTty('/dev/ttyUSB*')) 93 | SKETCHBOOK_HOME = resolve_var('SKETCHBOOK_HOME', 94 | path.expanduser('~/share/arduino/sketchbook/')) 95 | AVR_HOME = resolve_var('AVR_HOME', '') 96 | 97 | 98 | ARDUINO_BOARD = resolve_var('ARDUINO_BOARD', 'atmega328') 99 | ARDUINO_VER = resolve_var('ARDUINO_VER', 0) # Default to 0 if nothing is specified 100 | RST_TRIGGER = resolve_var('RST_TRIGGER', None) # use built-in pulseDTR() by default 101 | EXTRA_LIB = resolve_var('EXTRA_LIB', None) # handy for adding another arduino-lib dir 102 | 103 | pprint(VARTAB, indent = 4) 104 | 105 | if not ARDUINO_HOME: 106 | print 'ARDUINO_HOME must be defined.' 107 | raise KeyError('ARDUINO_HOME') 108 | 109 | ARDUINO_CONF = path.join(ARDUINO_HOME, 'hardware/arduino/boards.txt') 110 | # check given board name, ARDUINO_BOARD is valid one 111 | arduino_boards = path.join(ARDUINO_HOME,'hardware/*/boards.txt') 112 | custom_boards = path.join(SKETCHBOOK_HOME,'hardware/*/boards.txt') 113 | board_files = glob(arduino_boards) + glob(custom_boards) 114 | ptnBoard = re.compile(r'^([^#]*)\.name=(.*)') 115 | boards = {} 116 | for bf in board_files: 117 | for line in open(bf): 118 | result = ptnBoard.match(line) 119 | if result: 120 | boards[result.group(1)] = (result.group(2), bf) 121 | 122 | if ARDUINO_BOARD not in boards: 123 | print "ERROR! the given board name, %s is not in the supported board list:" % ARDUINO_BOARD 124 | print "all available board names are:" 125 | for name, description in boards.iteritems(): 126 | print "\t%s for %s" % (name.ljust(14), description[0]) 127 | #print "however, you may edit %s to add a new board." % ARDUINO_CONF 128 | sys.exit(-1) 129 | 130 | ARDUINO_CONF = boards[ARDUINO_BOARD][1] 131 | 132 | def getBoardConf(conf, default = None): 133 | for line in open(ARDUINO_CONF): 134 | line = line.strip() 135 | if '=' in line: 136 | key, value = line.split('=') 137 | if key == '.'.join([ARDUINO_BOARD, conf]): 138 | return value 139 | ret = default 140 | if ret == None: 141 | print "ERROR! can't find %s in %s" % (conf, ARDUINO_CONF) 142 | assert(False) 143 | return ret 144 | 145 | ARDUINO_CORE = path.join(ARDUINO_HOME, path.dirname(ARDUINO_CONF), 146 | 'cores/', getBoardConf('build.core', 'arduino')) 147 | ARDUINO_SKEL = path.join(ARDUINO_CORE, 'main.cpp') 148 | 149 | if ARDUINO_VER == 0: 150 | arduinoHeader = path.join(ARDUINO_CORE, 'Arduino.h') 151 | print "No Arduino version specified. Discovered version", 152 | if path.exists(arduinoHeader): 153 | print "100 or above" 154 | ARDUINO_VER = 100 155 | else: 156 | print "0023 or below" 157 | ARDUINO_VER = 23 158 | else: 159 | print "Arduino version " + ARDUINO_VER + " specified" 160 | 161 | # Some OSs need bundle with IDE tool-chain 162 | if platform == 'darwin' or platform == 'win32': 163 | AVRDUDE_CONF = path.join(ARDUINO_HOME, 'hardware/tools/avr/etc/avrdude.conf') 164 | 165 | AVR_BIN_PREFIX = path.join(AVR_HOME, 'avr-') 166 | 167 | ARDUINO_LIBS = [path.join(ARDUINO_HOME, 'libraries')] 168 | if EXTRA_LIB: 169 | ARDUINO_LIBS.append(EXTRA_LIB) 170 | if SKETCHBOOK_HOME: 171 | ARDUINO_LIBS.append(path.join(SKETCHBOOK_HOME, 'libraries')) 172 | 173 | 174 | # Override MCU and F_CPU 175 | MCU = ARGUMENTS.get('MCU', getBoardConf('build.mcu')) 176 | F_CPU = ARGUMENTS.get('F_CPU', getBoardConf('build.f_cpu')) 177 | 178 | # There should be a file with the same name as the folder and 179 | # with the extension .pde or .ino 180 | TARGET = path.basename(path.realpath(os.curdir)) 181 | assert(path.exists(TARGET + '.ino') or path.exists(TARGET + '.pde')) 182 | sketchExt = '.ino' if path.exists(TARGET + '.ino') else '.pde' 183 | 184 | cFlags = ['-ffunction-sections', '-fdata-sections', '-fno-exceptions', 185 | '-funsigned-char', '-funsigned-bitfields', '-fpack-struct', 186 | '-fshort-enums', '-Os', '-Wall', '-mmcu=%s' % MCU] 187 | envArduino = Environment(CC = AVR_BIN_PREFIX + 'gcc', 188 | CXX = AVR_BIN_PREFIX + 'g++', 189 | AS = AVR_BIN_PREFIX + 'gcc', 190 | CPPPATH = ['build/core'], 191 | CPPDEFINES = {'F_CPU': F_CPU, 'ARDUINO': ARDUINO_VER}, 192 | CFLAGS = cFlags + ['-std=gnu99'], 193 | CCFLAGS = cFlags, 194 | ASFLAGS = ['-assembler-with-cpp','-mmcu=%s' % MCU], 195 | TOOLS = ['gcc','g++', 'as']) 196 | 197 | hwVariant = path.join(ARDUINO_HOME, 'hardware/arduino/variants', 198 | getBoardConf("build.variant", "")) 199 | if hwVariant: 200 | envArduino.Append(CPPPATH = hwVariant) 201 | 202 | def run(cmd): 203 | """Run a command and decipher the return code. Exit by default.""" 204 | print ' '.join(cmd) 205 | try: 206 | check_call(cmd) 207 | except CalledProcessError as cpe: 208 | print "Error: return code: " + str(cpe.returncode) 209 | sys.exit(cpe.returncode) 210 | 211 | # WindowXP not supported path.samefile 212 | def sameFile(p1, p2): 213 | if platform == 'win32': 214 | ap1 = path.abspath(p1) 215 | ap2 = path.abspath(p2) 216 | return ap1 == ap2 217 | return path.samefile(p1, p2) 218 | 219 | def fnProcessing(target, source, env): 220 | wp = open(str(target[0]), 'wb') 221 | wp.write(open(ARDUINO_SKEL).read()) 222 | 223 | types='''void 224 | int char word long 225 | float double byte long 226 | boolean 227 | uint8_t uint16_t uint32_t 228 | int8_t int16_t int32_t''' 229 | types=' | '.join(types.split()) 230 | re_signature = re.compile(r"""^\s* ( 231 | (?: (%s) \s+ )? 232 | \w+ \s* 233 | \( \s* ((%s) \s+ \*? \w+ (?:\s*,\s*)? )* \) 234 | ) \s* {? \s* $""" % (types, types), re.MULTILINE | re.VERBOSE) 235 | 236 | prototypes = {} 237 | 238 | for file in glob(path.realpath(os.curdir) + "/*" + sketchExt): 239 | for line in open(file): 240 | result = re_signature.search(line) 241 | if result: 242 | prototypes[result.group(1)] = result.group(2) 243 | 244 | for name in prototypes.iterkeys(): 245 | print "%s;" % name 246 | wp.write("%s;\n" % name) 247 | 248 | for file in glob(path.realpath(os.curdir) + "/*" + sketchExt): 249 | print file, TARGET 250 | if not sameFile(file, TARGET + sketchExt): 251 | wp.write('#line 1 "%s"\r\n' % file) 252 | wp.write(open(file).read()) 253 | 254 | # Add this preprocessor directive to localize the errors. 255 | sourcePath = str(source[0]).replace('\\', '\\\\') 256 | wp.write('#line 1 "%s"\r\n' % sourcePath) 257 | wp.write(open(str(source[0])).read()) 258 | 259 | def fnCompressCore(target, source, env): 260 | core_prefix = 'build/core/'.replace('/', os.path.sep) 261 | core_files = (x for x in imap(str, source) 262 | if x.startswith(core_prefix)) 263 | for file in core_files: 264 | run([AVR_BIN_PREFIX + 'ar', 'rcs', str(target[0]), file]) 265 | 266 | bldProcessing = Builder(action = fnProcessing) #, suffix = '.cpp', src_suffix = sketchExt) 267 | bldCompressCore = Builder(action = fnCompressCore) 268 | bldELF = Builder(action = AVR_BIN_PREFIX + 'gcc -mmcu=%s ' % MCU + 269 | '-Os -Wl,--gc-sections -lm -o $TARGET $SOURCES -lc') 270 | bldHEX = Builder(action = AVR_BIN_PREFIX + 'objcopy -O ihex -R .eeprom $SOURCES $TARGET') 271 | 272 | envArduino.Append(BUILDERS = {'Processing' : bldProcessing}) 273 | envArduino.Append(BUILDERS = {'CompressCore': bldCompressCore}) 274 | envArduino.Append(BUILDERS = {'Elf' : bldELF}) 275 | envArduino.Append(BUILDERS = {'Hex' : bldHEX}) 276 | 277 | ptnSource = re.compile(r'\.(?:c(?:pp)?|S)$') 278 | def gatherSources(srcpath): 279 | return [path.join(srcpath, f) for f 280 | in os.listdir(srcpath) if ptnSource.search(f)] 281 | 282 | # add arduino core sources 283 | VariantDir('build/core', ARDUINO_CORE) 284 | core_sources = gatherSources(ARDUINO_CORE) 285 | core_sources = [x.replace(ARDUINO_CORE, 'build/core/') for x 286 | in core_sources if path.basename(x) != 'main.cpp'] 287 | 288 | # add libraries 289 | libCandidates = [] 290 | ptnLib = re.compile(r'^[ ]*#[ ]*include [<"](.*)\.h[>"]') 291 | for line in open(TARGET + sketchExt): 292 | result = ptnLib.search(line) 293 | if not result: 294 | continue 295 | # Look for the library directory that contains the header. 296 | filename = result.group(1) + '.h' 297 | for libdir in ARDUINO_LIBS: 298 | for root, dirs, files in os.walk(libdir, followlinks=True): 299 | if filename in files: 300 | libCandidates.append(path.basename(root)) 301 | 302 | # Hack. In version 20 of the Arduino IDE, the Ethernet library depends 303 | # implicitly on the SPI library. 304 | if ARDUINO_VER >= 20 and 'Ethernet' in libCandidates: 305 | libCandidates.append('SPI') 306 | 307 | all_libs_sources = [] 308 | for index, orig_lib_dir in enumerate(ARDUINO_LIBS): 309 | lib_dir = 'build/lib_%02d' % index 310 | VariantDir(lib_dir, orig_lib_dir) 311 | for libPath in ifilter(path.isdir, glob(path.join(orig_lib_dir, '*'))): 312 | libName = path.basename(libPath) 313 | if not libName in libCandidates: 314 | continue 315 | envArduino.Append(CPPPATH = libPath.replace(orig_lib_dir, lib_dir)) 316 | lib_sources = gatherSources(libPath) 317 | utilDir = path.join(libPath, 'utility') 318 | if path.exists(utilDir) and path.isdir(utilDir): 319 | lib_sources += gatherSources(utilDir) 320 | envArduino.Append(CPPPATH = utilDir.replace(orig_lib_dir, lib_dir)) 321 | lib_sources = (x.replace(orig_lib_dir, lib_dir) for x in lib_sources) 322 | all_libs_sources.extend(lib_sources) 323 | 324 | # Add raw sources which live in sketch dir. 325 | build_top = path.realpath('.') 326 | VariantDir('build/local/', build_top) 327 | local_sources = gatherSources(build_top) 328 | local_sources = [x.replace(build_top, 'build/local/') for x in local_sources] 329 | if local_sources: 330 | envArduino.Append(CPPPATH = 'build/local') 331 | 332 | # Convert sketch(.pde) to cpp 333 | envArduino.Processing('build/' + TARGET + '.cpp', 'build/' + TARGET + sketchExt) 334 | VariantDir('build', '.') 335 | 336 | sources = ['build/' + TARGET + '.cpp'] 337 | #sources += core_sources 338 | sources += local_sources 339 | sources += all_libs_sources 340 | 341 | # Finally Build!! 342 | core_objs = envArduino.Object(core_sources) 343 | objs = envArduino.Object(sources) #, LIBS=libs, LIBPATH='.') 344 | objs = objs + envArduino.CompressCore('build/core.a', core_objs) 345 | envArduino.Elf(TARGET + '.elf', objs) 346 | envArduino.Hex(TARGET + '.hex', TARGET + '.elf') 347 | 348 | # Print Size 349 | # TODO: check binary size 350 | MAX_SIZE = getBoardConf('upload.maximum_size') 351 | print "maximum size for hex file: %s bytes" % MAX_SIZE 352 | envArduino.Command(None, TARGET + '.hex', AVR_BIN_PREFIX + 'size --target=ihex $SOURCE') 353 | 354 | # Reset 355 | def pulseDTR(target, source, env): 356 | import serial 357 | import time 358 | ser = serial.Serial(ARDUINO_PORT) 359 | ser.setDTR(1) 360 | time.sleep(0.5) 361 | ser.setDTR(0) 362 | ser.close() 363 | 364 | if RST_TRIGGER: 365 | reset_cmd = '%s %s' % (RST_TRIGGER, ARDUINO_PORT) 366 | else: 367 | reset_cmd = pulseDTR 368 | 369 | # Upload 370 | UPLOAD_PROTOCOL = getBoardConf('upload.protocol') 371 | UPLOAD_SPEED = getBoardConf('upload.speed') 372 | 373 | if UPLOAD_PROTOCOL == 'stk500': 374 | UPLOAD_PROTOCOL = 'stk500v1' 375 | 376 | 377 | avrdudeOpts = ['-V', '-F', '-c %s' % UPLOAD_PROTOCOL, '-b %s' % UPLOAD_SPEED, 378 | '-p %s' % MCU, '-P %s' % ARDUINO_PORT, '-U flash:w:$SOURCES'] 379 | if AVRDUDE_CONF: 380 | avrdudeOpts.append('-C %s' % AVRDUDE_CONF) 381 | 382 | fuse_cmd = '%s %s' % (path.join(path.dirname(AVR_BIN_PREFIX), 'avrdude'), 383 | ' '.join(avrdudeOpts)) 384 | 385 | upload = envArduino.Alias('upload', TARGET + '.hex', [reset_cmd, fuse_cmd]) 386 | AlwaysBuild(upload) 387 | 388 | # Clean build directory 389 | envArduino.Clean('all', 'build/') 390 | 391 | # vim: et sw=4 fenc=utf-8: 392 | -------------------------------------------------------------------------------- /SerialPacket/examples/SendPackets/SendPackets.ino: -------------------------------------------------------------------------------- 1 | // SendPackets.ino - Demo application to send packet data 2 | // Copyright 2012 Jeroen Doggen (jeroendoggen@gmail.com) 3 | // 4 | // Program flow: 5 | // - send a data packet every second: x10 6 | // - send a command every second: x5 7 | // - send a 5 field data packet every second: x5 8 | // - send a 10 field data packet every second: x5 9 | // - no packets for 5 seconds 10 | // - restart 11 | // Options: 12 | // - select binary or ASCII mode by changing the #define values in 'includes.h' 13 | 14 | #include "SerialPacket.h" 15 | #include "defines.h" 16 | 17 | SerialPacket Packet; 18 | 19 | uint8_t sensorID=0; 20 | uint8_t commandID=0; 21 | 22 | uint8_t payload=0; 23 | 24 | uint8_t counter=0; 25 | 26 | uint8_t dataArray1[5]={0,1,2,3,4}; 27 | uint8_t dataArray2[10]={0,1,2,3,4,5,6,7,8,9}; 28 | 29 | void setup() 30 | { 31 | Packet.begin(115200,0); //begin(speed,nodeID); 32 | } 33 | 34 | void loop() 35 | { 36 | // if(counter < 1) 37 | // { 38 | // Packet.sendCommand(10, payload); 39 | // payload++; 40 | // } 41 | 42 | // if(counter < 3) 43 | // { 44 | // Packet.sendCommand(payload); 45 | // payload++; 46 | // } 47 | 48 | // if(counter > 4 && counter < 10) 49 | // { 50 | // Packet.sendCommandReply(commandID, payload); 51 | // payload++; 52 | // } 53 | // 54 | // if(counter > 9 && counter < 15) 55 | // { 56 | // Packet.sendDataRequest(sensorID, payload); 57 | // payload++; 58 | // } 59 | // 60 | // if(counter > 14 && counter < 20) 61 | // { 62 | // Packet.sendData(sensorID, payload); 63 | // payload++; 64 | // } 65 | // 66 | if(counter > 20 && counter < 25) { 67 | Packet.sendData(sensorID, payload); 68 | payload++; 69 | } 70 | 71 | // if(counter > 19 && counter < 25){ 72 | // Packet.setPacketType(AGGREGATEDDATA); //data packets 73 | // Packet.sendPacket(dataArray1,sizeof(dataArray1)); 74 | // for(int i=0;i 24 && counter < 30){ 80 | // Packet.setPacketType(AGGREGATEDDATA); //data packets 81 | // Packet.sendPacket(dataArray2,sizeof(dataArray2)); 82 | // for(int i=0;i reply= data packet with sensorvalue=1 8 | // -- the number '2' --> reply= data packet with sensorvalue=2 9 | // -- the letter 'a' --> reply= command packet with commandValue=1 10 | // -- the letter 'b' --> reply= command packet with commandValue=2 11 | 12 | #include "SerialPacket.h" 13 | #include "defines.h" 14 | 15 | SerialPacket Packet; 16 | 17 | uint8_t sensorValue=1; 18 | uint8_t commandValue=1; 19 | 20 | #define MYCOMMAND1 1 21 | #define MYCOMMAND2 1 22 | 23 | #define MYDATA1 1 24 | #define MYDATA2 1 25 | 26 | void setup() 27 | { 28 | Packet.begin(115200,0); //begin(speed,nodeID); 29 | } 30 | 31 | void loop() 32 | { 33 | if (Serial.available() > 0) { 34 | char inByte = Serial.read(); 35 | 36 | if (inByte == '1') { 37 | Packet.sendData(sensorValue); 38 | } 39 | 40 | if (inByte == '2') { 41 | Packet.sendData(sensorValue*2); 42 | } 43 | 44 | if (inByte == 'a') { 45 | Packet.sendCommand(commandValue); 46 | } 47 | 48 | if (inByte == 'b') { 49 | Packet.sendCommand(commandValue*2); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /SerialPacket/examples/nose_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # nose_test.py is copyright 2013 Jeroen Doggen. 4 | 5 | import os 6 | import subprocess 7 | import shutil 8 | 9 | 10 | def test_build_examples(): 11 | failures = 0 12 | path = os.getcwd() 13 | for example in os.listdir(path): 14 | if(os.path.isdir(example)): 15 | os.chdir(example) 16 | state = subprocess.call("scons") 17 | if (state != 0): 18 | failures += 1 19 | cleanup(example) 20 | os.chdir("../") 21 | assert (failures == 0) 22 | 23 | 24 | #def test_upload_examples(): 25 | #failures = 0 26 | #path = os.getcwd() 27 | #for example in os.listdir(path): 28 | #if(os.path.isdir(example)): 29 | #os.chdir(example) 30 | #state = subprocess.call(["scons", "upload"]) 31 | #if (state != 0): 32 | #failures += 1 33 | #cleanup(example) 34 | #os.chdir("../") 35 | #assert (failures == 0) 36 | 37 | 38 | def cleanup(example): 39 | if (os.path.exists("build")): 40 | shutil.rmtree("build") 41 | 42 | hexfile = example + ".hex" 43 | if (os.path.exists(hexfile)): 44 | os.remove(hexfile) 45 | 46 | elffile = example + ".elf" 47 | if (os.path.exists(elffile)): 48 | os.remove(elffile) 49 | -------------------------------------------------------------------------------- /SerialPacket/keywords.txt: -------------------------------------------------------------------------------- 1 | SerialPacket KEYWORD1 2 | begin KEYWORD2 3 | setPacketType KEYWORD2 4 | sendPacket KEYWORD2 5 | -------------------------------------------------------------------------------- /SerialPacket/resources/COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | //fsf.org/> 5 | Copyright (C) 2007 Free Software Foundation, Inc.