-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #389 from micro-manager/ArduinoCounter
Arduino counter, adds option to invert output
- Loading branch information
Showing
3 changed files
with
182 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
// COPYRIGHT: Altos Labs, 2023, based on code copyright UCSF 2008 | ||
// LICENSE: LGPL | ||
// | ||
// AUTHOR: Nico Stuurman, [email protected], 7/13/2023 | ||
// AUTHOR: Nico Stuurman, [email protected], 7/13/2023, 10/10/2023 | ||
// | ||
|
||
#include "ArduinoCounter.h" | ||
|
@@ -25,10 +25,13 @@ const char* g_DeviceNameArduinoCounterCamera = "ArduinoCounterCamera"; | |
|
||
|
||
// Global info about the state of the Arduino. | ||
const double g_Min_MMVersion = 1.0; | ||
const double g_Max_MMVersion = 1.1; | ||
const double g_Min_MMVersion = 2.0; | ||
const double g_Max_MMVersion = 2.0; | ||
const char* g_versionProp = "Version"; | ||
const char* g_Undefined = "Undefined"; | ||
const char* g_Logic = "Output Logic"; | ||
const char* g_Direct = "Direct"; | ||
const char* g_Invert = "Invert"; | ||
|
||
|
||
|
||
|
@@ -64,7 +67,8 @@ MODULE_API void DeleteDevice(MM::Device* pDevice) | |
ArduinoCounterCamera::ArduinoCounterCamera() : | ||
imageBuffer_(0), | ||
nrCamerasInUse_(0), | ||
initialized_(false) | ||
initialized_(false), | ||
invert_(false) | ||
{ | ||
InitializeDefaultErrorMessages(); | ||
|
||
|
@@ -167,6 +171,11 @@ int ArduinoCounterCamera::Initialize() | |
sversion << version_; | ||
CreateProperty(g_versionProp, sversion.str().c_str(), MM::Float, true, pAct); | ||
|
||
pAct = new CPropertyAction(this, &ArduinoCounterCamera::OnLogic); | ||
CreateProperty(g_Logic, g_Direct, MM::String, false, pAct); | ||
AddAllowedValue(g_Logic, g_Direct); | ||
AddAllowedValue(g_Logic, g_Invert); | ||
|
||
|
||
initialized_ = true; | ||
|
||
|
@@ -745,6 +754,60 @@ int ArduinoCounterCamera::OnPort(MM::PropertyBase* pProp, MM::ActionType pAct) | |
return DEVICE_OK; | ||
} | ||
|
||
int ArduinoCounterCamera::OnLogic(MM::PropertyBase* pProp, MM::ActionType pAct) | ||
{ | ||
int ret = DEVICE_OK; | ||
unsigned char command[2]; | ||
command[0] = 'p'; | ||
std::string answer; | ||
if (pAct == MM::BeforeGet) | ||
{ | ||
command[1] = '?'; | ||
ret = WriteToComPort(port_.c_str(), (const unsigned char*)command, 2); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
ret = GetSerialAnswer(port_.c_str(), "\r\n", answer); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
if (answer == g_Invert) | ||
invert_ = true; | ||
else if (answer == g_Direct) | ||
invert_ = false; | ||
else | ||
return DEVICE_SERIAL_INVALID_RESPONSE; | ||
} | ||
else if (pAct == MM::AfterSet) | ||
{ | ||
std::string cmd; | ||
pProp->Get(cmd); | ||
if (cmd == g_Invert) { | ||
command[1] = 'i'; | ||
ret = WriteToComPort(port_.c_str(), (const unsigned char*)command, 2); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
ret = GetSerialAnswer(port_.c_str(), "\r\n", answer); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
if (answer != g_Invert) | ||
return DEVICE_SERIAL_INVALID_RESPONSE; | ||
invert_ = true; | ||
} | ||
else if (cmd == g_Direct) { | ||
command[1] = 'd'; | ||
ret = WriteToComPort(port_.c_str(), (const unsigned char*)command, 2); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
ret = GetSerialAnswer(port_.c_str(), "\r\n", answer); | ||
if (ret != DEVICE_OK) | ||
return ret; | ||
if (answer != g_Direct) | ||
return DEVICE_SERIAL_INVALID_RESPONSE; | ||
invert_ = false; | ||
} | ||
} | ||
return DEVICE_OK; | ||
} | ||
|
||
int ArduinoCounterCamera::OnVersion(MM::PropertyBase* pProp, MM::ActionType pAct) | ||
{ | ||
if (pAct == MM::BeforeGet) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 114 additions & 58 deletions
172
DeviceAdapters/ArduinoCounter/ArduinoCounter/ArduinoCounter.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,145 @@ | ||
unsigned int version_ = 1; | ||
// Arduino firmware that counts input pulses, relays these to | ||
// the output, but stops doing so after a specified | ||
// amount of pulses has been received. | ||
// Since version 2, also can invert the output. | ||
// Communicates through serial, commands: | ||
// gnnn - starts pulse counting. nnn should be an | ||
// integer number (of any size) | ||
// s - Stops counting, and reverts to transducing | ||
// all input to the output | ||
// i - Info: returns identification string | ||
// pn - Sets/Reads the flag inverting the input polarity | ||
// n=i Invert the input to the output | ||
// n=d Do not invert the input to the output | ||
// n=? report output polarity | ||
|
||
// pin on which to receive the trigger (2 and 3 can be used with interrupts, although this code does not use interrupts) | ||
const int inPin = 2; | ||
|
||
|
||
const int outPin = 8; | ||
|
||
const unsigned long timeOut = 1000; | ||
unsigned int version_ = 2; | ||
|
||
unsigned int counter = 0; | ||
unsigned int limit; | ||
boolean counting = false; | ||
boolean inputWas; | ||
// pin on which to receive the trigger (2 and 3 can be used with interrupts, although this code does not use interrupts) | ||
const int inPin = 2; | ||
|
||
|
||
const int outPin = 8; | ||
|
||
const unsigned long timeOut = 1000; | ||
|
||
unsigned int counter = 0; | ||
unsigned int limit; | ||
boolean counting = false; | ||
boolean inputWas; | ||
boolean invert = false; | ||
|
||
void setup() { | ||
// put your setup code here, to run once: | ||
Serial.begin(115200); | ||
Serial.begin(115200); | ||
|
||
|
||
pinMode(inPin, INPUT); | ||
pinMode(outPin, OUTPUT); | ||
pinMode(inPin, INPUT); | ||
pinMode(outPin, OUTPUT); | ||
|
||
inputWas = digitalRead(inPin); | ||
|
||
inputWas = digitalRead(inPin); | ||
} | ||
|
||
void loop() { | ||
while(true){ | ||
// put your main code here, to run repeatedly: | ||
|
||
if (Serial.available() > 0) { | ||
int inByte = Serial.read(); | ||
switch (inByte) { | ||
|
||
// go (i.e. start) 'g' followed by max number of TTLs to pass | ||
case 103: | ||
if (waitForSerial(timeOut)) { | ||
limit = Serial.parseInt(); | ||
Serial.write("Starting with "); | ||
Serial.println(limit, DEC); | ||
while (true) { | ||
// put your main code here, to run repeatedly: | ||
|
||
if (Serial.available() > 0) { | ||
int inByte = Serial.read(); | ||
switch (inByte) { | ||
|
||
// go (i.e. start) 'g' followed by max number of TTLs to pass | ||
case 103: | ||
if (waitForSerial(timeOut)) { | ||
limit = Serial.parseInt(); | ||
Serial.write("Starting with "); | ||
Serial.println(limit, DEC); | ||
// set limit here | ||
counting = true; | ||
counter = 0; | ||
inputWas = digitalRead(inPin); | ||
break; | ||
} | ||
counting = true; | ||
counter = 0; | ||
inputWas = digitalRead(inPin); | ||
break; | ||
} | ||
|
||
// stop 's'; i.e. operate in passthrough mode | ||
case 115: | ||
counting = false; | ||
Serial.println("Stopping"); | ||
Serial.println("Stopping"); | ||
break; | ||
|
||
// get info 'i'; what version are you? | ||
case 105: | ||
Serial.println("ArduinoCounter version 1.0"); | ||
} | ||
|
||
|
||
} | ||
Serial.println("ArduinoCounter version 2.0"); | ||
break; | ||
|
||
// Sets/gets output polarity | ||
case 112: | ||
if (waitForSerial(timeOut)) { | ||
int command = Serial.read(); | ||
switch (command) { | ||
case 105: // "i" | ||
invert = true; | ||
Serial.println("Invert"); | ||
break; | ||
|
||
case 100: // "d" | ||
invert = false; | ||
Serial.println("Direct"); | ||
break; | ||
|
||
case 63: // "?" | ||
if (invert) { | ||
Serial.println("Invert"); | ||
} else { | ||
Serial.println("Direct"); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
if (counting) { | ||
if (inputWas && !(PIND & B00000100)) { | ||
counter++; | ||
inputWas = LOW; | ||
if (counter <= limit) { | ||
if (counting) { | ||
if (invert) { | ||
if (inputWas && !(PIND & B00000100)) { | ||
counter++; | ||
inputWas = LOW; | ||
PORTB = 1; | ||
} else if (!inputWas && (PIND & B00000100)) { | ||
counter++; | ||
inputWas = HIGH; | ||
if (counter <= limit) { | ||
PORTB = 0; | ||
} | ||
} | ||
} else { // do not invert output | ||
if (inputWas && !(PIND & B00000100)) { | ||
counter++; | ||
inputWas = LOW; | ||
if (counter <= limit) { | ||
PORTB = 0; | ||
} | ||
} else if (!inputWas && (PIND & B00000100)) { | ||
} | ||
} else if (!inputWas && (PIND & B00000100)) { | ||
inputWas = HIGH; | ||
PORTB = 1; | ||
} | ||
} | ||
} else { | ||
PORTB = (PIND & B00000100) >> 2; | ||
} | ||
} else { // not counting | ||
if (invert) { | ||
PORTB = !(PIND & B00000100); | ||
} else { | ||
PORTB = (PIND & B00000100) >> 2; | ||
} | ||
} | ||
} | ||
} | ||
|
||
bool waitForSerial(unsigned long timeOut) | ||
{ | ||
unsigned long startTime = millis(); | ||
while (Serial.available() == 0 && (millis() - startTime < timeOut) ) {} | ||
if (Serial.available() > 0) | ||
return true; | ||
return false; | ||
} | ||
bool waitForSerial(unsigned long timeOut) { | ||
unsigned long startTime = millis(); | ||
while (Serial.available() == 0 && (millis() - startTime < timeOut)) {} | ||
if (Serial.available() > 0) | ||
return true; | ||
return false; | ||
} |