--- /dev/null
+#include <SPI.h>
+
+int dataPin = 11;
+int strobePin = 10;
+int clockPin = 13;
+int pwmPin = 3;
+
+byte keysState[2];
+byte maxDutyCycle = 255;
+byte minDutyCycle = 200;
+word boostDuration = 150;
+
+byte command = 0;
+
+void sendInformation()
+{
+ Serial.write(keysState[1]);
+ Serial.write(keysState[0]);
+ Serial.write(maxDutyCycle);
+ Serial.write(minDutyCycle);
+ Serial.write(boostDuration >> 8);
+ Serial.write(byte(boostDuration));
+}
+
+// 4Mbits/s
+void setKeyConfiguration()
+{
+ //disable the output duding the setup
+ digitalWrite(strobePin, LOW);
+ //sends the keystates
+ SPI.transfer(keysState[0]);
+ SPI.transfer(keysState[1]);
+ //enable the output
+ digitalWrite(strobePin, HIGH);
+ //sets the boostmode
+ analogWrite(pwmPin, maxDutyCycle);
+ //wait for the end of the boost
+ delay(boostDuration);
+ //sets the economy mode
+ analogWrite(pwmPin, minDutyCycle);
+}
+
+void setup()
+{
+ pinMode(strobePin, OUTPUT);
+ pinMode(pwmPin, OUTPUT);
+ SPI.begin();
+/*
+ pinMode(clockPin, OUTPUT);
+ pinMode(dataPin, OUTPUT);
+ pinMode(strobePin, OUTPUT);
+ */
+
+ Serial.begin(115200);
+ keysState[0] = 0;
+ keysState[1] = 0;
+ analogWrite(pwmPin, minDutyCycle);
+}
+
+/*
+ Protocol:
+ cXYZ... where c is a character (byte) representing the command
+ and XYZ... are the paremeters. Eack digit parameter is a byte
+ In this version we assume we control 16 keys thus we need
+ 16bits (2 bytes) for commands related to keys.
+ Commands:
+ SXY sets a configuration on keys
+ XY is the configuration. Here 1 represent a raised key,
+ 0 a lowered key.
+ RXY raise the specified keys
+ 1 raises a key, 0 does not change its state
+ LXY lowers the specified keys
+ 1 lowers a key, 0 does not change its state
+ MX sets the Maximum duty cycle
+ this parameter controls the voltage used in the boost mode
+ required to raise the key
+ mX sets the minimum duty cycle
+ this parameter controls the voltage used in economic mode
+ this voltage should be suficient to keep the key up
+ DX sets the duration of the boost mode in ms
+ boost mode uses voltage out of the range of the solenoids
+ specification. Thus this modeshould not last too long and
+ be used too often
+ I send information (parameters)
+*/
+void loop()
+{
+ if (Serial.available() == 0)
+ return;
+
+ if (command == 0)
+ command = Serial.read();
+ switch(command)
+ {
+ case 'S':
+ if (Serial.available() >= 2)
+ {
+ keysState[1] = Serial.read();
+ keysState[0] = Serial.read();
+ setKeyConfiguration();
+ command = 0;
+ }
+ break;
+ case 'R':
+ if (Serial.available() >= 2)
+ {
+ keysState[1] = keysState[1] | Serial.read();
+ keysState[0] = keysState[0] | Serial.read();
+ setKeyConfiguration();
+ command = 0;
+ }
+ break;
+ case 'L':
+ if (Serial.available() >= 2)
+ {
+ keysState[1] = keysState[1] & ~(Serial.read());
+ keysState[0] = keysState[0] & ~(Serial.read());
+ setKeyConfiguration();
+ command = 0;
+ }
+ break;
+ case 'M':
+ if (Serial.available() >= 1)
+ {
+ maxDutyCycle = Serial.read();
+ command = 0;
+ }
+ break;
+ case 'm':
+ if (Serial.available() >= 1)
+ {
+ minDutyCycle = Serial.read();
+ analogWrite(pwmPin, minDutyCycle);
+ command = 0;
+ }
+ break;
+ case 'D':
+ if (Serial.available() >= 2)
+ {
+ boostDuration = 0;
+ boostDuration = Serial.read() << 8;
+ boostDuration |= Serial.read();
+ command = 0;
+ }
+ break;
+ case 'I':
+ sendInformation();
+ command = 0;
+ break;
+ default:
+ command = 0;
+ break;
+ }
+}
+\r
--- /dev/null
+\r
+Microsoft Visual Studio Solution File, Format Version 11.00\r
+# Visual Studio 2010\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DynamicKeyboardLibrary", "DynamicKeyboardLibrary\DynamicKeyboardLibrary.vcxproj", "{291779F7-46DD-489D-BEB2-73D81107CFB3}"\r
+EndProject\r
+Global\r
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Win32 = Debug|Win32\r
+ Release|Win32 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {291779F7-46DD-489D-BEB2-73D81107CFB3}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {291779F7-46DD-489D-BEB2-73D81107CFB3}.Debug|Win32.Build.0 = Debug|Win32\r
+ {291779F7-46DD-489D-BEB2-73D81107CFB3}.Release|Win32.ActiveCfg = Release|Win32\r
+ {291779F7-46DD-489D-BEB2-73D81107CFB3}.Release|Win32.Build.0 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(SolutionProperties) = preSolution\r
+ HideSolutionNode = FALSE\r
+ EndGlobalSection\r
+EndGlobal\r
--- /dev/null
+#include "DynamicKeyboardController.h"\r
+\r
+#include <ArduinoSerial\SerialWindows.hpp>\r
+\r
+#include <cstdio>\r
+\r
+DynamicKeyboardController::DynamicKeyboardController(char *port, int baudrate)\r
+{\r
+ try\r
+ {\r
+ _comPort = new SerialWindows(port, baudrate);\r
+ }\r
+ catch (...)\r
+ {\r
+ _comPort = NULL;\r
+ }\r
+}\r
+\r
+void DynamicKeyboardController::setConfiguration(UINT16 config)\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[3];\r
+ buffer[0] = 'S';\r
+ buffer[1] = UINT8(config >> 8);\r
+ buffer[2] = UINT8(config & 0xff);\r
+ _comPort->WriteData(buffer, 3);\r
+}\r
+\r
+void DynamicKeyboardController::raiseKeys(UINT16 config)\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[3];\r
+ buffer[0] = 'R';\r
+ buffer[1] = UINT8(config >> 8);\r
+ buffer[2] = UINT8(config & 0xff);\r
+ _comPort->WriteData(buffer, 3);\r
+}\r
+\r
+void DynamicKeyboardController::lowerKeys(UINT16 config)\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[3];\r
+ buffer[0] = 'L';\r
+ buffer[1] = UINT8(config >> 8);\r
+ buffer[2] = UINT8(config & 0xff);\r
+ _comPort->WriteData(buffer, 3);\r
+}\r
+\r
+void DynamicKeyboardController::setMaximumDutyCycle(UINT8 val) const\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[2];\r
+ buffer[0] = 'M';\r
+ buffer[1] = val;\r
+ _comPort->WriteData(buffer, 2);\r
+}\r
+\r
+void DynamicKeyboardController::setMinimumDutyCycle(UINT8 val) const\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[2];\r
+ buffer[0] = 'm';\r
+ buffer[1] = val;\r
+ _comPort->WriteData(buffer, 2);\r
+}\r
+\r
+void DynamicKeyboardController::setBoostDuration(UINT16 val) const\r
+{\r
+ if (!_comPort)\r
+ return;\r
+ unsigned char buffer[3];\r
+ buffer[0] = 'D';\r
+ buffer[1] = val >> 8;\r
+ buffer[2] = val & 0x00ff;\r
+ _comPort->WriteData(buffer, 3);\r
+}\r
+\r
+bool DynamicKeyboardController::getState(UINT16 &solenoids, UINT8 &minDutyCycle, UINT8 &maxDutyCycle, UINT16 &boostDuration) const\r
+{\r
+ if (!_comPort)\r
+ return false;\r
+ _comPort->WriteData("I",1);\r
+ Sleep(1000);\r
+\r
+ /*\r
+ we currently receive 2 bytes for 16 keys states, max DC, min DC and boost duration\r
+ We may receive more bytes in the future if we handle more keys\r
+ */\r
+ unsigned char buffer[6];\r
+ _comPort->ReadData(buffer, 6);\r
+ solenoids = (UINT16(buffer[0]) << 8) | buffer[1];\r
+ maxDutyCycle = buffer[2];\r
+ minDutyCycle = buffer[3];\r
+ boostDuration = UINT16(buffer[4]) << 8 |buffer[5];\r
+ return true;\r
+}\r
+\r
+std::ostream& operator <<(std::ostream& stream, const DynamicKeyboardController& controller)\r
+{\r
+ UINT16 solenoids, duration;\r
+ UINT8 min, max;\r
+ if (!controller.getState(solenoids, min, max, duration))\r
+ return stream;\r
+\r
+ stream << std::hex << solenoids << std::dec << ";" << min << ";" << max << ";" << duration;\r
+\r
+ return stream;\r
+}\r
--- /dev/null
+#ifndef __DYNAMICKEYBOARDCONTROLLER__\r
+#define __DYNAMICKEYBOARDCONTROLLER__\r
+\r
+#include <ArduinoSerial\Serial.hpp>\r
+\r
+#include <iostream>\r
+\r
+typedef unsigned char UINT8;\r
+typedef unsigned short int UINT16;\r
+\r
+class DynamicKeyboardController\r
+{\r
+ public:\r
+ /*\r
+ Creates the controller for a dynamic keyboard\r
+ port is the COM port for the communication with the Arduino Board\r
+ baudrate is the baudrate for the communication, the default value may be sufficient\r
+ */\r
+ __declspec(dllexport) DynamicKeyboardController(char *port, int baudrate = 115200);\r
+\r
+ /* sets a configuration on keys\r
+ XY is the configuration. Here 1 represent a raised key, \r
+ 0 a lowered key.\r
+ */\r
+ __declspec(dllexport) void setConfiguration(UINT16 config);\r
+ /*\r
+ raise the specified keys\r
+ 1 raises a key, 0 does not change its state\r
+ */\r
+ __declspec(dllexport) void raiseKeys(UINT16 config);\r
+ /*\r
+ lowers the specified keys\r
+ 1 lowers a key, 0 does not change its state\r
+ */\r
+ __declspec(dllexport) void lowerKeys(UINT16 config);\r
+\r
+ /*\r
+ higher duty cycle values results to higher voltage\r
+ maximum is used to give a boost to raise the key\r
+ minimum is used to keep the key raised\r
+ the values are choosen with empirical tests, \r
+ depending on the solenoids and the power supply\r
+ */\r
+ __declspec(dllexport) void setMaximumDutyCycle(UINT8 val) const;\r
+ __declspec(dllexport) void setMinimumDutyCycle(UINT8 val) const;\r
+\r
+ /*\r
+ The shorter the boost mode the better since it goes beyond the standards\r
+ The longer the boost mode is, the longer we should wait before changing \r
+ the keys state again.\r
+ */\r
+ __declspec(dllexport) void setBoostDuration(UINT16) const;\r
+\r
+ /*\r
+ returns the state of the solenoids, the max and min duty cycle and the boost duration\r
+ */\r
+ __declspec(dllexport) bool getState(UINT16 &solenoids, UINT8 &minDutyCycle, UINT8 &maxDutyCycle, UINT16 &boostDuration) const;\r
+\r
+ /*\r
+ returns on the stream the state of the solenoids, the max and min duty cycle and the boost duration\r
+ */\r
+ __declspec(dllexport) friend std::ostream& operator<< (std::ostream& stream, const DynamicKeyboardController& controller);\r
+\r
+ protected:\r
+ Serial *_comPort;\r
+};\r
+\r
+#endif\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup Label="ProjectConfigurations">\r
+ <ProjectConfiguration Include="Debug|Win32">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|Win32">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ </ItemGroup>\r
+ <PropertyGroup Label="Globals">\r
+ <ProjectGuid>{291779F7-46DD-489D-BEB2-73D81107CFB3}</ProjectGuid>\r
+ <RootNamespace>DynamicKeyboardLibrary</RootNamespace>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+ <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+ <UseDebugLibraries>true</UseDebugLibraries>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+ <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+ <UseDebugLibraries>false</UseDebugLibraries>\r
+ <WholeProgramOptimization>true</WholeProgramOptimization>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+ <ImportGroup Label="ExtensionSettings">\r
+ </ImportGroup>\r
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ </ImportGroup>\r
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ </ImportGroup>\r
+ <PropertyGroup Label="UserMacros" />\r
+ <PropertyGroup />\r
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <ClCompile>\r
+ <WarningLevel>Level3</WarningLevel>\r
+ <Optimization>Disabled</Optimization>\r
+ </ClCompile>\r
+ <Link>\r
+ <GenerateDebugInformation>true</GenerateDebugInformation>\r
+ <AdditionalDependencies>arduinoseriald.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ </Link>\r
+ </ItemDefinitionGroup>\r
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <ClCompile>\r
+ <WarningLevel>Level3</WarningLevel>\r
+ <Optimization>MaxSpeed</Optimization>\r
+ <FunctionLevelLinking>true</FunctionLevelLinking>\r
+ <IntrinsicFunctions>true</IntrinsicFunctions>\r
+ </ClCompile>\r
+ <Link>\r
+ <GenerateDebugInformation>true</GenerateDebugInformation>\r
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+ <OptimizeReferences>true</OptimizeReferences>\r
+ <AdditionalDependencies>arduinoserial.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ </Link>\r
+ </ItemDefinitionGroup>\r
+ <ItemGroup>\r
+ <ClInclude Include="DynamicKeyboardController.h" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="DynamicKeyboardController.cpp" />\r
+ </ItemGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+ <ImportGroup Label="ExtensionTargets">\r
+ </ImportGroup>\r
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup>\r
+ <Filter Include="Source Files">\r
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+ </Filter>\r
+ <Filter Include="Header Files">\r
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+ </Filter>\r
+ <Filter Include="Resource Files">\r
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+ </Filter>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClInclude Include="DynamicKeyboardController.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="DynamicKeyboardController.cpp">\r
+ <Filter>Source Files</Filter>\r
+ </ClCompile>\r
+ </ItemGroup>\r
+</Project>
\ No newline at end of file