|
@@ -0,0 +1,344 @@
|
|
|
|
+#include <stdio.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
+#include <string.h>
|
|
|
|
+#include <sys/statvfs.h>
|
|
|
|
+#include <sys/statfs.h>
|
|
|
|
+#include <sys/types.h>
|
|
|
|
+#include <sys/syscall.h>
|
|
|
|
+#include <fcntl.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
+#include <poll.h>
|
|
|
|
+#include <signal.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include "adcinfo.h"
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+#ifdef _DEBUG
|
|
|
|
+#define TRACE(...) fprintf(stdout, __VA_ARGS__), fflush(stdout)
|
|
|
|
+#else // _DEBUG
|
|
|
|
+#define TRACE(...)
|
|
|
|
+#endif // _DEBUG
|
|
|
|
+
|
|
|
|
+#define UNUSED(v) (void)v
|
|
|
|
+#define _countof(a) (sizeof(a) / sizeof(*a))
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+#define _SDA_POLL_INTERVAL_MS 200ULL
|
|
|
|
+#define _SDA_UPDATE_INTERVAL_US (_SDA_POLL_INTERVAL_MS * 10000ULL)
|
|
|
|
+
|
|
|
|
+#define _ADC_INFO_BASE_DIR "/sys/bus/iio/devices/iio:device0/"
|
|
|
|
+#define _ADC_IN_V0 _ADC_INFO_BASE_DIR "in_voltage0_raw"
|
|
|
|
+#define _ADC_IN_V1 _ADC_INFO_BASE_DIR "in_voltage1_raw"
|
|
|
|
+#define _ADC_IN_V2 _ADC_INFO_BASE_DIR "in_voltage2_raw"
|
|
|
|
+#define _ADC_IN_V3 _ADC_INFO_BASE_DIR "in_voltage3_raw"
|
|
|
|
+#define _ADC_IN_V4 _ADC_INFO_BASE_DIR "in_voltage4_raw"
|
|
|
|
+#define _ADC_IN_V5 _ADC_INFO_BASE_DIR "in_voltage5_raw"
|
|
|
|
+#define _ADC_IN_V6 _ADC_INFO_BASE_DIR "in_voltage6_raw"
|
|
|
|
+#define _ADC_IN_V7 _ADC_INFO_BASE_DIR "in_voltage7_raw"
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+static const int g_kty_tab[][2] =
|
|
|
|
+{
|
|
|
|
+ {199, 1250},
|
|
|
|
+ {351, 1000},
|
|
|
|
+ {643, 750},
|
|
|
|
+ {1185, 500},
|
|
|
|
+ {2048, 250},
|
|
|
|
+ {3025, 0},
|
|
|
|
+ {3705, -250}
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define KTY_TAB_LEN ((int)_countof(g_kty_tab))
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+CAdcInfo::CAdcInfo(void) : m_bPaused(false), m_bStateTransition(false)
|
|
|
|
+{
|
|
|
|
+ char szDisp[256];
|
|
|
|
+ if((m_gtt = ::GfAIpcGetTargetType(szDisp, sizeof(szDisp))) != GTT_NoGfATarget)
|
|
|
|
+ {
|
|
|
|
+ m_strDisplayName = szDisp;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+bool CAdcInfo::TargetHasTiva(void) const
|
|
|
|
+{
|
|
|
|
+ return (m_gtt == GTT_GfATargetWithTiva);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool CAdcInfo::IsGfATarget(void) const
|
|
|
|
+{
|
|
|
|
+ return (m_gtt != GTT_NoGfATarget);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+GfATargetTypes CAdcInfo::GetTargetType(void) const
|
|
|
|
+{
|
|
|
|
+ return m_gtt;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+std::string CAdcInfo::GetDisplayName(void) const
|
|
|
|
+{
|
|
|
|
+ return m_strDisplayName;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+int CAdcInfo::lin_kty(int resistance) const
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if(resistance <= g_kty_tab[0][0])
|
|
|
|
+ return(g_kty_tab[0][1]);
|
|
|
|
+ else if(resistance >= g_kty_tab[KTY_TAB_LEN - 1][0])
|
|
|
|
+ return(g_kty_tab[KTY_TAB_LEN - 1][1]);
|
|
|
|
+
|
|
|
|
+ for(i = 1; i < KTY_TAB_LEN; i++)
|
|
|
|
+ {
|
|
|
|
+ if(g_kty_tab[i][0] >= resistance)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // linear interpolation
|
|
|
|
+ return g_kty_tab[i - 1][1] + // y1 +
|
|
|
|
+ ( // (
|
|
|
|
+ (g_kty_tab[i][1] - g_kty_tab[i - 1][1]) * // (y2 - y1) *
|
|
|
|
+ (resistance - g_kty_tab[i - 1][0]) / // (x - x1) /
|
|
|
|
+ (g_kty_tab[i][0] - g_kty_tab[i - 1][0]) // (x2 - x1)
|
|
|
|
+ ); // )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CAdcInfo::ScaleInt(int in_min, int in_max, int out_min, int out_max, int wert) const
|
|
|
|
+{
|
|
|
|
+ int abc;
|
|
|
|
+ abc = (((long)out_max - (long)out_min) * (long)wert) / ( (long)in_max - (long)in_min);
|
|
|
|
+ abc = abc + out_min;
|
|
|
|
+ return abc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CAdcInfo::ReadIntegerValue(int fd, int &val) const
|
|
|
|
+{
|
|
|
|
+ int nRet;
|
|
|
|
+ char szVal[32];
|
|
|
|
+
|
|
|
|
+ if((nRet = read(fd, szVal, sizeof(szVal) - 1)) > 0)
|
|
|
|
+ {
|
|
|
|
+ szVal[nRet] = '\0';
|
|
|
|
+ val = atoi(szVal);
|
|
|
|
+ nRet = lseek(fd, 0, SEEK_SET);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nRet;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int CAdcInfo::ReadADCValue(int fd, GFA_SYSINFO_SPI &spi, int nWhich) const
|
|
|
|
+{
|
|
|
|
+ int nRet, nVal, nScaled;
|
|
|
|
+
|
|
|
|
+ if((nRet = ReadIntegerValue(fd, nVal)) == 0)
|
|
|
|
+ {
|
|
|
|
+ switch(nWhich)
|
|
|
|
+ {
|
|
|
|
+ case 0:
|
|
|
|
+ nScaled = ScaleInt(0, 4096, 0, 774, nVal); // val / 100.0 (interne 5V Hauptversorgungsspannung skaliert)
|
|
|
|
+ spi.adc.fVoltageSys = (float)nScaled / 100.f; // UV5Vsys
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ nScaled = ScaleInt(0, 4096, 0, 360, nVal); // val / 100.0 (Spannung Pufferbatterie skaliert)
|
|
|
|
+ spi.adc.fVoltageBackupBattery = (float)nScaled / 100.f; // UBatV3
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ nScaled = ScaleInt(0, 4096, 0, 3150, nVal) + 40; // val / 100.0 + 0.4 (Versorgungsspannung skaliert)
|
|
|
|
+ spi.adc.fVoltagePowerSupply = (float)nScaled / 100.f; // UVers
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ nScaled = ScaleInt(0, 4096, 0, 563, nVal);
|
|
|
|
+ spi.adc.fVoltageBattery = (float)nScaled / 100.f; // UV3V6Bat
|
|
|
|
+ break;
|
|
|
|
+ case 4:
|
|
|
|
+ nScaled = lin_kty(nVal); // val / 10.0 (Boardtemperatur linear interpoliert)
|
|
|
|
+ spi.adc.fTemperatureBoard = (float)nScaled / 10.f; // Temp
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ nRet = -1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nRet;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+void* CAdcInfo::ThreadRoutine(void *pParam)
|
|
|
|
+{
|
|
|
|
+ TRACE("Enter CAdcInfo::ThreadRoutine: TID: %ld\n", syscall(SYS_gettid));
|
|
|
|
+ LPEXEC_PARAMS pep = (LPEXEC_PARAMS)pParam;
|
|
|
|
+
|
|
|
|
+ if(pep)
|
|
|
|
+ {
|
|
|
|
+ const char *pszAdcFiles[] = {
|
|
|
|
+ _ADC_IN_V0, // val / 100.0 (interne 5V Hauptversorgungsspannung skaliert)
|
|
|
|
+ _ADC_IN_V1, // val / 100.0 (Spannung Pufferbatterie skaliert)
|
|
|
|
+ _ADC_IN_V2, // val / 100.0 + 0.4 (Versorgungsspannung skaliert)
|
|
|
|
+ _ADC_IN_V3, // val / 100.0 (interne 3V Akkuspannung skaliert)
|
|
|
|
+ _ADC_IN_V4 // val / 10.0 (Boardtemperatur linear interpoliert)
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ bool bInitializing = true, bRun = false;
|
|
|
|
+ int nRet, nSig;
|
|
|
|
+ GFA_SYSINFO_SPI spi;
|
|
|
|
+ pollfd pfd[_countof(pszAdcFiles)];
|
|
|
|
+
|
|
|
|
+ do
|
|
|
|
+ {
|
|
|
|
+ memset(&spi, 0, sizeof(spi));
|
|
|
|
+
|
|
|
|
+ do
|
|
|
|
+ {
|
|
|
|
+ for(size_t i = 0; i < _countof(pfd); ++i)
|
|
|
|
+ {
|
|
|
|
+ if((pfd[i].fd = open(pszAdcFiles[i], O_RDONLY, 0)) < 0)
|
|
|
|
+ break;
|
|
|
|
+ ReadADCValue(pfd[i].fd, spi, i);
|
|
|
|
+ pfd[i].events = POLLIN;
|
|
|
|
+ pfd[i].revents = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
|
|
|
|
+ bInitializing = false;
|
|
|
|
+ bRun = true;
|
|
|
|
+ }
|
|
|
|
+ while(false);
|
|
|
|
+
|
|
|
|
+ while(bRun)
|
|
|
|
+ {
|
|
|
|
+ if((nRet = WaitSignalTimeout(_SDA_UPDATE_INTERVAL_US, &nSig)) == ETIMEDOUT)
|
|
|
|
+ {
|
|
|
|
+ if(!m_bPaused)
|
|
|
|
+ {
|
|
|
|
+ if((nRet = poll(pfd, _countof(pfd), _SDA_POLL_INTERVAL_MS)) > 0)
|
|
|
|
+ {
|
|
|
|
+ int nUpdates = 0;
|
|
|
|
+
|
|
|
|
+ for(int i = 0; i < (int)_countof(pfd); ++i)
|
|
|
|
+ {
|
|
|
|
+ if(pfd[i].revents & POLLIN)
|
|
|
|
+ {
|
|
|
|
+ if(!(nRet = ReadADCValue(pfd[i].fd, spi, i)))
|
|
|
|
+ {
|
|
|
|
+ ++nUpdates;
|
|
|
|
+ }
|
|
|
|
+ else if(nRet < 0)
|
|
|
|
+ {
|
|
|
|
+ TRACE("ReadADCValue from '%s' failed: %s\n", pszAdcFiles[i], strerror(errno));
|
|
|
|
+ bInitializing = true;
|
|
|
|
+ bRun = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(nUpdates > 0)
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
|
|
|
|
+ }
|
|
|
|
+ else if(nRet < 0)
|
|
|
|
+ {
|
|
|
|
+ TRACE("poll failed: %s\n", strerror(errno));
|
|
|
|
+ bInitializing = true;
|
|
|
|
+ bRun = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ m_bStateTransition = false;
|
|
|
|
+ }
|
|
|
|
+ else if(!nRet) // signal received
|
|
|
|
+ {
|
|
|
|
+ TRACE("%s signal %d received.\n", "CAdcInfo::ThreadRoutine", nSig);
|
|
|
|
+
|
|
|
|
+ switch(nSig)
|
|
|
|
+ {
|
|
|
|
+ case S_Init:
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
|
|
|
|
+ break;
|
|
|
|
+ case S_Update:
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
|
|
|
|
+ break;
|
|
|
|
+ case S_Pause:
|
|
|
|
+ m_bStateTransition = !m_bPaused;
|
|
|
|
+ m_bPaused = true;
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, true);
|
|
|
|
+ break;
|
|
|
|
+ case S_Resume:
|
|
|
|
+ m_bStateTransition = m_bPaused;
|
|
|
|
+ m_bPaused = false;
|
|
|
|
+ break;
|
|
|
|
+ case S_Terminate:
|
|
|
|
+ bInitializing = false;
|
|
|
|
+ bRun = false;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ TRACE("WaitSignalTimeout failed: %s\n", strerror(errno));
|
|
|
|
+ bInitializing = true;
|
|
|
|
+ bRun = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, true);
|
|
|
|
+
|
|
|
|
+ for(size_t i = 0; i < _countof(pfd); ++i)
|
|
|
|
+ {
|
|
|
|
+ if(pfd[i].fd >= 0)
|
|
|
|
+ {
|
|
|
|
+ close(pfd[i].fd);
|
|
|
|
+ pfd[i].fd = -1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(!bRun && bInitializing)
|
|
|
|
+ {
|
|
|
|
+ if(!WaitSignalTimeout(_SDA_UPDATE_INTERVAL_US, &nSig))
|
|
|
|
+ {
|
|
|
|
+ TRACE("%s signal %d received.\n", "CAdcInfo::ThreadRoutine", nSig);
|
|
|
|
+
|
|
|
|
+ switch(nSig)
|
|
|
|
+ {
|
|
|
|
+ case S_Init:
|
|
|
|
+ break;
|
|
|
|
+ case S_Update:
|
|
|
|
+ break;
|
|
|
|
+ case S_Pause:
|
|
|
|
+ m_bStateTransition = !m_bPaused;
|
|
|
|
+ m_bPaused = true;
|
|
|
|
+ break;
|
|
|
|
+ case S_Resume:
|
|
|
|
+ m_bStateTransition = m_bPaused;
|
|
|
|
+ m_bPaused = false;
|
|
|
|
+ break;
|
|
|
|
+ case S_Terminate:
|
|
|
|
+ bInitializing = false;
|
|
|
|
+ bRun = false;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ while(bInitializing);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TRACE("%s exit.\n", "CAdcInfo::ThreadRoutine");
|
|
|
|
+ return nullptr;
|
|
|
|
+}
|