merge fix #721 PR (sync 7.0.2.rc) to developer (#739)

* merge fix from #721 PR (sync) 7.0.2.rc -> developer
* row and column for jungfrau mixed up

* multi module jungfrau sync must do slaves first then master for start acquisition and send software trigger, and master first and then slaves for stopacquisition

* non blocking to slaves first and only then blocking/nonblocking to the master for sending software trigger(jungfrau multi mod sync)

* fixed get/set timing jungfrau when sync enabled, getsync during blocking acquire (for trigger or stop) will get stuck as it should ask the stop server

* switching between 1 and 2 interfaces did not set gui/client zmq port properly. Resulted in dummy streaming forever. fixed

* formatting, refactoring: const & for positions, multi mod M3 stop first master first

* adding missing cstdint for gcc 13

* Refactoring handle sync out, handling synchronization also for softwaretrigger for m3, for start/sync/stop for g2/g1

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>

* fixed row and col for moench 2 interfaces

* fix moench getTiming and also allow moench to handle sync

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
This commit is contained in:
maliakal_d 2023-05-08 15:58:19 +02:00 committed by GitHub
parent 14ec4cf1da
commit e757e25fa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 183 additions and 103 deletions

View File

@ -39,7 +39,7 @@ This document describes the differences between v7.x.x and v7.0.0
Eiger 7.0.0 Eiger 7.0.0
Jungfrau 7.0.0 Jungfrau 7.0.2
Mythen3 7.0.0 Mythen3 7.0.0
Gotthard2 7.0.0 Gotthard2 7.0.0
Gotthard 7.0.0 Gotthard 7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServerv7.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServerv7.0.0

View File

@ -1449,7 +1449,7 @@ void setTiming(enum timingMode arg) {
} }
enum timingMode getTiming() { enum timingMode getTiming() {
if (bus_r(EXT_SIGNAL_REG) == EXT_SIGNAL_MSK) if ((bus_r(EXT_SIGNAL_REG) & EXT_SIGNAL_MSK) >> EXT_SIGNAL_OFST)
return TRIGGER_EXPOSURE; return TRIGGER_EXPOSURE;
return AUTO_TIMING; return AUTO_TIMING;
} }
@ -1736,40 +1736,40 @@ int setDetectorPosition(int pos[]) {
detPos[2] = outerPos[X]; detPos[2] = outerPos[X];
detPos[3] = outerPos[Y]; detPos[3] = outerPos[Y];
// row // row [Y]
// outer // outer
uint32_t addr = COORD_ROW_REG; uint32_t addr = COORD_ROW_REG;
bus_w(addr, bus_w(addr,
(bus_r(addr) & ~COORD_ROW_OUTER_MSK) | (bus_r(addr) & ~COORD_ROW_OUTER_MSK) |
((outerPos[X] << COORD_ROW_OUTER_OFST) & COORD_ROW_OUTER_MSK)); ((outerPos[Y] << COORD_ROW_OUTER_OFST) & COORD_ROW_OUTER_MSK));
if (((bus_r(addr) & COORD_ROW_OUTER_MSK) >> COORD_ROW_OUTER_OFST) != if (((bus_r(addr) & COORD_ROW_OUTER_MSK) >> COORD_ROW_OUTER_OFST) !=
outerPos[X])
ret = FAIL;
// inner
bus_w(addr,
(bus_r(addr) & ~COORD_ROW_INNER_MSK) |
((innerPos[X] << COORD_ROW_INNER_OFST) & COORD_ROW_INNER_MSK));
if (((bus_r(addr) & COORD_ROW_INNER_MSK) >> COORD_ROW_INNER_OFST) !=
innerPos[X])
ret = FAIL;
// col
// outer
addr = COORD_COL_REG;
bus_w(addr,
(bus_r(addr) & ~COORD_COL_OUTER_MSK) |
((outerPos[Y] << COORD_COL_OUTER_OFST) & COORD_COL_OUTER_MSK));
if (((bus_r(addr) & COORD_COL_OUTER_MSK) >> COORD_COL_OUTER_OFST) !=
outerPos[Y]) outerPos[Y])
ret = FAIL; ret = FAIL;
// inner // inner
bus_w(addr, bus_w(addr,
(bus_r(addr) & ~COORD_COL_INNER_MSK) | (bus_r(addr) & ~COORD_ROW_INNER_MSK) |
((innerPos[Y] << COORD_COL_INNER_OFST) & COORD_COL_INNER_MSK)); ((innerPos[Y] << COORD_ROW_INNER_OFST) & COORD_ROW_INNER_MSK));
if (((bus_r(addr) & COORD_COL_INNER_MSK) >> COORD_COL_INNER_OFST) != if (((bus_r(addr) & COORD_ROW_INNER_MSK) >> COORD_ROW_INNER_OFST) !=
innerPos[Y]) innerPos[Y])
ret = FAIL; ret = FAIL;
// col [X]
// outer
addr = COORD_COL_REG;
bus_w(addr,
(bus_r(addr) & ~COORD_COL_OUTER_MSK) |
((outerPos[X] << COORD_COL_OUTER_OFST) & COORD_COL_OUTER_MSK));
if (((bus_r(addr) & COORD_COL_OUTER_MSK) >> COORD_COL_OUTER_OFST) !=
outerPos[X])
ret = FAIL;
// inner
bus_w(addr,
(bus_r(addr) & ~COORD_COL_INNER_MSK) |
((innerPos[X] << COORD_COL_INNER_OFST) & COORD_COL_INNER_MSK));
if (((bus_r(addr) & COORD_COL_INNER_MSK) >> COORD_COL_INNER_OFST) !=
innerPos[X])
ret = FAIL;
if (ret == OK) { if (ret == OK) {
if (getNumberofUDPInterfaces() == 1) { if (getNumberofUDPInterfaces() == 1) {
LOG(logINFOBLUE, ("Position set to [%d, %d] #(col, row)\n", LOG(logINFOBLUE, ("Position set to [%d, %d] #(col, row)\n",

View File

@ -1345,7 +1345,7 @@ void setTiming(enum timingMode arg) {
} }
enum timingMode getTiming() { enum timingMode getTiming() {
if (bus_r(EXT_SIGNAL_REG) == EXT_SIGNAL_MSK) if ((bus_r(EXT_SIGNAL_REG) & EXT_SIGNAL_MSK) >> EXT_SIGNAL_OFST)
return TRIGGER_EXPOSURE; return TRIGGER_EXPOSURE;
return AUTO_TIMING; return AUTO_TIMING;
} }
@ -1632,40 +1632,40 @@ int setDetectorPosition(int pos[]) {
detPos[2] = outerPos[X]; detPos[2] = outerPos[X];
detPos[3] = outerPos[Y]; detPos[3] = outerPos[Y];
// row // row [Y]
// outer // outer
uint32_t addr = COORD_ROW_REG; uint32_t addr = COORD_ROW_REG;
bus_w(addr, bus_w(addr,
(bus_r(addr) & ~COORD_ROW_OUTER_MSK) | (bus_r(addr) & ~COORD_ROW_OUTER_MSK) |
((outerPos[X] << COORD_ROW_OUTER_OFST) & COORD_ROW_OUTER_MSK)); ((outerPos[Y] << COORD_ROW_OUTER_OFST) & COORD_ROW_OUTER_MSK));
if (((bus_r(addr) & COORD_ROW_OUTER_MSK) >> COORD_ROW_OUTER_OFST) != if (((bus_r(addr) & COORD_ROW_OUTER_MSK) >> COORD_ROW_OUTER_OFST) !=
outerPos[X])
ret = FAIL;
// inner
bus_w(addr,
(bus_r(addr) & ~COORD_ROW_INNER_MSK) |
((innerPos[X] << COORD_ROW_INNER_OFST) & COORD_ROW_INNER_MSK));
if (((bus_r(addr) & COORD_ROW_INNER_MSK) >> COORD_ROW_INNER_OFST) !=
innerPos[X])
ret = FAIL;
// col
// outer
addr = COORD_COL_REG;
bus_w(addr,
(bus_r(addr) & ~COORD_COL_OUTER_MSK) |
((outerPos[Y] << COORD_COL_OUTER_OFST) & COORD_COL_OUTER_MSK));
if (((bus_r(addr) & COORD_COL_OUTER_MSK) >> COORD_COL_OUTER_OFST) !=
outerPos[Y]) outerPos[Y])
ret = FAIL; ret = FAIL;
// inner // inner
bus_w(addr, bus_w(addr,
(bus_r(addr) & ~COORD_COL_INNER_MSK) | (bus_r(addr) & ~COORD_ROW_INNER_MSK) |
((innerPos[Y] << COORD_COL_INNER_OFST) & COORD_COL_INNER_MSK)); ((innerPos[Y] << COORD_ROW_INNER_OFST) & COORD_ROW_INNER_MSK));
if (((bus_r(addr) & COORD_COL_INNER_MSK) >> COORD_COL_INNER_OFST) != if (((bus_r(addr) & COORD_ROW_INNER_MSK) >> COORD_ROW_INNER_OFST) !=
innerPos[Y]) innerPos[Y])
ret = FAIL; ret = FAIL;
// col [X]
// outer
addr = COORD_COL_REG;
bus_w(addr,
(bus_r(addr) & ~COORD_COL_OUTER_MSK) |
((outerPos[X] << COORD_COL_OUTER_OFST) & COORD_COL_OUTER_MSK));
if (((bus_r(addr) & COORD_COL_OUTER_MSK) >> COORD_COL_OUTER_OFST) !=
outerPos[X])
ret = FAIL;
// inner
bus_w(addr,
(bus_r(addr) & ~COORD_COL_INNER_MSK) |
((innerPos[X] << COORD_COL_INNER_OFST) & COORD_COL_INNER_MSK));
if (((bus_r(addr) & COORD_COL_INNER_MSK) >> COORD_COL_INNER_OFST) !=
innerPos[X])
ret = FAIL;
if (ret == OK) { if (ret == OK) {
if (getNumberofUDPInterfaces() == 1) { if (getNumberofUDPInterfaces() == 1) {
LOG(logINFOBLUE, ("Position set to [%d, %d] #(col, row)\n", LOG(logINFOBLUE, ("Position set to [%d, %d] #(col, row)\n",

View File

@ -857,7 +857,7 @@ void Detector::stopDetector(Positions pos) {
throw RuntimeError( throw RuntimeError(
"Could not stop detector. Returned error status."); "Could not stop detector. Returned error status.");
} }
pimpl->Parallel(&Module::stopAcquisition, pos); pimpl->stopDetector(pos);
status = getDetectorStatus().squash(defs::runStatus::RUNNING); status = getDetectorStatus().squash(defs::runStatus::RUNNING);
++retries; ++retries;
@ -916,7 +916,7 @@ void Detector::setNextFrameNumber(uint64_t value, Positions pos) {
} }
void Detector::sendSoftwareTrigger(const bool block, Positions pos) { void Detector::sendSoftwareTrigger(const bool block, Positions pos) {
pimpl->Parallel(&Module::sendSoftwareTrigger, pos, block); pimpl->sendSoftwareTrigger(block, pos);
} }
Result<defs::scanParameters> Detector::getScan(Positions pos) const { Result<defs::scanParameters> Detector::getScan(Positions pos) const {
@ -954,18 +954,23 @@ void Detector::setNumberofUDPInterfaces(int n, Positions pos) {
} }
void Detector::setNumberofUDPInterfaces_(int n, Positions pos) { void Detector::setNumberofUDPInterfaces_(int n, Positions pos) {
if (!size()) {
throw RuntimeError("No modules added.");
}
bool previouslyClientStreaming = pimpl->getDataStreamingToClient(); bool previouslyClientStreaming = pimpl->getDataStreamingToClient();
int clientStartingPort = getClientZmqPort({0}).squash(0);
bool useReceiver = getUseReceiverFlag().squash(false); bool useReceiver = getUseReceiverFlag().squash(false);
bool previouslyReceiverStreaming = false; bool previouslyReceiverStreaming = false;
int startingPort = 0; int rxStartingPort = 0;
if (useReceiver) { if (useReceiver) {
previouslyReceiverStreaming = getRxZmqDataStream(pos).squash(true); previouslyReceiverStreaming = getRxZmqDataStream(pos).squash(true);
startingPort = getRxZmqPort({0}).squash(0); rxStartingPort = getRxZmqPort({0}).squash(0);
} }
pimpl->Parallel(&Module::setNumberofUDPInterfaces, pos, n); pimpl->Parallel(&Module::setNumberofUDPInterfaces, pos, n);
// ensure receiver zmq socket ports are multiplied by 2 (2 interfaces) // ensure receiver zmq socket ports are multiplied by 2 (2 interfaces)
if (getUseReceiverFlag().squash(false) && size()) { setClientZmqPort(clientStartingPort, -1);
setRxZmqPort(startingPort, -1); if (getUseReceiverFlag().squash(false)) {
setRxZmqPort(rxStartingPort, -1);
} }
// redo the zmq sockets if enabled // redo the zmq sockets if enabled
if (previouslyClientStreaming) { if (previouslyClientStreaming) {

View File

@ -755,7 +755,7 @@ void DetectorImpl::readFrameFromReceiver() {
int nDetActualPixelsY = nDetPixelsY; int nDetActualPixelsY = nDetPixelsY;
if (gapPixels) { if (gapPixels) {
int n = InsertGapPixels(multiframe.get(), multigappixels, int n = insertGapPixels(multiframe.get(), multigappixels,
quadEnable, dynamicRange, quadEnable, dynamicRange,
nDetActualPixelsX, nDetActualPixelsY); nDetActualPixelsX, nDetActualPixelsY);
callbackImage = multigappixels; callbackImage = multigappixels;
@ -794,7 +794,7 @@ void DetectorImpl::readFrameFromReceiver() {
delete[] multigappixels; delete[] multigappixels;
} }
int DetectorImpl::InsertGapPixels(char *image, char *&gpImage, bool quadEnable, int DetectorImpl::insertGapPixels(char *image, char *&gpImage, bool quadEnable,
int dr, int &nPixelsx, int &nPixelsy) { int dr, int &nPixelsx, int &nPixelsy) {
LOG(logDEBUG) << "Insert Gap pixels:" LOG(logDEBUG) << "Insert Gap pixels:"
@ -1242,43 +1242,105 @@ int DetectorImpl::acquire() {
return OK; return OK;
} }
void DetectorImpl::startAcquisition(bool blocking, std::vector<int> positions) { bool DetectorImpl::handleSynchronization(Positions pos) {
// handle Mythen3 synchronization bool handleSync = false;
if (shm()->detType == defs::MYTHEN3 && size() > 1) { // multi module m3 or multi module sync enabled jungfrau
std::vector<int> master; if (size() > 1) {
std::vector<int> slaves; switch (shm()->detType) {
if (positions.empty() || case defs::MYTHEN3:
(positions.size() == 1 && positions[0] == -1)) { case defs::GOTTHARD2:
positions.resize(modules.size()); case defs::GOTTHARD:
std::iota(begin(positions), end(positions), 0); handleSync = true;
} break;
// could be all slaves in positions case defs::JUNGFRAU:
slaves.reserve(positions.size()); case defs::MOENCH:
auto is_master = Parallel(&Module::isMaster, positions); if (Parallel(&Module::getSynchronizationFromStopServer, pos)
for (size_t i : positions) { .tsquash("Inconsistent synchronization among modules")) {
if (is_master[i]) handleSync = true;
master.push_back(i); }
else break;
slaves.push_back(i); default:
break;
} }
}
return handleSync;
}
void DetectorImpl::getMasterSlaveList(std::vector<int> positions,
std::vector<int> &masters,
std::vector<int> &slaves) {
// expand positions list
if (positions.empty() || (positions.size() == 1 && positions[0] == -1)) {
positions.resize(modules.size());
std::iota(begin(positions), end(positions), 0);
}
// could be all slaves in positions
slaves.reserve(positions.size());
auto is_master = Parallel(&Module::isMaster, positions);
for (size_t i : positions) {
if (is_master[i])
masters.push_back(i);
else
slaves.push_back(i);
}
}
void DetectorImpl::startAcquisition(const bool blocking, Positions pos) {
// slaves first
if (handleSynchronization(pos)) {
std::vector<int> masters;
std::vector<int> slaves;
getMasterSlaveList(pos, masters, slaves);
if (!slaves.empty()) { if (!slaves.empty()) {
Parallel(&Module::startAcquisition, slaves); Parallel(&Module::startAcquisition, slaves);
} }
if (!master.empty()) { if (!masters.empty()) {
if (blocking) { Parallel((blocking ? &Module::startAndReadAll
Parallel(&Module::startAndReadAll, master); : &Module::startAcquisition),
} else { pos);
Parallel(&Module::startAcquisition, master);
}
}
} else {
if (blocking) {
Parallel(&Module::startAndReadAll, positions);
} else {
Parallel(&Module::startAcquisition, positions);
} }
} }
// all in parallel
else {
Parallel(
(blocking ? &Module::startAndReadAll : &Module::startAcquisition),
pos);
}
}
void DetectorImpl::sendSoftwareTrigger(const bool block, Positions pos) {
// slaves first
if (handleSynchronization(pos)) {
std::vector<int> masters;
std::vector<int> slaves;
getMasterSlaveList(pos, masters, slaves);
if (!slaves.empty())
Parallel(&Module::sendSoftwareTrigger, slaves, false);
if (!masters.empty())
Parallel(&Module::sendSoftwareTrigger, masters, block);
}
// all in parallel
else {
Parallel(&Module::sendSoftwareTrigger, pos, block);
}
}
void DetectorImpl::stopDetector(Positions pos) {
// masters first
if (handleSynchronization(pos)) {
std::vector<int> masters;
std::vector<int> slaves;
getMasterSlaveList(pos, masters, slaves);
if (!masters.empty())
Parallel(&Module::stopAcquisition, masters);
if (!slaves.empty())
Parallel(&Module::stopAcquisition, slaves);
}
// all in parallel
else {
Parallel(&Module::stopAcquisition, pos);
}
} }
void DetectorImpl::printProgress(double progress) { void DetectorImpl::printProgress(double progress) {
@ -1383,7 +1445,8 @@ std::vector<char> DetectorImpl::readProgrammingFile(const std::string &fname) {
default: default:
throw RuntimeError( throw RuntimeError(
"Unknown detector type. Did the 'hostname' command execute " "Unknown detector type. Did the 'hostname' command execute "
"successfully? Or use update mode in the detector server side."); "successfully? Or use update mode in the detector server "
"side.");
} }
LOG(logINFO) << "This can take awhile. Please be patient."; LOG(logINFO) << "This can take awhile. Please be patient.";
@ -1411,10 +1474,9 @@ std::vector<char> DetectorImpl::readProgrammingFile(const std::string &fname) {
int dst = mkstemp(destfname); // create temporary file and open it in r/w int dst = mkstemp(destfname); // create temporary file and open it in r/w
if (dst == -1) { if (dst == -1) {
fclose(src); fclose(src);
throw RuntimeError( throw RuntimeError(std::string("Could not create destination file "
std::string( "in /tmp for programming: ") +
"Could not create destination file in /tmp for programming: ") + destfname);
destfname);
} }
// convert src to dst rawbin // convert src to dst rawbin
@ -1466,8 +1528,8 @@ std::vector<char> DetectorImpl::readProgrammingFile(const std::string &fname) {
} }
// validate pof: read less than footer offset // validate pof: read less than footer offset
if (isPof && dstFilePos < pofFooterOfst) { if (isPof && dstFilePos < pofFooterOfst) {
throw RuntimeError( throw RuntimeError("Could not convert programming file. EOF "
"Could not convert programming file. EOF before end of flash"); "before end of flash");
} }
} }
if (fclose(src) != 0) { if (fclose(src) != 0) {

View File

@ -278,7 +278,13 @@ class DetectorImpl : public virtual slsDetectorDefs {
int acquire(); int acquire();
/** also takes care of master and slave for multi module mythen */ /** also takes care of master and slave for multi module mythen */
void startAcquisition(bool blocking, std::vector<int> positions); void startAcquisition(const bool blocking, Positions pos);
/** also takes care of master and slave for multi module mythen */
void sendSoftwareTrigger(const bool block, Positions pos);
/** also takes care of master and slave for multi module mythen */
void stopDetector(Positions pos);
/** /**
* Combines data from all readouts and gives it to the gui * Combines data from all readouts and gives it to the gui
@ -379,9 +385,14 @@ class DetectorImpl : public virtual slsDetectorDefs {
* @param nPixelsy number of pixels in Y axis (updated) * @param nPixelsy number of pixels in Y axis (updated)
* @returns total data bytes for updated image * @returns total data bytes for updated image
*/ */
int InsertGapPixels(char *image, char *&gpImage, bool quadEnable, int dr, int insertGapPixels(char *image, char *&gpImage, bool quadEnable, int dr,
int &nPixelsx, int &nPixelsy); int &nPixelsx, int &nPixelsy);
bool handleSynchronization(Positions pos);
void getMasterSlaveList(std::vector<int> positions,
std::vector<int> &masters,
std::vector<int> &slaves);
void printProgress(double progress); void printProgress(double progress);
void startProcessingThread(bool receiver); void startProcessingThread(bool receiver);

View File

@ -544,8 +544,15 @@ bool Module::getSynchronization() const {
return sendToDetector<int>(F_GET_SYNCHRONIZATION); return sendToDetector<int>(F_GET_SYNCHRONIZATION);
} }
bool Module::getSynchronizationFromStopServer() const {
return sendToDetectorStop<int>(F_GET_SYNCHRONIZATION);
}
void Module::setSynchronization(const bool value) { void Module::setSynchronization(const bool value) {
sendToDetector(F_SET_SYNCHRONIZATION, static_cast<int>(value), nullptr); sendToDetector(F_SET_SYNCHRONIZATION, static_cast<int>(value), nullptr);
// to deal with virtual servers as well
// (get sync from stop server during blocking acquisition)
sendToDetectorStop(F_SET_SYNCHRONIZATION, static_cast<int>(value), nullptr);
} }
std::vector<int> Module::getBadChannels() const { std::vector<int> Module::getBadChannels() const {

View File

@ -130,6 +130,7 @@ class Module : public virtual slsDetectorDefs {
bool isMaster() const; bool isMaster() const;
void setMaster(const bool master); void setMaster(const bool master);
bool getSynchronization() const; bool getSynchronization() const;
bool getSynchronizationFromStopServer() const;
void setSynchronization(const bool value); void setSynchronization(const bool value);
std::vector<int> getBadChannels() const; std::vector<int> getBadChannels() const;
void setBadChannels(std::vector<int> list); void setBadChannels(std::vector<int> list);

View File

@ -2,6 +2,7 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package // Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once #pragma once
#include <array> #include <array>
#include <cstdint>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <cstdint> #include <cstdint>

View File

@ -5,9 +5,9 @@
#define APICTB "developer 0x230224" #define APICTB "developer 0x230224"
#define APIGOTTHARD "developer 0x230224" #define APIGOTTHARD "developer 0x230224"
#define APIGOTTHARD2 "developer 0x230224" #define APIGOTTHARD2 "developer 0x230224"
#define APIJUNGFRAU "developer 0x230224"
#define APIMYTHEN3 "developer 0x230224" #define APIMYTHEN3 "developer 0x230224"
#define APIMOENCH "developer 0x230224"
#define APILIB "developer 0x230224" #define APILIB "developer 0x230224"
#define APIRECEIVER "developer 0x230224" #define APIRECEIVER "developer 0x230224"
#define APIEIGER "developer 0x230224" #define APIEIGER "developer 0x230224"
#define APIJUNGFRAU "developer 0x230508"
#define APIMOENCH "developer 0x230508"