Skip to content
Snippets Groups Projects
Commit 39258e18 authored by Evan Paul Mladina's avatar Evan Paul Mladina
Browse files

kk additions not yet pushed. Should fix LVenable test

parent bca804a5
Branches calibrationEM
No related tags found
No related merge requests found
...@@ -11,6 +11,7 @@ target_sources(DevCom ...@@ -11,6 +11,7 @@ target_sources(DevCom
PCA9548ACom.cpp PCA9548ACom.cpp
SPICom.cpp SPICom.cpp
SPIDevCom.cpp
ComIOException.cpp ComIOException.cpp
NotSupportedException.cpp NotSupportedException.cpp
...@@ -32,7 +33,7 @@ target_sources(DevCom ...@@ -32,7 +33,7 @@ target_sources(DevCom
AD799X.cpp AD799X.cpp
MAX11619.cpp MAX11619.cpp
MCP3425.cpp MCP3425.cpp
#LTC2333.cpp LTC2451.cpp
MCP3428.cpp MCP3428.cpp
IOExpander.cpp IOExpander.cpp
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#ifndef __APPLE__ #ifndef __APPLE__
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -24,7 +25,9 @@ I2CDevCom::I2CDevCom(uint8_t deviceAddr, const std::string& i2cdev) ...@@ -24,7 +25,9 @@ I2CDevCom::I2CDevCom(uint8_t deviceAddr, const std::string& i2cdev)
} }
I2CDevCom::~I2CDevCom() I2CDevCom::~I2CDevCom()
{ } {
close(m_fh);
}
void I2CDevCom::write_reg32(uint32_t address, uint32_t data) void I2CDevCom::write_reg32(uint32_t address, uint32_t data)
{ {
......
#include "LTC2451.h"
#include "LinearCalibration.h"
#include "NotSupportedException.h"
#include "OutOfRangeException.h"
LTC2451::LTC2451(double reference, std::shared_ptr<I2CCom> com)
: ADCDevice(std::make_shared<LinearCalibration>(reference, 0xFFFF)),
m_com(com)
{ }
LTC2451::~LTC2451()
{ }
int32_t LTC2451::readCount()
{
return m_com->read_reg16(0x00);
}
int32_t LTC2451::readCount(uint8_t ch)
{
if(ch!=0)
throw OutOfRangeException(ch,0,0);
return readCount();
}
void LTC2451::readCount(const std::vector<uint8_t>& chs, std::vector<int32_t>& counts)
{
counts.clear();
for(uint8_t ch : chs)
counts.push_back(readCount(ch));
}
#ifndef LTC2451_H
#define LTC2451_H
#include <stdint.h>
#include <memory>
#include "I2CCom.h"
#include "ADCDevice.h"
class LTC2451 : public ADCDevice
{
public:
LTC2451(double reference, std::shared_ptr<I2CCom> com);
virtual ~LTC2451();
virtual int32_t readCount();
virtual int32_t readCount(uint8_t ch);
virtual void readCount(const std::vector<uint8_t>& chs, std::vector<int32_t>& data);
private:
std::shared_ptr<I2CCom> m_com;
};
#endif // LTC2451_H
#include "SPIDevCom.h"
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include "ComIOException.h"
SPIDevCom::SPIDevCom(const std::string& spidev)
: SPICom()
{
m_fh = open(spidev.c_str(), O_RDWR);
if(m_fh<0)
throw ComIOException(std::string("SPIDevCom open failed: ")+std::strerror(errno));
}
SPIDevCom::~SPIDevCom()
{ }
void SPIDevCom::write_reg32(uint32_t address, uint32_t data)
{
write_block(address,
{static_cast<uint8_t>((data>>24)&0xFF),
static_cast<uint8_t>((data>>16)&0xFF),
static_cast<uint8_t>((data>> 8)&0xFF),
static_cast<uint8_t>((data>> 0)&0xFF)});
}
void SPIDevCom::write_reg16(uint32_t address, uint16_t data)
{
write_block(address,
{static_cast<uint8_t>((data>> 8)&0xFF),
static_cast<uint8_t>((data>> 0)&0xFF)});
}
void SPIDevCom::write_reg8 (uint32_t address, uint8_t data)
{
write_block(address,{data});
}
void SPIDevCom::write_reg32(uint32_t data)
{
write_block({static_cast<uint8_t>((data>>24)&0xFF),
static_cast<uint8_t>((data>>16)&0xFF),
static_cast<uint8_t>((data>> 8)&0xFF),
static_cast<uint8_t>((data>> 0)&0xFF)});
}
void SPIDevCom::write_reg16(uint16_t data)
{
write_block({static_cast<uint8_t>((data>> 8)&0xFF),
static_cast<uint8_t>((data>> 0)&0xFF)});
}
void SPIDevCom::write_reg8 (uint8_t data)
{
write_block({data});
}
void SPIDevCom::write_block(uint32_t address, const std::vector<uint8_t>& data)
{
std::vector<uint8_t> inbuf=data;
inbuf.insert(inbuf.begin(),static_cast<uint8_t>(address&0xFF));
write_block(inbuf);
}
void SPIDevCom::write_block(const std::vector<uint8_t>& data)
{
struct spi_ioc_transfer msgs[1];
memset(msgs, 0, sizeof msgs);
msgs[0].tx_buf = (unsigned long)&data[0];
msgs[0].len = data.size();
if (ioctl(m_fh, SPI_IOC_MESSAGE(1), &msgs) < 0)
throw ComIOException(std::string("SPIDevCom write_reg32 failed: ")+std::strerror(errno));
}
uint32_t SPIDevCom::read_reg32(uint32_t address)
{
write_reg8(address&0xFF);
return read_reg32();
}
uint16_t SPIDevCom::read_reg16(uint32_t address)
{
write_reg8(address&0xFF);
return read_reg16();
}
uint8_t SPIDevCom::read_reg8 (uint32_t address)
{
write_reg8(address&0xFF);
return read_reg8();
}
uint32_t SPIDevCom::read_reg32()
{
std::vector<uint8_t> data(4);
read_block(data);
return (data[0]<<24|data[1]<<16|data[2]<<8|data[3]);
}
uint16_t SPIDevCom::read_reg16()
{
std::vector<uint8_t> data(2);
read_block(data);
return (data[0]<<8|data[1]);
}
uint8_t SPIDevCom::read_reg8 ()
{
std::vector<uint8_t> data(1);
read_block(data);
return data[0];
}
void SPIDevCom::read_block(uint32_t address, std::vector<uint8_t>& data)
{
write_reg8(address&0xFF);
read_block(data);
}
void SPIDevCom::read_block(std::vector<uint8_t>& data)
{
struct spi_ioc_transfer msgs[1];
memset(msgs, 0, sizeof msgs);
msgs[0].rx_buf =(unsigned long)&data[0];
msgs[0].len = data.size();
if (ioctl(m_fh, SPI_IOC_MESSAGE(1), &msgs) < 0)
throw ComIOException(std::string("SPIDevCom read_reg16 failed: ")+std::strerror(errno));
}
#ifndef SPIDEVCOM_H
#define SPIDEVCOM_H
#include "SPICom.h"
class SPIDevCom : public SPICom
{
public:
SPIDevCom(const std::string& spidev);
virtual ~SPIDevCom();
//
// Write commands
virtual void write_reg32(uint32_t address, uint32_t data);
virtual void write_reg16(uint32_t address, uint16_t data);
virtual void write_reg8 (uint32_t address, uint8_t data);
virtual void write_reg32(uint32_t data);
virtual void write_reg16(uint16_t data);
virtual void write_reg8 (uint8_t data);
virtual void write_block(uint32_t address, const std::vector<uint8_t>& data);
virtual void write_block(const std::vector<uint8_t>& data);
//
// Read commands
virtual uint32_t read_reg32(uint32_t address);
virtual uint16_t read_reg16(uint32_t address);
virtual uint8_t read_reg8 (uint32_t address);
virtual uint32_t read_reg32();
virtual uint16_t read_reg16();
virtual uint8_t read_reg8 ();
virtual void read_block(uint32_t address, std::vector<uint8_t>& data);
virtual void read_block(std::vector<uint8_t>& data);
private:
int m_fh =0;
};
#endif // SPIDEVCOM_H
#include "DT54xxPs.h"
#include <algorithm>
#include <thread>
#include <iostream>
#include "Logger.h"
DT54xxPs::DT54xxPs(const std::string& dev)
{
m_com = std::make_shared<SerialCom>(dev, B9600);
}
void DT54xxPs::send(const std::string& cmd)
{
logger(logDEBUG2) << __PRETTY_FUNCTION__ << " -> Sending: " << cmd;
m_com->write(cmd+"\r\n");
std::this_thread::sleep_for(std::chrono::milliseconds(m_wait));
}
std::string DT54xxPs::receive(const std::string& cmd)
{
logger(logDEBUG2) << __PRETTY_FUNCTION__ << " -> Sending: " << cmd;
m_com->write(cmd+"\r\n");
std::this_thread::sleep_for(std::chrono::milliseconds(m_wait));
std::string buf;
m_com->read(buf);
logger(logDEBUG2) << __PRETTY_FUNCTION__ << " -> Received: " << buf;
return buf;
}
std::string DT54xxPs::command(const std::string& cmd, const std::string& par, const std::string& value)
{
// Build command
std::string tosend="$CMD:"+cmd+",PAR:"+par;
if(!value.empty())
tosend+=",VAL:"+value;
// Send command and receive response
std::string resp=receive(tosend);
// Parse response
if(resp.empty())
throw "DT54xx: No response :(";
std::string retvalue;
std::string cmdvalue;
std::string token;
std::stringstream ss(resp);
while(std::getline(ss, token, ','))
{
size_t seppos=token.find(':');
if(seppos==std::string::npos)
continue; // Not a valid part
if(token.substr(0,seppos)=="VAL")
{ // This is the value part!
retvalue=token.substr(seppos+1);
}
else if(token.substr(0,seppos)=="#CMD")
{ // This is the value part!
cmdvalue=token.substr(seppos+1);
}
}
if(cmdvalue.empty())
throw "DT54xx: No CMD in return statement :(";
cmdvalue.erase(std::remove_if(cmdvalue.begin(), cmdvalue.end(),
[](char ch) { return ch=='\n' || ch=='\r'; }
), cmdvalue.end());
retvalue.erase(std::remove_if(retvalue.begin(), retvalue.end(),
[](char ch) { return ch=='\n' || ch=='\r'; }
), retvalue.end());
if(cmdvalue=="ERR")
throw "DT54xx:: CMD shows an error :(";
return retvalue;
}
void DT54xxPs::init()
{
// Check if the PS is connected
std::string idn=command("MON","BDNAME");
if(idn!="DT5472 500V / 1mA ")
throw std::string("Unknown power supply: "+idn);
turnOff();
command("SET","BDCLR");
}
void DT54xxPs::reset()
{
command("SET","BDCLR");
}
void DT54xxPs::setIMonRange(bool high)
{
command("SET", "IMRANGE", (high)?"HIGH":"LOW");
}
void DT54xxPs::setVoltage(double volt)
{
command("SET", "VSET", std::to_string(volt));
while((status()&Status::RampingUp) || (status()&Status::RampingDown))
{
double volt=getVoltage();
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> ramping: " << volt << "V";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
double DT54xxPs::getVoltage()
{
return std::stod(command("MON","VMON"));
}
void DT54xxPs::setCurrent(double cur)
{
command("SET", "ISET", std::to_string(cur*1e6));
}
double DT54xxPs::getCurrent()
{
return std::stod(command("MON","IMON"))/1e6;
}
void DT54xxPs::turnOn()
{
command("SET","ON");
while(status()&Status::RampingUp)
{
double volt=getVoltage();
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> ramping up: " << volt << "V";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void DT54xxPs::turnOff()
{
command("SET","OFF");
while(status()&Status::RampingDown)
{
double volt=getVoltage();
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> ramping down: " << volt << "V";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
uint16_t DT54xxPs::status()
{
return std::stoi(command("MON","STAT"))&0xFFFF;
}
#ifndef DT54XXPS_H
#define DT54XXPS_H
#include <string>
#include <memory>
#include <chrono>
#include "SerialCom.h"
#include "GenericPs.h"
/**
* CAEN DT54xx USB High Voltage Power Supplies
* https://www.caen.it/products/dt5472/
*
* Assumes direct USB connection
*/
class DT54xxPs : public GenericPs
{
public:
/**
* Interpretation of status bits.
* The value is the bitmask to select the bit in status() return value.
*/
enum Status
{
On =(1<< 0), // 1 : ON 0 : OFF
RampingUp =(1<< 1), // 1 : Channel Ramping UP
RampingDown=(1<< 2), // 1 : Channel Ramping DOWN
OVC =(1<< 3), // 1 : Over current
OVV =(1<< 4), // 1 : Over voltage
UNV =(1<< 5), // 1 : Under voltage
MAXV =(1<< 6), // 1 : VOUT in MAXV protection
Trip =(1<< 7), // 1 : Current generator
OVT =(1<< 8), // 1 : Over temperature
Disabled =(1<<10), // 1 : Ch disabled
Kill =(1<<11), // 1 : Ch in KILL
Interlock =(1<<12), // 1 : Ch in INTERLOCK
CalError =(1<<13) // 1 : Calibration Error
};
/**
* \param dev Serial port device to use for communication
*/
DT54xxPs(const std::string& dev);
~DT54xxPs() =default;
void init();
void reset();
void setVoltage(double volt);
double getVoltage();
void setCurrent(double cur);
double getCurrent();
/**
* Enable power supply output
*
* Block until power supply finishes ramping.
*/
void turnOn();
/**
* Disable power supply output
*
* Block until power supply finishes rampdown.
*/
void turnOff();
/**
* Return the status of the Power Supply.
* Use with Status enum to interpret bits.
*
* \return status bits
*/
uint16_t status();
/**
* Set the current monitoring range to high or low.
*
* \param high true for high range, false for low
*/
void setIMonRange(bool high);
private:
std::shared_ptr<SerialCom> m_com;
/**
* Send string over serial port without checking for a response.
*
* \param cmd string to send
*/
void send(const std::string& cmd);
/**
* Send string over serial port and return the response
*
* \param cmd string to send
*
* \return Response from the power supply
*/
std::string receive(const std::string& cmd);
/**
* Build a command string and parse the response/
*
* Throws an exception if any of the following errors are detected:
* - no response
* - returned CMD value is ERR
*
* \param cmd CMD value
* \param par PAR value
* \param value VAL value (if empty, not appended)
*
* \return The returned VAL value.
*/
std::string command(const std::string& cmd, const std::string& par, const std::string& value="");
//! Time to wait before checking for response
std::chrono::milliseconds m_wait{200};
};
#endif // DT54XXPS_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment