Skip to content

Commit ac94e40

Browse files
authored
Merge pull request #81 from open-ephys-plugins/issue-77
Aggregate updates for new firmware version
2 parents 5907dee + c17fa54 commit ac94e40

File tree

13 files changed

+246
-18
lines changed

13 files changed

+246
-18
lines changed

Source/Devices/DeviceList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "MemoryMonitor.h"
2929
#include "OutputClock.h"
3030
#include "Heartbeat.h"
31+
#include "PersistentHeartbeat.h"
3132
#include "HarpSyncInput.h"
3233
#include "AnalogIO.h"
3334
#include "DigitalIO.h"

Source/Devices/Heartbeat.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,32 @@ bool Heartbeat::updateSettings()
4848
{
4949
oni_reg_val_t clkHz;
5050
int rc = deviceContext->readRegister(deviceIdx, (oni_reg_addr_t)HeartbeatRegisters::CLK_HZ, &clkHz);
51+
if (rc != ONI_ESUCCESS) return false;
52+
5153
rc = deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)HeartbeatRegisters::CLK_DIV, clkHz / beatsPerSecond);
5254

5355
if (rc == ONI_EREADONLY) return true; // NB: Ignore read-only errors
5456

5557
return rc == ONI_ESUCCESS;
5658
}
59+
60+
void Heartbeat::startAcquisition()
61+
{
62+
}
63+
64+
void Heartbeat::stopAcquisition()
65+
{
66+
}
67+
68+
void Heartbeat::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
69+
{
70+
}
71+
72+
void Heartbeat::addFrame(oni_frame_t* frame)
73+
{
74+
oni_destroy_frame(frame);
75+
}
76+
77+
void Heartbeat::processFrames()
78+
{
79+
}

Source/Devices/Heartbeat.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,17 @@ namespace OnixSourcePlugin
4848
bool updateSettings() override;
4949

5050
/** Starts probe data streaming */
51-
void startAcquisition() override {};
51+
void startAcquisition() override;
5252

5353
/** Stops probe data streaming*/
54-
void stopAcquisition() override {};
54+
void stopAcquisition() override;
5555

5656
/** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */
57-
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override {};
57+
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override;
5858

59-
void addFrame(oni_frame_t* frame) override { oni_destroy_frame(frame); }
59+
void addFrame(oni_frame_t* frame) override;
6060

61-
void processFrames() override {};
61+
void processFrames() override;
6262

6363
static OnixDeviceType getDeviceType();
6464

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
Copyright (C) Open Ephys
5+
6+
------------------------------------------------------------------
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+
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
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
21+
*/
22+
23+
#include "PersistentHeartbeat.h"
24+
25+
using namespace OnixSourcePlugin;
26+
27+
PersistentHeartbeat::PersistentHeartbeat(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr<Onix1> oni_ctx)
28+
: OnixDevice(name, hubName, PersistentHeartbeat::getDeviceType(), deviceIdx_, oni_ctx)
29+
{
30+
}
31+
32+
OnixDeviceType PersistentHeartbeat::getDeviceType()
33+
{
34+
return OnixDeviceType::PERSISTENTHEARTBEAT;
35+
}
36+
37+
int PersistentHeartbeat::configureDevice()
38+
{
39+
if (deviceContext == nullptr || !deviceContext->isInitialized())
40+
throw error_str("Device context is not initialized properly for " + getName());
41+
42+
setEnabled(true); // NB: PersistentHeart is always enabled.
43+
44+
return ONI_ESUCCESS;
45+
}
46+
47+
bool PersistentHeartbeat::updateSettings()
48+
{
49+
oni_reg_val_t clkHz;
50+
51+
int rc = deviceContext->readRegister(deviceIdx, (oni_reg_addr_t)PersistentHeartbeatRegisters::CLK_HZ, &clkHz);
52+
if (rc != ONI_ESUCCESS) return false;
53+
54+
rc = deviceContext->readRegister(deviceIdx, (oni_reg_addr_t)PersistentHeartbeatRegisters::MIN_HB_HZ, &minimumHeartbeatHz);
55+
if (rc != ONI_ESUCCESS) return false;
56+
57+
if (beatsPerSecond < minimumHeartbeatHz || beatsPerSecond > MaxBeatsPerSecond)
58+
{
59+
LOGE("Invalid beats per second for persistent heartbeat device. Value must be between " + std::to_string(minimumHeartbeatHz) +
60+
" and " + std::to_string(MaxBeatsPerSecond));
61+
return false;
62+
}
63+
64+
rc = deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)PersistentHeartbeatRegisters::CLK_DIV, clkHz / beatsPerSecond);
65+
66+
return rc == ONI_ESUCCESS;
67+
}
68+
69+
void PersistentHeartbeat::startAcquisition()
70+
{
71+
}
72+
73+
void PersistentHeartbeat::stopAcquisition()
74+
{
75+
}
76+
77+
void PersistentHeartbeat::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
78+
{
79+
}
80+
81+
void PersistentHeartbeat::addFrame(oni_frame_t* frame)
82+
{
83+
oni_destroy_frame(frame);
84+
}
85+
86+
void PersistentHeartbeat::processFrames()
87+
{
88+
}
89+
90+
void PersistentHeartbeat::setBeatsPerSecond(uint32_t value)
91+
{
92+
beatsPerSecond = value;
93+
}
94+
95+
uint32_t PersistentHeartbeat::getBeatsPerSecond() const
96+
{
97+
return beatsPerSecond;
98+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
Copyright (C) Open Ephys
5+
6+
------------------------------------------------------------------
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+
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
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
21+
*/
22+
23+
#pragma once
24+
25+
#include "../OnixDevice.h"
26+
27+
namespace OnixSourcePlugin
28+
{
29+
enum class PersistentHeartbeatRegisters : uint32_t
30+
{
31+
ENABLE = 0, // Heartbeat enable state (read only; always enabled for this device).
32+
CLK_DIV = 1, // Heartbeat clock divider ratio. Minimum value is CLK_HZ / 10e6.
33+
// Maximum value is CLK_HZ / MIN_HB_HZ.Attempting to set to a value outside
34+
// this range will result in error.
35+
CLK_HZ = 2, // The frequency parameter, CLK_HZ, used in the calculation of CLK_DIV
36+
MIN_HB_HZ = 3 // The minimum allowed beat frequency, in Hz, for this device
37+
};
38+
39+
/*
40+
Configures a Heartbeat device on a Breakout Board
41+
*/
42+
class PersistentHeartbeat : public OnixDevice
43+
{
44+
public:
45+
PersistentHeartbeat(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr<Onix1> oni_ctx);
46+
47+
/** Configures the device so that it is ready to stream with default settings */
48+
int configureDevice() override;
49+
50+
/** Update the settings of the device */
51+
bool updateSettings() override;
52+
53+
/** Starts probe data streaming */
54+
void startAcquisition() override;
55+
56+
/** Stops probe data streaming*/
57+
void stopAcquisition() override;
58+
59+
/** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */
60+
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override;
61+
62+
void addFrame(oni_frame_t* frame) override;
63+
64+
void processFrames() override;
65+
66+
static OnixDeviceType getDeviceType();
67+
68+
void setBeatsPerSecond(uint32_t value);
69+
70+
uint32_t getBeatsPerSecond() const;
71+
72+
private:
73+
74+
uint32_t minimumHeartbeatHz = 100;
75+
uint32_t beatsPerSecond = 100;
76+
77+
static constexpr uint32_t MaxBeatsPerSecond = 10e6;
78+
79+
JUCE_LEAK_DETECTOR(PersistentHeartbeat);
80+
};
81+
}

Source/Devices/PolledBno055.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,13 @@ void PolledBno055::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
209209

210210
int16_t PolledBno055::readInt16(uint32_t startAddress)
211211
{
212-
oni_reg_val_t byte1 = 0, byte2 = 0;
212+
uint32_t value = 0;
213+
int rc = ReadWord(startAddress, 2, &value);
213214

214-
int rc = ReadByte(startAddress, &byte1);
215-
if (rc != ONI_ESUCCESS) return 0;
216-
rc = ReadByte(startAddress + 1, &byte2);
217-
if (rc != ONI_ESUCCESS) return 0;
215+
if (rc != ONI_ESUCCESS)
216+
return 0;
218217

219-
return (static_cast<int16_t>(byte2) << 8) | byte1;
218+
return static_cast<int16_t>(value);
220219
}
221220

222221
void PolledBno055::hiResTimerCallback()

Source/I2CRegisterContext.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,20 @@ int I2CRegisterContext::WriteByte(uint32_t address, uint32_t value, bool sixteen
4040

4141
int I2CRegisterContext::ReadByte(uint32_t address, oni_reg_val_t* value, bool sixteenBitAddress)
4242
{
43+
return ReadWord(address, 1, value, sixteenBitAddress);
44+
}
45+
46+
int I2CRegisterContext::ReadWord(uint32_t address, uint32_t numBytes, uint32_t* value, bool sixteenBitAddress)
47+
{
48+
if (numBytes < 1 || numBytes > 4)
49+
{
50+
LOGE("Invalid number of bytes requested when reading a word.");
51+
return 1;
52+
}
53+
4354
uint32_t registerAddress = (address << 7) | (i2cAddress & 0x7F);
4455
registerAddress |= sixteenBitAddress ? 0x80000000 : 0;
56+
registerAddress |= (numBytes - 1) << 28;
4557

4658
return i2cContext->readRegister(deviceIndex, registerAddress, value);
4759
}

Source/I2CRegisterContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ namespace OnixSourcePlugin
3939

4040
int WriteByte(uint32_t address, uint32_t value, bool sixteenBitAddress = false);
4141

42+
int WriteWord(uint32_t address, uint32_t value, uint32_t numBytes, bool sixteenBitAddress = false);
43+
4244
int ReadByte(uint32_t address, oni_reg_val_t* value, bool sixteenBitAddress = false);
4345

46+
int ReadWord(uint32_t address, uint32_t numBytes, uint32_t* value, bool sixteenBitAddress = false);
47+
4448
int set933I2cRate(double);
4549

4650
protected:

Source/OnixDevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespace OnixSourcePlugin
5151
MEMORYMONITOR,
5252
OUTPUTCLOCK,
5353
HEARTBEAT,
54+
PERSISTENTHEARTBEAT,
5455
HARPSYNCINPUT,
5556
ANALOGIO,
5657
DIGITALIO,

Source/OnixSource.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,10 @@ bool OnixSource::configureDevice(OnixDeviceVector& sources,
124124
LOGD("Difference in names found for device at address ", deviceIdx, ". Found ", deviceName, " on ", hubName, ", but was expecting ", device->getName(), " on ", device->getHubName());
125125
}
126126
}
127-
else if (device->getDeviceType() == OnixDeviceType::HEARTBEAT || device->getDeviceType() == OnixDeviceType::MEMORYMONITOR) // NB: These are devices with no equivalent settings tab that still need to be created and added to the vector of devices
128-
{
127+
else if (device->getDeviceType() == OnixDeviceType::HEARTBEAT ||
128+
device->getDeviceType() == OnixDeviceType::PERSISTENTHEARTBEAT ||
129+
device->getDeviceType() == OnixDeviceType::MEMORYMONITOR)
130+
{// NB: These are devices with no equivalent settings tab that still need to be created and added to the vector of devices
129131
LOGD("Creating new device ", deviceName, " on ", hubName);
130132
device = std::make_shared<Device>(deviceName, hubName, deviceIdx, ctx);
131133
}
@@ -233,7 +235,7 @@ bool OnixSource::checkHubFirmwareCompatibility(std::shared_ptr<Onix1> context, d
233235
{
234236
if (hubId == ONIX_HUB_FMCHOST) // NB: Breakout Board
235237
{
236-
static constexpr int RequiredMajorVersion = 1;
238+
static constexpr int RequiredMajorVersion = 2;
237239
uint32_t firmwareVersion = 0;
238240
if (!getHubFirmwareVersion(context, hubIndex, &firmwareVersion))
239241
{
@@ -247,7 +249,11 @@ bool OnixSource::checkHubFirmwareCompatibility(std::shared_ptr<Onix1> context, d
247249

248250
if (majorVersion != RequiredMajorVersion)
249251
{
250-
Onix1::showWarningMessageBoxAsync("Invalid Firmware Version", "The breakout board major version is v" + std::to_string(majorVersion) + ", but this plugin is only compatible with v" + std::to_string(RequiredMajorVersion) + ". To use this plugin, upgrade to a version that supports the breakout board v" + std::to_string(majorVersion));
252+
Onix1::showWarningMessageBoxAsync(
253+
"Invalid Firmware Version",
254+
"The breakout board firmware major version is v" + std::to_string(majorVersion) +
255+
", but this plugin is only compatible with v" + std::to_string(RequiredMajorVersion) +
256+
". To use this plugin, upgrade the firmware to a version that supports the breakout board v" + std::to_string(majorVersion));
251257
return false;
252258
}
253259
}
@@ -290,8 +296,8 @@ bool OnixSource::initializeDevices(device_map_t deviceTable, bool updateStreamIn
290296
hubNames.insert({ hubIndex, BREAKOUT_BOARD_NAME });
291297
auto canvas = editor->getCanvas();
292298

293-
devicesFound = configureDevice<Heartbeat>(sources, canvas, "Heartbeat", BREAKOUT_BOARD_NAME, Heartbeat::getDeviceType(), hubIndex, context);
294-
if (!devicesFound)
299+
devicesFound = configureDevice<PersistentHeartbeat>(sources, canvas, "Heartbeat", BREAKOUT_BOARD_NAME, PersistentHeartbeat::getDeviceType(), hubIndex, context);
300+
if (!devicesFound)
295301
{
296302
sources.clear();
297303
return false;
@@ -595,7 +601,10 @@ std::map<int, OnixDeviceType> OnixSource::createDeviceMap(OnixDeviceVector devic
595601

596602
for (const auto& device : devices)
597603
{
598-
if (filterDevices && (device->getDeviceType() == OnixDeviceType::HEARTBEAT || device->getDeviceType() == OnixDeviceType::MEMORYMONITOR)) continue;
604+
if (filterDevices &&
605+
(device->getDeviceType() == OnixDeviceType::HEARTBEAT ||
606+
device->getDeviceType() == OnixDeviceType::PERSISTENTHEARTBEAT ||
607+
device->getDeviceType() == OnixDeviceType::MEMORYMONITOR)) continue;
599608

600609
deviceMap.insert({ device->getDeviceIdx(), device->getDeviceType() });
601610
}

0 commit comments

Comments
 (0)