Kaynağa Gözat

Tiva-SPI-Info implementiert.

Rind 4 yıl önce
ebeveyn
işleme
25de449d3b

+ 6 - 1
README.md

@@ -1,7 +1,7 @@
 ## libgfaipc  
 
 ***Version:***  
-libgfaipc.so.1.3.0  
+libgfaipc.so.1.4.0  
 
 ***SO-Name:***  
 libgfaipc.so.1
@@ -29,6 +29,7 @@ gfa/shm.h, gfa/mutex.h, gfa/sema.h, gfa/procmem.h, gfa/thread.h
 * Funktionen zur Ermittlung von CPU-Informationen
 * Funktionen zur Überwachung von Hotplug-Events von Mass Storage Devices (z. B. USB oder MMC)
 * Funktionen zur Ermittlung von MySql-Server Statusinformationen. 
+* Funktionen zur Ermittlung von Tiva-Informationen über SysFs (/sys/gfa/tiva)
 * Exportiert C++ Synchronisationsobjekte wie Mutex und Semaphore.
 * Hilfsfunktionen zur UUID-Manipulation
 
@@ -45,6 +46,9 @@ gfa/shm.h, gfa/mutex.h, gfa/sema.h, gfa/procmem.h, gfa/thread.h
 * **1.3.0**<br>
 	App-Control-Funktion zum Beenden eines Prozesses im Zombie-State hinzugefügt.
 
+* **1.4.0**<br>
+	App-Control-Funktion Ermittlung von Tiva-Informationen über SysFs hinzugefügt. Benötigt gfaspi.ko.
+
 ---
 
 ## gfasysinfo
@@ -56,3 +60,4 @@ Versorgt die Bibliothek mit Informationen über CPU-Auslastung, Speichernutzung,
 * libgfaipc
 * libgfasitarautils
 * libudev
+* gfaspi.ko (Tiva-Info)

+ 1 - 1
gfaipc.pro

@@ -1,5 +1,5 @@
 TEMPLATE = lib
-VERSION = 1.3
+VERSION = 1.4
 CONFIG -= qt app_bundle
 CONFIG += c++11 shared thread
 

+ 2 - 0
gfasysinfo/gfasysinfo.pro

@@ -31,6 +31,7 @@ SOURCES += \
     src/mysqlinfo.cpp \
     src/mysqlwrap.cpp \
     src/procfile.cpp \
+    src/spiinfo.cpp \
     src/stgdevinfo.cpp
 
 HEADERS += \
@@ -38,4 +39,5 @@ HEADERS += \
     src/mysqlinfo.h \
     src/mysqlwrap.h \
     src/procfile.h \
+    src/spiinfo.h \
     src/stgdevinfo.h

+ 16 - 1
gfasysinfo/src/main.cpp

@@ -22,6 +22,7 @@
 #include <gfa/gfaipc.h>
 #include "stgdevinfo.h"
 #include "mysqlinfo.h"
+#include "spiinfo.h"
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -709,6 +710,7 @@ int main(int argc, char *argv[])
 	std::string sDbUser, sDbPass;
 	CMySqlInfo mySqlInfo;
 	CStgDevInfo stgDevInfo;
+	CSpiInfo spiInfo;
 	bool bStateTransition;
 
 	/////////////////////////////////////////////////////////////////////////
@@ -779,12 +781,16 @@ int main(int argc, char *argv[])
 		
 		CStgDevInfo::EXEC_PARAMS step = {hAC};
 		stgDevInfo.Create(&step);
+		
+		CSpiInfo::EXEC_PARAMS spep = {hAC};
+		spiInfo.Create(&spep);
 
 		g_fZombie = false;
 		g_fRun = true;
 		::GfaIpcAppCtrlSetState(hAC, GIAS_Running);
 		mySqlInfo.Signal(CMySqlInfo::S_UpdateAll);
 		stgDevInfo.Signal(CStgDevInfo::S_Init);
+		spiInfo.Signal(CSpiInfo::S_Init);
 	}
 	while(false);
 
@@ -820,11 +826,13 @@ int main(int argc, char *argv[])
 				{
 					mySqlInfo.Signal(CMySqlInfo::S_Pause);
 					stgDevInfo.Signal(CStgDevInfo::S_Pause);
+					spiInfo.Signal(CSpiInfo::S_Pause);
 				}
 				else
 				{
 					mySqlInfo.Signal(CMySqlInfo::S_Resume);
 					stgDevInfo.Signal(CStgDevInfo::S_Resume);
+					spiInfo.Signal(CSpiInfo::S_Resume);
 				}
 			}
 
@@ -838,6 +846,10 @@ int main(int argc, char *argv[])
 
 			ct.Sleep1();
 		}
+		else
+		{
+			::GfaIpcAppCtrlSetState(hAC, GIAS_Terminating);
+		}
 	}
 
 	/////////////////////////////////////////////////////////////////////////
@@ -846,9 +858,11 @@ int main(int argc, char *argv[])
 
 	mySqlInfo.Signal(CMySqlInfo::S_Terminate);
 	stgDevInfo.Signal(CStgDevInfo::S_Terminate);
+	spiInfo.Signal(CSpiInfo::S_Terminate);
 
 	mySqlInfo.Join(NULL);
 	stgDevInfo.Join(NULL);
+	spiInfo.Join(NULL);
 	
 	if(g_fZombie)
 	{
@@ -856,11 +870,12 @@ int main(int argc, char *argv[])
 			::GfaIpcAppCtrlSetState(hAC, GIAS_Zombie);
 		TRACE("%-8s: State: %s\n", "Me", ::GfaIpcAppCtrlGetStateText(GIAS_Zombie));
 		pause();
+		if(hAC)
+			::GfaIpcAppCtrlSetState(hAC, GIAS_Terminating);
 	}
 
 	if(hAC)
 	{
-		::GfaIpcAppCtrlSetState(hAC, GIAS_Terminating);
 		::GfaIpcAppCtrlReleaseSysInfo(hAC);
 		::GfaIpcAppCtrlRelease(hAC);
 	}

+ 6 - 4
gfasysinfo/src/mysqlinfo.cpp

@@ -2,6 +2,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
 #include <iostream>
 #include <fstream>
 #include <sstream>
@@ -504,6 +506,7 @@ CMySqlInfo::CMySqlInfo(void) : m_bPaused(false)
 void* CMySqlInfo::ThreadRoutine(void *pParam)
 {
 	LPEXEC_PARAMS pep = (LPEXEC_PARAMS)pParam;
+	TRACE("Enter CMySqlInfo::ThreadRoutine: TID: %ld\n", syscall(SYS_gettid));
 
 	if(pep)
 	{
@@ -515,7 +518,6 @@ void* CMySqlInfo::ThreadRoutine(void *pParam)
 		{
 			if((nRet = WaitSignalTimeout(_QUICK_UPDATE_INTERVAL_MS * 1000, &nSig)) == ETIMEDOUT)
 			{
-//				TRACE("%s wait timeout.\n", __FUNCTION__);
 				if(!m_bPaused)
 				{
 					::_GetDbInfo(pep->sUser, pep->sPass, sdb);
@@ -524,7 +526,7 @@ void* CMySqlInfo::ThreadRoutine(void *pParam)
 			}
 			else if(!nRet) // signal received
 			{
-				TRACE("%s signal %d received.\n", __FUNCTION__, nSig);
+				TRACE("%s signal %d received.\n", "CMySqlInfo::ThreadRoutine", nSig);
 
 				switch(nSig)
 				{
@@ -553,11 +555,11 @@ void* CMySqlInfo::ThreadRoutine(void *pParam)
 			}
 			else
 			{
-//				TRACE("%s error %d.\n", __FUNCTION__, nRet);
+				TRACE("%s error %d.\n", "CMySqlInfo::ThreadRoutine", nRet);
 			}
 		}
 	}
 
-	TRACE("%s exit.\n", __FUNCTION__);
+	TRACE("%s exit.\n", "CMySqlInfo::ThreadRoutine");
 	return NULL;
 }

+ 285 - 0
gfasysinfo/src/spiinfo.cpp

@@ -0,0 +1,285 @@
+#include <stdio.h>
+#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 "spiinfo.h"
+
+#define _SDA_UPDATE_INTERVAL_MS					200ULL
+#define _SYS_FS_TIVA_ROOT						"/sys/gfa/tiva"
+#define _SYS_FS_TIVA_ADC						"/sys/gfa/tiva/adc"
+#define _SYS_FS_TIVA_ADC_BIN					"/sys/gfa/tiva/adc/AdcBin"
+#define _SYS_FS_TIVA_UPTIME						"/sys/gfa/tiva/uptime"
+#define _SYS_FS_TIVA_FIRMWARE_VER				"/sys/gfa/tiva/firmware/version"
+
+/////////////////////////////////////////////////////////////////////////////
+
+#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))
+
+/////////////////////////////////////////////////////////////////////////////
+
+CSpiInfo::CSpiInfo(void) : m_bPaused(false), m_bStateTransition(false)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int CSpiInfo::ReadADC(int fd, GFA_SYSINFO_SPI &spi) const
+{
+	int nRet;
+	TIVA_ADC tadc;
+
+	if((nRet = read(fd, &tadc, sizeof(tadc))) == sizeof(tadc))
+	{
+		spi.adc.fVoltagePowerSupply		= (float)tadc.UVers / 100.0 + 0.4;
+		spi.adc.fVoltageBackupBattery	= (float)tadc.UBatV3 / 100.0;
+		spi.adc.fVoltageSys				= (float)tadc.UV5Vsys / 100.0;
+		spi.adc.fVoltageBattery			= (float)tadc.UV3V6Bat / 100.0;
+		spi.adc.fTemperatureBoard		= (float)tadc.Temp / 10.0;
+		spi.adc.fTemperatureTiva		= 147.5 - 187.5 * (float)tadc.TempTIVA / 4096.0;
+		nRet = lseek(fd, 0, SEEK_SET);
+	}
+
+	return nRet;
+}
+
+int CSpiInfo::ReadTivaUptime(int fd, GFA_SYSINFO_SPI &spi) const
+{
+	int nRet;
+	char szUptime[64];
+
+	if((nRet = read(fd, szUptime, sizeof(szUptime) - 1)) > 0)
+	{
+		szUptime[nRet] = 0;
+		spi.nUptimeSec = (unsigned int)((unsigned long long)atoll(szUptime) / 1000ULL);
+		nRet = lseek(fd, 0, SEEK_SET);
+	}
+
+	return nRet;
+}
+
+int CSpiInfo::ReadFirmwareVersion(int fd, GFA_SYSINFO_SPI &spi) const
+{
+	int nRet, hw, sw;
+	char szVersion[64];
+
+	if((nRet = read(fd, szVersion, sizeof(szVersion) - 1)) > 0)
+	{
+		szVersion[nRet] = 0;
+		if(sscanf(szVersion, "%d %d", &hw, &sw) == 2)
+		{
+			spi.nHwVersion = hw;
+			spi.nSwVersion = sw;
+		}
+		nRet = lseek(fd, 0, SEEK_SET);
+	}
+
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void* CSpiInfo::ThreadRoutine(void *pParam)
+{
+	LPEXEC_PARAMS pep = (LPEXEC_PARAMS)pParam;
+    TRACE("Enter CSpiInfo::ThreadRoutine: TID: %ld\n", syscall(SYS_gettid));
+
+	if(pep)
+	{
+		unsigned long long nWaitIntvUs = 0;
+		bool bInitializing = true, bRun = false;
+		int nRet, nSig;
+		GFA_SYSINFO_SPI spi;
+		pollfd pfd[3];
+
+		do
+		{
+			do
+			{
+				for(size_t i = 0; i < _countof(pfd); ++i)
+				{
+					pfd[i].fd = -1;
+				}
+
+				if((pfd[0].fd = open(_SYS_FS_TIVA_ADC_BIN, O_RDONLY, 0)) < 0)
+					break;
+				pfd[0].events = POLLPRI;
+				pfd[0].revents = 0;
+
+				if((pfd[1].fd = open(_SYS_FS_TIVA_UPTIME, O_RDONLY, 0)) < 0)
+					break;
+				pfd[1].events = POLLPRI;
+				pfd[1].revents = 0;
+
+				if((pfd[2].fd = open(_SYS_FS_TIVA_FIRMWARE_VER, O_RDONLY, 0)) < 0)
+					break;
+				pfd[2].events = POLLPRI;
+				pfd[2].revents = 0;
+
+				bInitializing = false;
+				bRun = true;
+			}
+			while(false);
+
+			while(bRun)
+			{
+				nWaitIntvUs = m_bPaused ? (_SDA_UPDATE_INTERVAL_MS * 1000ULL) : 0;
+
+				if((nRet = WaitSignalTimeout(nWaitIntvUs, &nSig)) == ETIMEDOUT)
+				{
+					if(!m_bPaused)
+					{
+						while((nRet = poll(pfd, _countof(pfd), _SDA_UPDATE_INTERVAL_MS)) > 0)
+						{
+							if(pfd[0].revents & POLLPRI)
+							{
+								if(!(nRet = ReadADC(pfd[0].fd, spi)))
+								{
+									::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
+								}
+								else if(nRet < 0)
+								{
+									TRACE("ReadADC failed: %s\n", strerror(errno));
+									bInitializing = true;
+									bRun = false;
+									break;
+								}
+							}
+
+							if(pfd[1].revents & POLLPRI)
+							{
+								if(!(nRet = ReadTivaUptime(pfd[1].fd, spi)))
+								{
+									::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
+								}
+								else if(nRet < 0)
+								{
+									TRACE("ReadTivaUptime failed: %s\n", strerror(errno));
+									bInitializing = true;
+									bRun = false;
+									break;
+								}
+							}
+
+							if(pfd[2].revents & POLLPRI)
+							{
+								if(!(nRet = ReadFirmwareVersion(pfd[2].fd, spi)))
+								{
+									::GfaIpcAppCtrlUpdateSpiInfo(pep->hAC, spi, false);
+								}
+								else if(nRet < 0)
+								{
+									TRACE("ReadFirmwareVersion failed: %s\n", strerror(errno));
+									bInitializing = true;
+									bRun = false;
+									break;
+								}
+							}
+						}
+
+						if(nRet < 0)
+						{
+							TRACE("poll failed: %s\n", strerror(errno));
+							bInitializing = true;
+							bRun = false;
+							break;
+						}
+					}
+
+					m_bStateTransition = false;
+				}
+				else if(!nRet) // signal received
+				{
+					TRACE("%s signal %d received.\n", "CSpiInfo::ThreadRoutine", nSig);
+
+					switch(nSig)
+					{
+					case S_Init:
+						break;
+					case S_Update:
+						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);
+			}
+
+			if(!bRun && bInitializing)
+			{
+				if(!WaitSignalTimeout(_SDA_UPDATE_INTERVAL_MS * 5000ULL, &nSig))
+				{
+					TRACE("%s signal %d received.\n", "CSpiInfo::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", "CSpiInfo::ThreadRoutine");
+	return NULL;
+}

+ 51 - 0
gfasysinfo/src/spiinfo.h

@@ -0,0 +1,51 @@
+// spiinfo.h :
+//
+
+#if !defined(AGD_SPIINFO_H__412BF45C_AE50_4A79_984F_2AE495DF86B1__INCLUDED_)
+#define AGD_SPIINFO_H__412BF45C_AE50_4A79_984F_2AE495DF86B1__INCLUDED_
+
+#include <gfa/gfaipc.h>
+#include <gfa/ipcpriv.h>
+#include <gfa/thread.h>
+#include "../../../gfaspidrv/gfaspi.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// spiinfo.h - Declarations:
+
+class CSpiInfo : public CThread
+{
+public:
+	typedef enum
+	{
+		S_Init = 1,
+		S_Update,
+		S_Pause,
+		S_Resume,
+		S_Terminate
+	}Signals;
+
+public:
+	typedef struct _EXEC_PARAMS
+	{
+		HAPPCTRL hAC;
+	}EXEC_PARAMS, *LPEXEC_PARAMS;
+	typedef const EXEC_PARAMS *LPCEXEC_PARAMS;
+
+public:
+	CSpiInfo(void);
+
+protected:
+	virtual void* ThreadRoutine(void *pParam);
+
+private:
+	int ReadADC(int fd, GFA_SYSINFO_SPI &spi) const;
+	int ReadTivaUptime(int fd, GFA_SYSINFO_SPI &spi) const;
+	int ReadFirmwareVersion(int fd, GFA_SYSINFO_SPI &spi) const;
+
+private:
+	bool m_bPaused;
+	bool m_bStateTransition;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_SPIINFO_H__412BF45C_AE50_4A79_984F_2AE495DF86B1__INCLUDED_)

+ 13 - 6
gfasysinfo/src/stgdevinfo.cpp

@@ -12,6 +12,7 @@
 #include <sys/statvfs.h>
 #include <sys/statfs.h>
 #include <sys/types.h>
+#include <sys/syscall.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
@@ -41,6 +42,8 @@
 #define _INTERNAL_EMMC_PART1				"mmcblk1p1"
 #define _INTERNAL_EMMC_PART2				"mmcblk1p2"
 
+#define _POLL_INTERVAL_MS					500
+
 /////////////////////////////////////////////////////////////////////////////
 
 typedef std::map<std::string, std::string>	MountMap;
@@ -644,6 +647,7 @@ CStgDevInfo::CStgDevInfo(void) : m_bPaused(false), m_bStateTransition(false)
 void* CStgDevInfo::ThreadRoutine(void *pParam)
 {
 	LPEXEC_PARAMS pep = (LPEXEC_PARAMS)pParam;
+	TRACE("Enter CStgDevInfo::ThreadRoutine: TID: %ld\n", syscall(SYS_gettid));
 
 	if(pep)
 	{
@@ -656,7 +660,8 @@ void* CStgDevInfo::ThreadRoutine(void *pParam)
 		MountMap mm;
 		pollfd pfd[2];
 		memset(&pfd, 0, sizeof(pfd));
-		
+		unsigned long long nWaitIntvUs = 0;
+
 		do
 		{
 		    if(!(pUdev = ::udev_new()))
@@ -701,13 +706,15 @@ void* CStgDevInfo::ThreadRoutine(void *pParam)
 
 		while(bRun)
 		{
-			if((nRet = WaitSignalTimeout(0, &nSig)) == ETIMEDOUT)
+			nWaitIntvUs = m_bPaused ? (_POLL_INTERVAL_MS * 1000ULL) : 0;
+
+			if((nRet = WaitSignalTimeout(nWaitIntvUs, &nSig)) == ETIMEDOUT)
 			{
 				_ClearMapChanges(sdm);
 
 				if(!m_bPaused)
 				{
-					while(poll(pfd, 2, 500) > 0)
+					while(poll(pfd, 2, _POLL_INTERVAL_MS) > 0)
 					{
 						_UpdateMountMap(mm);
 
@@ -743,7 +750,7 @@ void* CStgDevInfo::ThreadRoutine(void *pParam)
 			}
 			else if(!nRet) // signal received
 			{
-				TRACE("%s signal %d received.\n", __FUNCTION__, nSig);
+				TRACE("%s signal %d received.\n", "CStgDevInfo::ThreadRoutine", nSig);
 
 				switch(nSig)
 				{
@@ -770,7 +777,7 @@ void* CStgDevInfo::ThreadRoutine(void *pParam)
 			}
 			else
 			{
-				TRACE("%s error %d.\n", __FUNCTION__, nRet);
+				TRACE("%s error %d.\n", "CStgDevInfo::ThreadRoutine", nRet);
 			}
 		}
 
@@ -784,6 +791,6 @@ void* CStgDevInfo::ThreadRoutine(void *pParam)
 			::udev_unref(pUdev);
 	}
 
-	TRACE("%s exit.\n", __FUNCTION__);
+	TRACE("%s exit.\n", "CStgDevInfo::ThreadRoutine");
 	return NULL;
 }

+ 120 - 69
src/appctrl.cpp

@@ -51,7 +51,7 @@ static const char *g_pszKnownAppNames[] =
 	"GEB"
 };
 
-static_assert(_countof(g_pszKnownAppNames) == (GAI_Last - GAI_Remanent), "enum GfaAppIndex does not meet string representation!");
+static_assert(_countof(g_pszKnownAppNames) == (GAI_Last - GAI_Remanent), "enum GfaAppIndex does not meet string representation in g_pszKnownAppNames!");
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
@@ -495,7 +495,7 @@ const char* CAppCtrl::GetStateText(GfaIpcAppStates state)
 		"Zombie",
 		"Invalid"
 	};
-	
+
 	static_assert(_countof(pszStateNames) == (GIAS_Invalid - GIAS_StateNotRunning + 1), "enum GfaIpcAppStates does not meet string representation!");
 
 	if(state >= GIAS_StateNotRunning && state <= GIAS_Invalid)
@@ -1007,92 +1007,93 @@ bool CAppCtrl::UpdateStorageDeviceMap(const GFA_SYSINFO_STORAGE_DEVICE_MAP &sdm,
 		{
 			GFA_SYSINFO_DISK &diskShm = sys.sdm.disks[i];
 			_DELETE_DISK(diskShm);
-			sys.nDiskMask &= ~(0x01 << i);
 		}
 
 		for(int i = 0; i < (int)_countof(sys.sdm.parts); ++i)
 		{
 			GFA_SYSINFO_PARTITION &partShm = sys.sdm.parts[i];
 			_DELETE_PARTITION(partShm);
-			sys.nPartMask &= ~(0x01 << i);
 			_DELETE_MOUNTPOINT(partShm);
-			sys.nMountMask &= ~i;
 		}
-		
-		return true;
-	}
 
-	while(nPartChangeMask)
+		sys.nDiskMask = 0;
+		sys.nPartMask = 0;
+		sys.nMountMask = 0;
+	}
+	else
 	{
-		int nPartIdx = ffsll(nPartChangeMask) - 1;
-		uint32_t nPartBit = (0x01 << nPartIdx);
-		nPartChangeMask &= ~nPartBit;
-		
-		if((nPartIdx >= 0) && (nPartIdx < (ssize_t)_countof(sdm.parts)))
+		while(nPartChangeMask)
 		{
-			const GFA_SYSINFO_PARTITION &partNew = sdm.parts[nPartIdx];
-			GFA_SYSINFO_PARTITION &partShm = sys.sdm.parts[nPartIdx];
-			int nDiskIdx = partNew.nDiskIdx;
-			
-			if((nDiskIdx >= 0) && (nDiskIdx < (ssize_t)_countof(sdm.disks)))
+			int nPartIdx = ffsll(nPartChangeMask) - 1;
+			uint32_t nPartBit = (0x01 << nPartIdx);
+			nPartChangeMask &= ~nPartBit;
+
+			if((nPartIdx >= 0) && (nPartIdx < (int)_countof(sdm.parts)))
 			{
-				const GFA_SYSINFO_DISK &diskNew = sdm.disks[nDiskIdx];
-				GFA_SYSINFO_DISK &diskShm = sys.sdm.disks[nDiskIdx];
-				uint32_t nDiskBit = (0x01 << nDiskIdx);
+				const GFA_SYSINFO_PARTITION &partNew = sdm.parts[nPartIdx];
+				GFA_SYSINFO_PARTITION &partShm = sys.sdm.parts[nPartIdx];
+				int nDiskIdx = partNew.nDiskIdx;
 
-				if(diskNew.valid && !diskShm.valid)
-				{
-					// disk add
-					_COPY_DISK(diskShm, diskNew);
-					sys.nDiskMask |= nDiskBit;
-				}
-				else if(!diskNew.valid && diskShm.valid)
+				if((nDiskIdx >= 0) && (nDiskIdx < (ssize_t)_countof(sdm.disks)))
 				{
-					// disk remove
-					_DELETE_DISK(diskShm);
-					sys.nDiskMask &= ~nDiskBit;
-				}
-				else if(diskNew.valid && diskShm.valid)
-				{
-					// disk change
-					_COPY_DISK(diskShm, diskNew);
-					sys.nDiskMask |= nDiskBit;
-				}
+					const GFA_SYSINFO_DISK &diskNew = sdm.disks[nDiskIdx];
+					GFA_SYSINFO_DISK &diskShm = sys.sdm.disks[nDiskIdx];
+					uint32_t nDiskBit = (0x01 << nDiskIdx);
 
-				if(partNew.valid && !partShm.valid)
-				{
-					// partition add
-					_COPY_PARTITION(partShm, partNew);
-					sys.nPartMask |= nPartBit;
-				}
-				else if(!partNew.valid && partShm.valid)
-				{
-					// partition remove
-					_DELETE_PARTITION(partShm);
-					sys.nPartMask &= ~nPartBit;
-				}
+					if(diskNew.valid && !diskShm.valid)
+					{
+						// disk add
+						_COPY_DISK(diskShm, diskNew);
+						sys.nDiskMask |= nDiskBit;
+					}
+					else if(!diskNew.valid && diskShm.valid)
+					{
+						// disk remove
+						_DELETE_DISK(diskShm);
+						sys.nDiskMask &= ~nDiskBit;
+					}
+					else if(diskNew.valid && diskShm.valid)
+					{
+						// disk change
+						_COPY_DISK(diskShm, diskNew);
+						sys.nDiskMask |= nDiskBit;
+					}
 
-				if(partNew.valid && partShm.valid)
-				{
-					// partition change
-					if(*partNew.szMntPoint && !*partShm.szMntPoint)
+					if(partNew.valid && !partShm.valid)
 					{
-						// mountpoint add
-						_COPY_MOUNTPOINT(partShm, partNew);
-						sys.nMountMask |= nPartBit;
+						// partition add
+						_COPY_PARTITION(partShm, partNew);
+						sys.nPartMask |= nPartBit;
 					}
-					else if(!*partNew.szMntPoint && *partShm.szMntPoint)
+					else if(!partNew.valid && partShm.valid)
 					{
-						// mountpoint remove
-						_DELETE_MOUNTPOINT(partShm);
-						sys.nMountMask &= ~nPartBit;
+						// partition remove
+						_DELETE_PARTITION(partShm);
+						sys.nPartMask &= ~nPartBit;
 					}
-					else if(*partNew.szMntPoint && *partShm.szMntPoint)
+
+					if(partNew.valid && partShm.valid)
 					{
-						// mountpoint change
-						if(strcmp(partNew.szMntPoint, partShm.szMntPoint))
+						// partition change
+						if(*partNew.szMntPoint && !*partShm.szMntPoint)
+						{
+							// mountpoint add
 							_COPY_MOUNTPOINT(partShm, partNew);
-						sys.nMountMask |= nPartBit;
+							sys.nMountMask |= nPartBit;
+						}
+						else if(!*partNew.szMntPoint && *partShm.szMntPoint)
+						{
+							// mountpoint remove
+							_DELETE_MOUNTPOINT(partShm);
+							sys.nMountMask &= ~nPartBit;
+						}
+						else if(*partNew.szMntPoint && *partShm.szMntPoint)
+						{
+							// mountpoint change
+							if(strcmp(partNew.szMntPoint, partShm.szMntPoint))
+								_COPY_MOUNTPOINT(partShm, partNew);
+							sys.nMountMask |= nPartBit;
+						}
 					}
 				}
 			}
@@ -1259,16 +1260,15 @@ bool CAppCtrl::UpdateDbInfo(const GFA_SYSINFO_DATABASE &sdb)
 	if(m_hShm)
 	{
 		sysevt_t evt = 0;
-		
 		GFA_SYSINFO_DATABASE &rsdb = m_pAppCtrl->sdb;
 		CAppCtrlShmLocker locker(*this);
-		
+
 		if(rsdb.bIsInit != sdb.bIsInit)
 		{
 			evt |= GFA_APPCTRL_SYSEVENT_MYSQL_INIT_EVT;
 			rsdb.bIsInit = sdb.bIsInit;
 		}
-		
+
 		if(sdb.bIsInit)
 		{
 			if(memcmp(&rsdb.svr, &sdb.svr, sizeof(GFA_MYSQL_SERVER)))
@@ -1312,7 +1312,50 @@ bool CAppCtrl::UpdateDbInfo(const GFA_SYSINFO_DATABASE &sdb)
 				}
 			}
 		}
+
+		return true;
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool CAppCtrl::UpdateSpiInfo(const GFA_SYSINFO_SPI &spi, bool bReset)
+{
+	if(m_hShm)
+	{
+		sysevt_t evt = 0;
+		GFA_SYSINFO_SPI &spiShm = m_pAppCtrl->sys.spi;
+		CAppCtrlShmLocker locker(*this);
 		
+		if(bReset)
+		{
+			memset(&spiShm, 0, sizeof(spiShm));
+			evt |= GFA_APPCTRL_SYSEVENT_TIVA_RST;
+		}
+		else
+		{
+			if(memcmp(&spiShm, &spi, sizeof(spiShm)))
+			{
+				memcpy(&spiShm, &spi, sizeof(spiShm));
+				evt |= GFA_APPCTRL_SYSEVENT_TIVA_EVT;
+			}
+		}
+
+		if(evt)
+		{
+			for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i)
+			{
+				APP_CTRL_PROCESS &proc = m_pAppCtrl->proc[i];
+
+				if(_IS_VALID_APP_ID(proc.nAppID) && (evt & proc.nSysEvtRegistered))
+				{
+					proc.nSysEvtPending |= evt;
+				}
+			}
+		}
+
 		return true;
 	}
 
@@ -1622,6 +1665,14 @@ extern "C" bool GfaIpcAppCtrlUpdateDbInfo(HAPPCTRL hAC, const GFA_SYSINFO_DATABA
 	return false;
 }
 
+extern "C" bool GfaIpcAppCtrlUpdateSpiInfo(HAPPCTRL hAC, const GFA_SYSINFO_SPI &spi, bool bReset)
+{
+	CAppCtrl *p = reinterpret_cast<CAppCtrl*>(hAC);
+	if(p)
+		return p->UpdateSpiInfo(spi, bReset);
+	return false;
+}
+
 extern "C" bool GfaIpcAppCtrlTriggertHeartBeat(HAPPCTRL hAC)
 {
 	CAppCtrl *p = reinterpret_cast<CAppCtrl*>(hAC);

+ 1 - 0
src/appctrl.h

@@ -151,6 +151,7 @@ public:
 	bool UpdateSysInfo(void);
 	bool UpdateStorageDeviceMap(const GFA_SYSINFO_STORAGE_DEVICE_MAP &sdm, bool bReset);
 	bool UpdateDbInfo(const GFA_SYSINFO_DATABASE &sdb);
+	bool UpdateSpiInfo(const GFA_SYSINFO_SPI &spi, bool bReset);
 
 	bool GetSysMem(LPGFA_APPCTRL_SYSMEM psm);
 	bool GetSysSPI(LPGFA_SYSINFO_SPI pspi);

+ 16 - 1
src/gfaipc.h

@@ -188,6 +188,10 @@ typedef enum
 #define GFA_APPCTRL_SYSEVENT_MYSQL_DATABASE_EVT		GFA_APPCTRL_MAKE_SYSEVENT(6)
 #define GFA_APPCTRL_SYSEVENT_ALL_MYSQL				(GFA_APPCTRL_SYSEVENT_MYSQL_INIT_EVT | GFA_APPCTRL_SYSEVENT_MYSQL_SERVER_EVT | GFA_APPCTRL_SYSEVENT_MYSQL_RESOURCE_EVT | GFA_APPCTRL_SYSEVENT_MYSQL_DATABASE_EVT)
 
+#define GFA_APPCTRL_SYSEVENT_TIVA_RST				GFA_APPCTRL_MAKE_SYSEVENT(7)
+#define GFA_APPCTRL_SYSEVENT_TIVA_EVT				GFA_APPCTRL_MAKE_SYSEVENT(8)
+#define GFA_APPCTRL_SYSEVENT_ALL_TIVA				(GFA_APPCTRL_SYSEVENT_TIVA_RST | GFA_APPCTRL_SYSEVENT_TIVA_EVT)
+
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -299,7 +303,7 @@ typedef const GFA_SYSINFO_DISK *LPCGFA_SYSINFO_DISK;
 
 /////////////////////////////////////////////////////////////////////////////
 
-typedef struct _GFA_SYSINFO_SPI
+typedef struct _GFA_SYSINFO_SPI_ADC
 {
 	float fVoltagePowerSupply;
 	float fVoltageBackupBattery;
@@ -307,6 +311,17 @@ typedef struct _GFA_SYSINFO_SPI
 	float fVoltageBattery;
 	float fTemperatureBoard;
 	float fTemperatureTiva;
+}GFA_SYSINFO_SPI_ADC, *LPGFA_SYSINFO_SPI_ADC;
+typedef const GFA_SYSINFO_SPI_ADC *LPCGFA_SYSINFO_SPI_ADC;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_SYSINFO_SPI
+{
+	GFA_SYSINFO_SPI_ADC adc;
+	unsigned int nUptimeSec;
+	int nHwVersion;
+	int nSwVersion;
 }GFA_SYSINFO_SPI, *LPGFA_SYSINFO_SPI;
 typedef const GFA_SYSINFO_SPI *LPCGFA_SYSINFO_SPI;
 

+ 2 - 0
src/ipcpriv.h

@@ -31,6 +31,8 @@ bool GfaIpcAppCtrlUpdateSysInfo(HAPPCTRL hAC);
 bool GfaIpcAppCtrlUpdateStorageDeviceMap(HAPPCTRL hAC, const GFA_SYSINFO_STORAGE_DEVICE_MAP &sdm, bool bReset = false);
 void GfaIpcForceReleaseMutex(void);
 bool GfaIpcAppCtrlUpdateDbInfo(HAPPCTRL hAC, const GFA_SYSINFO_DATABASE &sdb);
+bool GfaIpcAppCtrlUpdateSpiInfo(HAPPCTRL hAC, const GFA_SYSINFO_SPI &spi, bool bReset = false);
+
 bool GfaIpcAppCtrlTriggertHeartBeat(HAPPCTRL hAC);
 
 /////////////////////////////////////////////////////////////////////////////

+ 8 - 7
src/sysinfo.cpp

@@ -135,12 +135,12 @@ bool CSysInfo::GetBootInfo(bool &bootFromEMMC)
 			
 			if(!sPart.compare(_INTERNAL_EMMC_PART12) || sPart.compare(_INTERNAL_EMMC_PART11))
 			{
-				bootFromEMMC = false;
+				bootFromEMMC = true;
 				return true;
 			}
 			else if(!sPart.compare(_INTERNAL_EMMC_PART02) || sPart.compare(_INTERNAL_EMMC_PART01))
 			{
-				bootFromEMMC = true;
+				bootFromEMMC = false;
 				return true;
 			}
 		}
@@ -150,6 +150,7 @@ bool CSysInfo::GetBootInfo(bool &bootFromEMMC)
 }
 
 /////////////////////////////////////////////////////////////////////////////
+// https://github.com/torvalds/linux/blob/master/Documentation/filesystems/proc.rst
 
 bool CSysInfo::Update(void)
 {
@@ -174,27 +175,27 @@ bool CSysInfo::Update(void)
 				
 				if(pszKey && *pszKey && pszValue && *pszValue)
 				{
-					if(!strcmp(pszKey, "MemTotal"))
+					if(!strcmp(pszKey, "MemTotal"))	// Total usable RAM (i.e. physical RAM minus a few reserved bits and the kernel binary code)
 					{
 						_GetSiValueKB(pszValue, m_memInfo.MemTotal);
 						dwFound |= _FLAG_MEM_TOTAL;
 					}
-					else if(!strcmp(pszKey, "MemFree"))
+					else if(!strcmp(pszKey, "MemFree"))	// The amount of physical RAM, in kilobytes, left unused by the system
 					{
 						_GetSiValueKB(pszValue, m_memInfo.MemFree);
 						dwFound |= _FLAG_MEM_FREE;
 					}
-					else if(!strcmp(pszKey, "MemAvailable"))
+					else if(!strcmp(pszKey, "MemAvailable"))	// An estimate of how much memory is available for starting new applications, without swapping
 					{
 						_GetSiValueKB(pszValue, m_memInfo.MemAvailable);
 						dwFound |= _FLAG_MEM_AVAIL;
 					}
-					else if(!strcmp(pszKey, "Buffers"))
+					else if(!strcmp(pszKey, "Buffers"))	// The amount of physical RAM, in kilobytes, used for file buffers
 					{
 						_GetSiValueKB(pszValue, m_memInfo.Buffers);
 						dwFound |= _FLAG_MEM_BUFFERS;
 					}
-					else if(!strcmp(pszKey, "Cached"))
+					else if(!strcmp(pszKey, "Cached"))	// The amount of physical RAM, in kilobytes, used as cache memory
 					{
 						_GetSiValueKB(pszValue, m_memInfo.Cached);
 						dwFound |= _FLAG_MEM_CACHED;

+ 6 - 6
src/sysinfo.h

@@ -20,12 +20,12 @@ typedef const SI_VAL *LPCSI_VAL;
 
 typedef struct _MEM_INFO
 {
-	SI_VAL MemTotal;
-	SI_VAL MemUsed;
-	SI_VAL MemFree;
-	SI_VAL MemAvailable;
-	SI_VAL Buffers;
-	SI_VAL Cached;
+	SI_VAL MemTotal;		// Total usable RAM (i.e. physical RAM minus a few reserved bits and the kernel binary code)
+	SI_VAL MemUsed;			// MemTotal - MemFree
+	SI_VAL MemFree;			// The amount of physical RAM, in kilobytes, left unused by the system
+	SI_VAL MemAvailable;	// An estimate of how much memory is available for starting new applications, without swapping
+	SI_VAL Buffers;			// The amount of physical RAM, in kilobytes, used for file buffers
+	SI_VAL Cached;			// The amount of physical RAM, in kilobytes, used as cache memory
 }MEM_INFO, *LPMEM_INFO;
 typedef const MEM_INFO *LPCMEM_INFO;
 

+ 1 - 0
src/thread.cpp

@@ -133,6 +133,7 @@ int CThread::Signal(int nSig)
 	{
 		m_nCondSig = -1;
 		m_vSigs.push_back(nSig);
+		nRet = 0;
 	}
 	::pthread_mutex_unlock(&m_tMtxCond);
 	return nRet;