blob: a826e5b5d337523469a0543317aa5a2c250a200a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 fortiss GmbH and Herwig Eichler, www.conmeleon.org
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alois Zoitl and Herwig Eichler
*******************************************************************************/
#include "processinterface.h"
const char * const CConmeleonC1ProcessInterface::scmUnknownChannel = "Channel number not existing";
const char * const CConmeleonC1ProcessInterface::scmChannelNotSupported = "Channel type not supported by hardware";
const char * const CConmeleonC1ProcessInterface::scmChannelInUse = "Channel already in use by other FB";
const char * const CConmeleonC1ProcessInterface::scmInitDeinitOK = "OK";
const char * const CConmeleonC1ProcessInterface::scmNotInitialised = "Not initialized";
const char * const CConmeleonC1ProcessInterface::scmOK = "OK";
CONMELEON::CGpioPin CConmeleonC1ProcessInterface::smDigitalInputs[] = {
{20, CONMELEON::input},
{21, CONMELEON::input},
{22, CONMELEON::input},
{23, CONMELEON::input}
};
CONMELEON::CGpioPin CConmeleonC1ProcessInterface::smDigitalOutputs[] = {
{24, CONMELEON::output},
{25, CONMELEON::output},
{26, CONMELEON::output},
{27, CONMELEON::output}
};
CONMELEON::CAds1018 CConmeleonC1ProcessInterface::smADC("/dev/spidev0.1", 1000000, CONMELEON::SPIMODE1);
CConmeleonC1ProcessInterface::EIOState CConmeleonC1ProcessInterface::smAIUsage[5] = {
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree
};
CConmeleonC1ProcessInterface::EIOState CConmeleonC1ProcessInterface::smDIUsage[4] = {
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree
};
CConmeleonC1ProcessInterface::EIOState CConmeleonC1ProcessInterface::smDOUsage[4] = {
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree,
CConmeleonC1ProcessInterface::enFree
};
CConmeleonC1ProcessInterface::CConmeleonC1ProcessInterface(CResource *paSrcRes, const SFBInterfaceSpec *paInterfaceSpec, const CStringDictionary::TStringId paInstanceNameId, TForteByte *paFBConnData, TForteByte *paFBVarsData) :
CProcessInterfaceBase(paSrcRes, paInterfaceSpec, paInstanceNameId, paFBConnData, paFBVarsData), mChannelNr(-1), mCallingFB(enUnsupported){
// initialize the ADC settings
smADC.setPGA(CONMELEON::FS4096); // maximum input voltage of ADC is 3.3V so we use 4.096V as full scale setting
smADC.setVoltageDivider(3.0); // CONMELEON C1 input voltage divider has value of 3.0: 10.0V to 3.3V
smADC.setConversionMode(CONMELEON::SingleShot); // set to single shot conversion mode
}
CConmeleonC1ProcessInterface::~CConmeleonC1ProcessInterface(){
}
bool CConmeleonC1ProcessInterface::initialise(bool m_bInputOrOutput){
CIEC_INT param;
param.fromString(PARAMS().getValue());
mChannelNr = param;
setCallingFBType(m_bInputOrOutput);
if (!checkChannelBoundaries()){
STATUS() = scmUnknownChannel;
return false;
}
if (checkCallingFBTypeIsIW()){
// we need to handle an analog input
if (smAIUsage[mChannelNr-1] == enFree){
smAIUsage[mChannelNr-1] = enUsed;
}
else{
STATUS() = scmChannelInUse;
return false;
}
}
else if (checkCallingFBTypeIsIX()){
// we need to handle an digital input
if (smDIUsage[mChannelNr-1] == enFree){
smDIUsage[mChannelNr-1] = enUsed;
// conmeleon c1 digital inputs have inverted logic level
smDigitalInputs[mChannelNr-1].setInverted(true);
}
else{
STATUS() = scmChannelInUse;
return false;
}
}
else if (checkCallingFBTypeIsQX()){
// we need to handle an digital output
if (smDOUsage[mChannelNr-1] == enFree){
smDOUsage[mChannelNr-1] = enUsed;
}
else{
STATUS() = scmChannelInUse;
return false;
}
}
else {
STATUS() = scmChannelNotSupported;
return false;
}
STATUS() = scmInitDeinitOK;
return true;
}
bool CConmeleonC1ProcessInterface::deinitialise(){
if (checkChannelBoundaries()){
if (checkCallingFBTypeIsIW()){
smAIUsage[mChannelNr-1] = enFree;
}
else if (checkCallingFBTypeIsIX()){
smDIUsage[mChannelNr-1] = enFree;
}
else if (checkCallingFBTypeIsQX()){
smDOUsage[mChannelNr-1] = enFree;
}
}
mChannelNr = -1;
mCallingFB = enUnsupported;
STATUS() = scmInitDeinitOK;
return true;
}
bool CConmeleonC1ProcessInterface::readPin(){
if (!checkChannelBoundaries()){
STATUS() = scmUnknownChannel;
return false;
}
if (checkCallingFBTypeIsIX()){
IN_X() = smDigitalInputs[mChannelNr-1].read();
STATUS() = scmOK;
return true;
}
else {
STATUS() = scmChannelNotSupported;
return false;
}
}
bool CConmeleonC1ProcessInterface::writePin(){
if (!checkChannelBoundaries()){
STATUS() = scmUnknownChannel;
return false;
}
if (checkCallingFBTypeIsQX()){
smDigitalOutputs[mChannelNr-1].write(OUT_X());
STATUS() = scmOK;
return true;
}
else {
STATUS() = scmChannelNotSupported;
return false;
}
}
bool CConmeleonC1ProcessInterface::readWord(){
if (!checkChannelBoundaries()){
STATUS() = scmUnknownChannel;
return false;
}
if (checkCallingFBTypeIsIW()){
if (mChannelNr <= 4) {
// read voltage input
IN_W() = static_cast<TForteWord>(smADC.readVoltage(mChannelNr-1));
}
if (mChannelNr == 5){
// read temperature input
IN_W() = static_cast<TForteWord>(smADC.readTemperature());
}
STATUS() = scmOK;
return true;
}
else {
STATUS() = scmChannelNotSupported;
return false;
}
}
void CConmeleonC1ProcessInterface::setCallingFBType(bool paIsInput){
mCallingFB = enUnsupported;
if (paIsInput){
// the only way is to check the interface of the FB
if (getDO(2)->getDataTypeID() == CIEC_ANY::e_WORD){
// IW FB called
mCallingFB = enIW;
}
else if (getDO(2)->getDataTypeID() == CIEC_ANY::e_BOOL){
// IX FB called
mCallingFB = enIX;
}
}
else {
if (getDI(2)->getDataTypeID() == CIEC_ANY::e_BOOL){
// QX FB called
mCallingFB = enQX;
}
}
}
bool CConmeleonC1ProcessInterface::checkChannelBoundaries() const{
// channel number should be between 1..4 for DI and DO and 1..5 for AI
if ((mChannelNr > 0) && ((checkCallingFBTypeIsIW() && (mChannelNr <= 5)) || (mChannelNr <= 4))){
return true;
}
return false;
}