VMCPlugin/atb_system.cpp

724 lines
20 KiB
C++

#include "atb_system.h"
#include "ATBHMIconfig.h"
#include <QDebug>
#include <QProcess>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QTextStream>
#include <QString>
#include <QTimer>
ATB_system::ATB_system(ATBHMIconfig *config, QObject *parent) :
QObject(parent)
{
this->config = config;
this->tf_gpio = nullptr;
#if defined (ARCH_PTU2)
if (config->hasFeatureTF()) init_touch_feedback();
#elif defined (ARCH_PTU4)
if (config->hasFeatureTF()) init_touch_feedback();
#endif
}
ATB_system::~ATB_system()
{
if (config->hasFeatureTF()) {
delete(this->tf_gpio_outstream);
delete(this->tf_gpio);
}
}
void ATB_system::executeSystemCommand(quint16 cmd, QByteArray data)
{
Q_UNUSED(data);
switch (cmd) {
case SYS_COMMAND_SLEEP:
qDebug() << "ATB_system::executeSystemCommand(): " << cmd;
dbus_permitSuspend();
break;
case SYS_COMMAND_DIMLOW:
if (config->hasFeatureDBusDisplayControl()) {
dbus_DimControlStart();
} else {
this->DimLow();
}
break;
case SYS_COMMAND_DIMHIGH:
if (config->hasFeatureDBusDisplayControl()) {
dbus_DimHighPermanent();
} else {
this->DimHigh();
}
break;
case SYS_COMMAND_BEEP:
if (config->hasFeatureTF()) this->Beep();
break;
case SYS_COMMAND_MACHINE_NUMBER: // deprecated and not used
// setMachineNumber(data);
break;
case SYS_COMMAND_LED_CONTROL:
this->privateConfigLED(data);
break;
case SYS_COMMAND_HALT:
this->halt();
break;
case SYS_COMMAND_REBOOT:
this->reboot();
break;
default:
qDebug() << "ATB_system::executeSystemCommand(): unknown command: " << cmd;
break;
}
}
/*****************************************************************************
* stubs for display control
*
* this methodes should later be scriptable an call corresponding methodes
* in DisplayControl via DBus.
*/
void ATB_system::DimLow() { return; }
void ATB_system::DimHigh()
{
//if (config->hasFeatureDC())
// this->dc->DimHigh();
}
//void ATB_system::Dim(quint8 value) { if (config->hasFeatureDC()) this->dc->Dim((uchar)value); }
void ATB_system::DimStart() { return; }
void ATB_system::DimStop() { return; }
/*****************************************************************************
*/
void ATB_system::Beep() {
qDebug() << "ATB_system::Beep(): now i should make a beep!";
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QTimer::singleShot (BEEPTIMEOUT, this, SLOT(BeepStop()) );
*(this->tf_gpio_outstream) << config->getTouchFeedbackOnValue();
this->tf_gpio_outstream->flush();
#endif
}
void ATB_system::BeepStop() {
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
*(this->tf_gpio_outstream) << config->getTouchFeedbackOffValue();
this->tf_gpio_outstream->flush();
#endif
}
int ATB_system::init_touch_feedback() {
#if defined (ARCH_PTU2)
QString GPIODirName("/sys/class/gpio/");
QString directionFileName;
QString valueFileName;
// # echo 129 > /sys/class/gpio/export
QFile file("/sys/class/gpio/export");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << config->getTouchFeedbackGPIO();
file.close();
// check, if gpio-dir was created
GPIODirName.append("gpio");
GPIODirName.append(config->getTouchFeedbackGPIO());
QFileInfo fileinfo1(GPIODirName);
if (! fileinfo1.isDir() ) {
qDebug() << "ATB_system::init_touch_feedback(): \"" << GPIODirName << "\" is not a directory";
config->unsetFeatureTF();
return -1;
}
directionFileName = GPIODirName + "/direction";
QFileInfo fileinfo2(directionFileName);
if (! fileinfo2.isWritable() ) {
qDebug() << "ATB_system::init_touch_feedback(): \"" << directionFileName << "\" is not writable";
config->unsetFeatureTF();
return -1;
}
// # echo out > /sys/class/gpio/gpio129/direction
QFile directionfile(directionFileName);
directionfile.open(QIODevice::ReadWrite | QIODevice::Text);
QTextStream out2(&directionfile);
out2 << "out";
out2.flush();
// re-read 'direction' for confirmation
// -> the following is disabled because this sometimes failed
//QTextStream in(&directionfile);
//QString line = in.readLine();
//if (line != "out") {
// qDebug() << "ATB_system::init_touch_feedback(): re-read directionfile failed";
// config->unsetFeatureTF();
// return -1;
//}
directionfile.close();
// open gpio file
valueFileName = GPIODirName + "/value";
this->tf_gpio = new QFile(valueFileName);
this->tf_gpio->open(QIODevice::WriteOnly);
this->tf_gpio_outstream = new QTextStream(this->tf_gpio);
qDebug() << "ATB_system::init_touch_feedback(): GPIODirName = \"" << GPIODirName << "\"";
qDebug() << "ATB_system::init_touch_feedback(): valueFileName = \"" << valueFileName << "\"";
#elif defined (ARCH_PTU4)
QString sysfs_buzzer("/sys/class/leds/Buzzer/brightness");
this->tf_gpio = new QFile(sysfs_buzzer);
tf_gpio->open(QIODevice::WriteOnly);
this->tf_gpio_outstream = new QTextStream(this->tf_gpio);
#endif
return 1;
}
/********************************************************************************
* set date/time
*
* Datestring format: YYYY-MM-DD hh:mm[:ss]
* This is a format that is accepted both by busybox-date (e.g. PTU2) and by
* coreutils-date.
*
* example:
* /bin/date -s "2015-08-05 17:55:00"
*
*/
void ATB_system::setDateTime(const QString & dateTimeString)
{
QString datetimeCMD = "/bin/date -s " + dateTimeString;
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QProcess::startDetached(datetimeCMD);
// the following does not work on PTU2:
//QProcess::startDetached ("/sbin/hwclock -w");
#endif
}
/********************************************************************************
* static functions to write single values to files.
*
* Used e.g. to store some machine specific settings like customer number or machine
* number in filesystem.
*
* This data should be updated rarely and the calling function must keep this in mind!
*
* Note: QFile::open() creates a file, if it is not existing.
*/
quint8 ATB_system::setPSAConfigInt(const QString &filename, quint16 iValue)
{
return setPSAConfigString(filename, QString::number(iValue));
}
quint8 ATB_system::setPSAConfigString(const QString & filename, const QString & sValue)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(filename);
#else
QFile file(QDir::homePath() + filename);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::setPSAConfigString() cannot open file: " << filename;
qDebug() << " file.errorString() = " << file.errorString();
return 0;
}
qDebug() << "ATB_system::setPSAConfigString() write file: " << filename;
QTextStream out(&file);
out << sValue;
out.flush();
file.close();
return 1;
}
quint16 ATB_system::readPSAConfigInt(const QString & filename)
{
bool ok;
quint16 result = (quint16)readPSAConfigString(filename).toInt(&ok);
if (!ok) {
result = 0;
}
return result;
}
QString ATB_system::readPSAConfigString(const QString & filename)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFileInfo fileinfo(filename);
#else
QFileInfo fileinfo(QDir::homePath() + filename);
#endif
if (! fileinfo.isReadable() ) {
qDebug() << "ATB_system::readPSAConfigString(): \"" << filename << "\" is not readable";
return 0;
}
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(filename);
#else
QFile file(QDir::homePath() + filename);
#endif
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "ATB_system::readPSAConfigString() cannot open file: " << filename;
return 0;
}
QTextStream in(&file);
QString stringValue = in.readLine(100);
qDebug() << "ATB_system::readPSAConfigString() stringValue = " << stringValue;
file.close();
return stringValue;
}
/********************************************************************************
* LED control interface
*
*/
void ATB_system::onConfigLED(LED_NAME LED, LED_TRIGGER trigger, quint16 delayOn, quint16 delayOff)
{
QString LEDPath = "/sys/class/leds/";
QString LEDName = "";
QString LEDtrigger = "";
// DEBUG
// ////////
switch (LED) {
#if defined (ARCH_PTU2)
case ATB_LED1: LEDName.append("atb_led1"); break;
case ATB_LED2: LEDName.append("atb_led2"); break;
case ATB_LED3: LEDName.append("atb_led3"); break;
case ATB_LED4: LEDName.append("atb_led4"); break;
#elif defined (ARCH_PTU4)
case ATB_LED1: LEDName.append("D504"); break;
case ATB_LED2: LEDName.append("D503"); break;
case ATB_LED3: LEDName.append("D502"); break;
case ATB_LED4: LEDName.append("D501"); break;
#endif
default: return;
}
switch (trigger) {
case LED_TRIGGER_NONE: LEDtrigger.append("none"); break;
case LED_TRIGGER_TIMER: LEDtrigger.append("timer"); break;
#if defined (ARCH_PTU2)
case LED_TRIGGER_DEFAULT_ON: LEDtrigger.append("default-on"); break;
#elif defined (ARCH_PTU4)
/* note: ptu4 leds currently do not support 'default-on' trigger
* workaround is to set delay_off to '0'
*/
case LED_TRIGGER_DEFAULT_ON: LEDtrigger.append("timer");
trigger = LED_TRIGGER_TIMER;
delayOn = 1;
delayOff = 0;
break;
#endif
default: return;
}
QString filename = LEDPath + LEDName + "/trigger";
// set trigger
this->privateSetLEDTrigger(filename, LEDtrigger);
// set delays for trigger 'timer'
if (trigger == LED_TRIGGER_TIMER) {
// set delay on
if (delayOn != 0) {
filename = LEDPath + LEDName + "/delay_on";
this->privateSetLEDDelayOn(filename, QString::number(delayOn));
}
// set delay off
if (delayOff != 0) {
filename = LEDPath + LEDName + "/delay_off";
this->privateSetLEDDelayOn(filename, QString::number(delayOff));
}
}
return;
}
/*****************************************************************************
* wrapper function for LED control.
*
* TODO: Test, check: plausibillity, cmd.lenght(), type casts to LED_NAME, LED_TRIGGER
*/
void ATB_system::privateConfigLED(const QByteArray & cmd)
{
quint16 delayOn = (quint8)cmd.at(3) + ((quint16)(cmd.at(2) << 8));
quint16 delayOff = (quint8)cmd.at(5) + ((quint16)(cmd.at(4) << 8));
this->onConfigLED((LED_NAME)cmd.at(0), (LED_TRIGGER)cmd.at(1), delayOn, delayOff);
}
void ATB_system::privateSetLEDTrigger(const QString & led, const QString & trigger)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << trigger;
out.flush();
file.close();
}
void ATB_system::privateSetLEDDelayOn(const QString & led, const QString & delayOn)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << delayOn;
out.flush();
file.close();
}
void ATB_system::privateSetLEDDelayOff(const QString & led, const QString & delayOff)
{
#if defined (ARCH_PTU2) || defined (ARCH_PTU4)
QFile file(led);
#else
QFile file(QDir::homePath() + led);
#endif
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::onConfigLED() cannot open file: " << led;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
qDebug() << "ATB_system::onConfigLED() write file: " << led;
QTextStream out(&file);
out << delayOff;
out.flush();
file.close();
}
/*****************************************************************************
* functions for switching blink button on/off
* This is only available on PTU4
*/
void ATB_system::switchBlinkButtonOn()
{
this->privateSwitchBlinkButton(true);
}
void ATB_system::switchBlinkButtonOff()
{
this->privateSwitchBlinkButton(false);
}
void ATB_system::privateSwitchBlinkButton(bool on)
{
#if defined (ARCH_PTU2)
#elif defined (ARCH_PTU4)
QString BlinkLED("/sys/class/leds/TIMER_RESET/brightness");
QFile file(BlinkLED);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ATB_system::privateSwitchBlinkButton() cannot open file: " << BlinkLED;
qDebug() << " file.errorString() = " << file.errorString();
return;
}
QTextStream out(&file);
if (on) { out << "0"; }
else { out << "1"; }
out.flush();
file.close();
#else
Q_UNUSED(on)
#endif
}
/*****************************************************************************
* halt system.
*
*/
void ATB_system::halt()
{
QProcess::startDetached("/sbin/halt");
}
/*****************************************************************************
* reboot system.
*
*/
void ATB_system::reboot()
{
QProcess::startDetached("/sbin/reboot");
}
/*****************************************************************************
* functions for wake vmc
* This is only available on PTU4
*/
void ATB_system::onWakeVMC()
{
#if defined (ARCH_PTU2)
#elif defined (ARCH_PTU4)
if (config->hasFeatureDBusSuspendControl()) {
this->dbus_wakeSystem();
}
#endif
}
/*****************************************************************************
* get event device name by a type:
*
* e.g. type is TOUCHSCREEN:
* getEventDeviceName(TOUCHSCREEN) returns "/dev/input/event0"
*
*/
QString ATB_system::getEventDeviceName(DEVICE_TYPE type)
{
QString procDevices = "/proc/bus/input/devices";
QFile inFile(procDevices);
if (!inFile.open(QFile::ReadOnly)) {
qCritical() << "ATB_system::getEventDeviceName() ERROR open()" << procDevices;
return "";
}
QTextStream textInStream(&inFile);
QString line;
QString N_RegExp;
QString DeviceTypeName;
int lineCounter = 0;
bool typeFound = false;
QString H_RegExp = "^H: Handlers"; // H: Handlers=kbd event2
QString eventDeviceName = "";
QString eventPart;
QStringList devNames;
QString DeviceNamePattern;
//PTU4 Touchscreen N: Name="atmel_mxt_ts T100 touchscreen"
//PTU4 GPIO kys N: Name="gpio_keys.6"
//RFID Reader, Stronglink SL040 N: Name="StrongLink USB CardReader"
//2D Scanner, Datalogig DSE0420 N: Name="Datalogic ADC Inc. Handheld Barcode Scanner" VID: 05f9, PID:4005
//2D Scanner, Datalogig DSM0400 N: Name="Datalogic Handheld Barcode Scanner" VID: 05f9, PID:4005
//2D Scanner, Honeywell N56000 N: Name="Honeywell Imaging & Mobility N5600"
//2D Scanner, Newland FM3080 N: Name="Newland Auto-ID NLS-FM3080V2-20 USB POS KBW" VID: 1eab, PID:0022
//2D Scanner, Opticon MDI-4000 N: Name="Opticon Opticon USB Barcode Reader"
//USB Mouse N: Name="Logitech USB-PS/2 Optical Mouse"
/* Datalogic DSE0420
I: Bus=0003 Vendor=05f9 Product=4005 Version=0110
N: Name="Datalogic ADC Inc. Handheld Barcode Scanner"
P: Phys=usb-700000.ehci-2.3/input2
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.3/1-2.3:1.2/input/input14
U: Uniq=S/N G16C15795
H: Handlers=kbd event3
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
/* Datalogic DSM04XX
I: Bus=0003 Vendor=05f9 Product=4005 Version=0110
N: Name="Datalogic Handheld Barcode Scanner"
P: Phys=usb-700000.ehci-2.3/input0
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.3/1-2.3:1.0/input/input15
U: Uniq=S/N G21FA0180
H: Handlers=kbd event3
B: PROP=0
B: EV=120013
B: KEY=e080ffdf 1cfffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
/*
I: Bus=0003 Vendor=1eab Product=0022 Version=0110
N: Name="Newland Auto-ID NLS-FM3080V2-20 USB POS KBW"
P: Phys=usb-700000.ehci-2.2/input0
S: Sysfs=/devices/ahb.0/700000.ehci/usb1/1-2/1-2.2/1-2.2:1.0/input/input6
U: Uniq=FM3080V2-20-BH00017
H: Handlers=kbd event2
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
*/
switch (type) {
case EVENT_DEVICE_BARCODEREADER:
N_RegExp = "^N: Name=.+(Barcode|Honeywell Imaging|Newland Auto).+";
DeviceTypeName = "1D/2D-Scanner";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_TOUCHSCREEN:
N_RegExp = "^N: Name=.+touch.+";
DeviceTypeName = "Touchscreen";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_GPIO_KEYBOARD:
N_RegExp = "^N: Name=.+gpio.+";
DeviceTypeName = "gpio-keys";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_KEYBOARD:
N_RegExp = "^N: Name=.+touch.+";
DeviceTypeName = "keyboard";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_RFIDREADER:
N_RegExp = "^N: Name=.+Card.+";
DeviceTypeName = "card reader";
DeviceNamePattern = "event";
break;
case EVENT_DEVICE_USBMOUSE:
N_RegExp = "^N: Name=.+USB.+Mouse.+";
DeviceTypeName = "USB Mouse";
DeviceNamePattern = "mouse";
break;
}
qDebug() << "ATB_system::getEventDeviceName() N_RegExp = " << N_RegExp;
do {
line = textInStream.readLine();
// DEBUG
//qDebug() << " " << line;
// find "N:"-line:
if (line.contains(QRegExp(N_RegExp))) {
typeFound = true;
lineCounter = 0;
qDebug() << "ATB_system::getEventDeviceName() found N_RegExp = " << N_RegExp;
}
if (typeFound) {
// found "N:"-line, now search for "H:"-line;
// the corresponding "H:"-line should be within the next 7 following text lines.
// example lines:
// - "H: Handlers=event0 mouse0" -> for touchscreen on PTU4
// - "H: Handlers=event3 mouse1" -> for USB mouse on PTU4
lineCounter++;
if ( (lineCounter<=7) && (line.contains(QRegExp(H_RegExp))) ) {
eventPart = line.split("=", QString::SkipEmptyParts).takeLast();
devNames = eventPart.split(" ", QString::SkipEmptyParts);
for (int i=0; i<devNames.size(); i++ ) {
if (devNames.at(i).contains(DeviceNamePattern)) {
eventDeviceName = "/dev/input/" + devNames.at(i);
qDebug() << "ATB_system::getEventDeviceName() found device = " << eventDeviceName;
}
}
}
if ( lineCounter>7 ) {
lineCounter=0;
typeFound = false;
}
}
} while (!line.isNull());
if (eventDeviceName == "") {
qCritical() << "ATB_system::getEventDeviceName(): could not detect input event device type " << DeviceTypeName;
}
return eventDeviceName;
}