#pragma once #ifdef LAUNCHPAD #include #include #include "driver_include.hpp" #pragma pack(push,1) struct __attribute__((aligned(1), packed)) _launchpadMessage { uint8_t status; uint8_t cmd; uint8_t key; uint8_t currentScene; uint8_t lpNumber; uint8_t shiftDown; short param0; short param1; #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" void FromMessage(LaunchpadMessage *src) { status = (uint8_t)src->status; cmd = (uint8_t)src->cmd; key = (uint8_t)src->key; currentScene = (uint8_t)src->currentScene; lpNumber = (uint8_t)src->lpNumber; shiftDown = (uint8_t)(src->shiftDown ? 1 : 0); param0 = src->param0; param1 = src->param1; } LaunchpadMessage Reconstruct() { LaunchpadMessage rv; rv.status = (LaunchpadKeyStatus)status; rv.cmd = (LaunchpadCommand)cmd; rv.key = (LaunchpadKey)key; rv.currentScene = (LaunchpadScene)currentScene; rv.lpNumber = lpNumber; rv.shiftDown = shiftDown != 0; rv.param0 = param0; rv.param1 = param1; return rv; } }; #pragma pack(pop) class communicator { private: class circBuffer { private: uint8_t * mapAccess; int rdPtr; int WR_PTR_POS; int P0; int PN; public: static int bufferOverhead() { return sizeof(uint32_t); } // n. di bytes EXTRA richiesti per la gestione del buffer circolare void Clear() { rdPtr = wrPtr_get(); } circBuffer(int bufferSize, void *acc, int offset) { WR_PTR_POS = offset; P0 = WR_PTR_POS + bufferOverhead(); // posizione 0 memoria effettiva (dove salvare e leggere i dati, dopo i primi 8 bytes riservati ai puntatori rd/wr) PN = P0 + bufferSize - bufferOverhead(); mapAccess = (uint8_t*)acc; Clear(); } ~circBuffer() { mapAccess = NULL; } void WriteChunk(LaunchpadMessage *_msg) { #ifdef DEBUG info("send message %i; tx size is %i", _msg->cmd, sizeof(_launchpadMessage)); #endif _launchpadMessage msg; msg.FromMessage(_msg); uint8_t *ptr = (uint8_t *)&msg; int cur_wrPtr = wrPtr_get(); for(int k = 0; k < (int)sizeof(_launchpadMessage); k++) cur_wrPtr = Put(*ptr++, cur_wrPtr); wrPtr_set(cur_wrPtr); // finalizza IN SOLIDO il chunk appena letto } LaunchpadMessage ReadChunk() { if(data_available()) { _launchpadMessage msg; uint8_t *p = (uint8_t *)&msg; for(int k = 0; k < (int)sizeof(_launchpadMessage); k++) *p++ = Get(); return msg.Reconstruct(); } LaunchpadMessage rv; rv.status = LaunchpadKeyStatus::keyNone; return rv; } private: int wrPtr_get() { return *((uint32_t *)(mapAccess + WR_PTR_POS)); } void wrPtr_set(uint32_t v) { uint32_t *ptr = (uint32_t *)(mapAccess + WR_PTR_POS); *ptr = v; } bool data_available() { return rdPtr != wrPtr_get(); } int incPtr(int ptr) { if(++ptr >= PN) ptr = P0; return ptr; } int Put(uint8_t b, int ptr) { mapAccess[ptr] = b; return incPtr(ptr); } uint8_t Get() { int trdPtr = rdPtr; uint8_t rv = mapAccess[trdPtr]; rdPtr = incPtr(trdPtr); return rv; } }; public: communicator() { hMapFile = NULL; syncMutex = NULL; pmemory = NULL; pCommonMemory = NULL; rdBuffer = wrBuffer = NULL; } ~communicator() { deinit(); } void clear() { if(pmemory != NULL) { rdBuffer->Clear(); wrBuffer->Clear(); } } bool Connected() { return pmemory != NULL; } bool Open() { if(pmemory == NULL) { try { init(); } catch(_exception ex) { deinit(); } } return pmemory != NULL; } void Write(LaunchpadMessage msg) { if(checkServer()) { if(WaitForSingleObject(syncMutex, 500) == WAIT_OBJECT_0) { wrBuffer->WriteChunk(&msg); ReleaseMutex(syncMutex); } } } LaunchpadMessage Read() { if(checkServer()) return rdBuffer->ReadChunk(); LaunchpadMessage rv; rv.status = LaunchpadKeyStatus::keyNone; return rv; } private: void *pmemory; uint32_t *pCommonMemory; circBuffer *rdBuffer; circBuffer *wrBuffer; HANDLE hMapFile; HANDLE syncMutex; void init() { const int BUFFER_SIZE = 100; const int SERVERUP_POS = 0; // (Int32) : indica se il server e' up o down const int START_OF_BUFFER = SERVERUP_POS + sizeof(uint32_t); // prima locazione di memoria utile per il buffer circolare int b_l = BUFFER_SIZE * sizeof(_launchpadMessage) + circBuffer::bufferOverhead(); #ifdef DEBUG info("Open file mapping"); #endif hMapFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, TRUE, "launchpad_mem"); if(hMapFile != NULL) { #ifdef DEBUG info("file mapping opened"); #endif void *p = MapViewOfFile(hMapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 2 * b_l + sizeof(uint32_t)/*flag SERVER_POS*/); #ifdef DEBUG info("MapViewOfFile success"); #endif syncMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "launchpad_mtx"); #ifdef DEBUG if(syncMutex != NULL) info("mutex OK"); else info("*** no mutexxxxxxx!!!!!! ****"); #endif wrBuffer = new circBuffer(b_l, p, START_OF_BUFFER); rdBuffer = new circBuffer(b_l, p, START_OF_BUFFER + b_l); #ifdef DEBUG info("circBuffer created"); #endif pmemory = p; pCommonMemory = (uint32_t *)p; #ifdef DEBUG info("Opened OK"); #endif } } bool checkServer() { bool rv = false; if(pCommonMemory != NULL) { uint32_t server = *pCommonMemory; if(server == 0) { #ifdef DEBUG info("*** connection lost ***"); #endif deinit(); } else rv = true; } return rv; } void deinit() { void *p = pmemory; pmemory = NULL; pCommonMemory = NULL; if(p != NULL) UnmapViewOfFile(p); if(hMapFile != NULL) CloseHandle(hMapFile); hMapFile = NULL; if(rdBuffer != NULL) { delete rdBuffer; rdBuffer = NULL; } if(wrBuffer != NULL) { delete wrBuffer; wrBuffer = NULL; } if(syncMutex != NULL) { CloseHandle(syncMutex); syncMutex = NULL; } } }; #endif