extern "C" int
VSCPBlockingReceive(long handle, vscpEvent *pEvent, unsigned long timeout)
{
	int rv = 0;
 
    // Check pointer
    if ( NULL == pEvent) return CANAL_ERROR_PARAMETER;
    
	CRawEthernet *pdrvObj = theApp.getDriverObject(handle);
	if (NULL == pdrvObj) return CANAL_ERROR_MEMORY;
    
    if ( wxSEMA_TIMEOUT == pdrvObj->m_semReceiveQueue.WaitTimeout( timeout ) ) {
        return CANAL_ERROR_TIMEOUT;
    }
    
    //VSCPEVENTLIST_RECEIVE::compatibility_iterator nodeClient;

	pdrvObj->m_mutexReceiveQueue.Lock();
	//nodeClient = pdrvObj->m_receiveQueue.GetFirst();
	//vscpEvent *pLocalEvent = nodeClient->GetData();
    vscpEvent *pLocalEvent = pdrvObj->m_receiveList.front();
    pdrvObj->m_receiveList.pop_front();
	pdrvObj->m_mutexReceiveQueue.Unlock();
    if (NULL == pLocalEvent) return CANAL_ERROR_MEMORY;
    
    copyVSCPEvent( pEvent, pLocalEvent );
    //pdrvObj->m_receiveQueue.DeleteNode(nodeClient);
    deleteVSCPevent( pLocalEvent );
	
	return CANAL_ERROR_SUCCESS;
}
Example #2
0
void *TXWorkerThread::Entry()
{
  eventOutQueue::compatibility_iterator node;
  vscpEvent *pEvent;

  // Must be a valid control object pointer
    if ( NULL == m_pCtrlObject ) return NULL;

    wxCommandEvent eventConnectionLost( wxVSCP_CTRL_LOST_EVENT, m_pCtrlObject->m_windowID );
  
  /// TCP/IP Control
  VscpTcpIf tcpifControl;
  


  
  // Connect to the server with the control interface
  if ( !tcpifControl.doCmdOpen( m_pCtrlObject->m_ifVSCP.m_strHost,
                                m_pCtrlObject->m_ifVSCP.m_port,
                                m_pCtrlObject->m_ifVSCP.m_strUser,
                                m_pCtrlObject->m_ifVSCP.m_strPassword ) ) {
    //::wxGetApp().logMsg ( _("VSCP TX thread - Unable to connect to server."), DAEMON_LOGMSG_CRITICAL );
    m_pCtrlObject->m_errorControl = VSCP_SESSION_ERROR_UNABLE_TO_CONNECT;
        wxPostEvent( m_pCtrlObject->m_pWnd, eventConnectionLost );
    return NULL;
  }
  
  // Get channel ID
  tcpifControl.doCmdGetChannelID( &m_pCtrlObject->m_txChannelID );
  
    while ( !TestDestroy() && !m_pCtrlObject->m_bQuit )
    {
    if ( wxSEMA_TIMEOUT == m_pCtrlObject->m_semOutQue.WaitTimeout( 500 ) ) continue;
    m_pCtrlObject->m_mutexOutQueue.Lock();
    node = m_pCtrlObject->m_outQueue.GetFirst();
    pEvent = node->GetData();
    tcpifControl.doCmdSend( pEvent );
    m_pCtrlObject->m_outQueue.DeleteNode( node );
    deleteVSCPevent( pEvent );
    m_pCtrlObject->m_mutexOutQueue.Unlock();
    } // while
  
  // Close the interface
  tcpifControl.doCmdClose();

    wxPostEvent( m_pCtrlObject->m_pWnd, eventConnectionLost );

    return NULL;

}
Example #3
0
void *UDPReceiveThread::Entry()
{
	unsigned long errorCode = 0;
#ifdef WIN32
	int nLen;
#else
	socklen_t nLen;
#endif
	unsigned char buf[ 1024 ];
	unsigned char *p;

	CLIENTEVENTLIST::compatibility_iterator nodeVSCP;
	vscpEvent *pvscpEvent = NULL;

	// Must be a valid control object pointer
	if (NULL == m_pCtrlObject) return NULL;


	// We need to create a clientobject and add this object to the list
	CClientItem *pClientItem = new CClientItem;
	if (NULL == pClientItem) return NULL;

	// This is an active client
	pClientItem->m_bOpen = true;
	pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_CLIENT_INTERNAL;
	pClientItem->m_strDeviceName = _("Internal UDP Receive Client. Started at ");
	wxDateTime now = wxDateTime::Now();
	pClientItem->m_strDeviceName += now.FormatISODate();
	pClientItem->m_strDeviceName += _(" ");
	pClientItem->m_strDeviceName += now.FormatISOTime();

	// Mark as UDP receive channel
	pClientItem->m_bUDPReceiveChannel = true;

	// Add the client to the Client List
	m_pCtrlObject->m_wxClientMutex.Lock();
	m_pCtrlObject->addClient(pClientItem/*, CLIENT_ITEM_SPECIAL_ID_UDP*/);
	m_pCtrlObject->m_wxClientMutex.Unlock();


	crcInit();

	char szName[ 128 ];
	struct hostent * lpLocalHostEntry;

	if (-1 == gethostname(szName, sizeof( szName))) {
		wxLogError(_("UDP Receive Thread: Failed to get hostname\n"));
		return NULL;
	}

	wxLogDebug(_("udpReceiceThread: Hostname: %s"), szName);

	lpLocalHostEntry = gethostbyname(szName);
	if (NULL == lpLocalHostEntry) {
		wxLogError(_("UDP Receive Thread: Failed to get hostaddress\n"));
		return NULL;
	}

	// Get the address
	//localaddr = (in_addr_t *)lpLocalHostEntry->h_addr_list[ 0 ];

#ifndef WIN32

	/*
	  char ac[ 80 ];
	  if ( gethostname( ac, sizeof( ac ) ) == -1 ) {
	    ;
	  }
 
	  struct hostent *phe = gethostbyname( ac );

	  for ( int i = 0; phe->h_addr_list[i] != 0; ++i ) {
	    struct in_addr addr;
	    memcpy( &addr, phe->h_addr_list[i], sizeof (struct in_addr ) );
	    //cout << "Address " << i << ": " << inet_ntoa(addr) << endl;
	    wxLogDebug( _("Interface address:  %X\n"), addr );
	  }
	 */

#endif

	// Get all local addresses of the local machine
	int idx = -1;
	void *pAddr;
#ifdef WIN32
	unsigned long localaddr[ 16 ]; // max 16 local addresses
#else
	in_addr_t localaddr[ 16 ]; // max 16 local addresses
#endif
	do {
		idx++;
		localaddr[ idx ] = 0;
#ifdef WIN32
		pAddr = lpLocalHostEntry->h_addr_list[ idx ];
		if (NULL != pAddr) localaddr[ idx ] = *((unsigned long *) pAddr);
#else
		pAddr = (in_addr_t *) lpLocalHostEntry->h_addr_list[ idx ];
		if (NULL != pAddr) localaddr[ idx ] = *((in_addr_t *) pAddr);
		if (NULL != pAddr) wxLogTrace(_("wxTRACE_vscpd_receiveQueue"),
			_("udpReceiceThread: Local address: %X"),
			* (in_addr_t *) pAddr);

#endif


	} while ((NULL != pAddr) && (idx < 16));

	//
	// Create a UDP/IP datagram socket
	//
	int theSocket;

	theSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == theSocket) {
		return NULL;
	}

	int on = 1; // As suggested by Charles Tewiah
	setsockopt(theSocket,
		SOL_SOCKET,
		SO_REUSEADDR,
		(const char *) &on,
		sizeof( on));

	//
	// Fill in the address structure
	//
	struct sockaddr_in saServer;

	saServer.sin_family = AF_INET;
	saServer.sin_addr.s_addr = INADDR_ANY;
	saServer.sin_port = htons(m_pCtrlObject->m_UDPPort);

	// For multi interface machines.
	// If no bind address is given the default interface is used to receive
	// UDP datagrams which means datagrams will be received from all interfaces. Set
	// to ip of interface to select a specific interface.
	if (0 != m_pCtrlObject->m_strUdpBindInterfaceAddress.Length()) {
#if ( WIN32 && (_WIN32_WINNT<0x0600) ) 
		saServer.sin_addr.s_addr =
			inet_addr(m_pCtrlObject->m_strUdpBindInterfaceAddress.ToAscii());
#else
		inet_pton(AF_INET,
			m_pCtrlObject->m_strUdpBindInterfaceAddress.ToAscii(),
			(void *) &saServer.sin_addr.s_addr);
#endif
	}

	//
	// bind the name to the socket
	//

	int nRet;

	nRet = bind(theSocket,
		(struct sockaddr *) &saServer,
		sizeof( struct sockaddr));

	if (-1 == nRet) {
		return NULL;
	}

	struct sockaddr_in saClient;
	nLen = sizeof( struct sockaddr_in);

	wxLogDebug(_("udpReceiceThread: Ready to Work!"));

	while (!TestDestroy() && !m_bQuit) {

#ifdef WIN32
		memset(buf, 0, sizeof( buf));

		// Wait for data from the client
		nRet = recvfrom(theSocket,
			(char *) buf,
			sizeof(buf),
			0,
			(LPSOCKADDR) & saClient,
			&nLen);

		if (!nRet || (nRet == SOCKET_ERROR) || (nRet < 25)) {
			continue;
		}
#else
		bzero((uint8_t *) & saClient, sizeof( saClient));
		nLen = sizeof( struct sockaddr_in);
		bzero((uint8_t *) buf, sizeof( buf));

		// Wait for data from the client

		nRet = recvfrom(theSocket,
			buf,
			sizeof( buf),
			0,
			(struct sockaddr *) &saClient,
			&nLen);

		if ((0 == nRet) || (-1 == nRet) || (nRet < 25)) {
			continue;
		}

		wxLogDebug(_("udpReceiveThread: Incoming event. Addr=%X"),
			(in_addr_t) saClient.sin_addr.s_addr);
#endif
		// Handle received package

#ifdef WIN32

		// If this is a packet sent from this machine
		// we just disregards it		
		bool bLocalAddress = false;
		idx = 0;
		while ((0 != localaddr[ idx ]) && (idx < 16)) {
			if (localaddr[ idx ] == (unsigned long) saClient.sin_addr.S_un.S_addr) {
				bLocalAddress = true;
				break;
			}

			idx++;
		}

#else

		// If this is a packet sent from this machine
		// we just disregards it
		//if ( *localaddr == saClient.sin_addr.s_addr ) continue;
		bool bLocalAddress = false;
		idx = 0;
		while ((0 != localaddr[ idx ]) && (idx < 16)) {
			wxLogTrace(_("wxTRACE_vscpd_receiveQueue"),
				_(" Received address = %x"), (in_addr_t)
				saClient.sin_addr.s_addr);
			if (localaddr[ idx ] == (in_addr_t) saClient.sin_addr.s_addr) {
				bLocalAddress = true;
				wxLogTrace(_("wxTRACE_vscpd_receiveQueue"),
					_("Skipped because event has local origin "));
				break;
			}
			idx++;
		}

#endif

		if (bLocalAddress) continue; // From ourself get next event

		wxLogTrace(_("wxTRACE_vscpd_receiveQueue"),
			_("udpReceiveThread: It's from another machine. Grab it."));

		// Check size
		// The size member must be low enough for the data to fit
		// in the package
		unsigned short size;
		p = (unsigned char *) &size;
		* (p + 0) = buf[ VSCP_UDP_POS_SIZE + 1 ];
		* (p + 1) = buf[ VSCP_UDP_POS_SIZE + 0 ];

		if ((size + 25) > nRet) {
			// Wrong size -> Package faulty
			continue;
		}

		// Calculate CRC if requested
		if (!(buf[ VSCP_UDP_POS_HEAD + 0 ] & VSCP_NO_CRC_CALC)) {
			if (!crcFast(buf, size)) continue; // Faulty CRC
		}

		vscpEvent *pEvent = new vscpEvent;

		if (NULL != pEvent) {

			pEvent->obid = pClientItem->m_clientID;

			// Head
			p = (unsigned char *) &pEvent->head;
			* (p + 0) = buf[ VSCP_UDP_POS_HEAD + 0 ];

			// VSCP class
			p = (unsigned char *) &pEvent->vscp_class;
			* (p + 0) = buf[ VSCP_UDP_POS_CLASS + 1 ];
			* (p + 1) = buf[ VSCP_UDP_POS_CLASS + 0 ];

			// VSCP type
			p = (unsigned char *) &pEvent->vscp_type;
			* (p + 0) = buf[ VSCP_UDP_POS_TYPE + 1 ];
			* (p + 1) = buf[ VSCP_UDP_POS_TYPE + 0 ];

			// Node address
			p = (unsigned char *) &pEvent->GUID;
			memcpy(p, &buf[ VSCP_UDP_POS_GUID + 0 ], 16);

			// Number of valid data bytes
			pEvent->sizeData = size;

			if (pEvent->sizeData > 487) {
				// Can't be a VSCP package
				delete pEvent;
				continue;
			}

			// CRC
			p = (unsigned char *) &pEvent->crc;
			* (p + 0) = buf[ VSCP_UDP_POS_CRC + 1 ];
			* (p + 1) = buf[ VSCP_UDP_POS_CRC + 0 ];

			pEvent->pdata = NULL;

			if (0 != pEvent->sizeData) {

				// Allocate storage for data
				unsigned char *pDataArea = new unsigned char[ pEvent->sizeData ];

				if (NULL != pDataArea) {

					// Data Max 487 (512- 25) bytes
					pEvent->pdata = pDataArea;

					// size = sz - command_byte - control_bytes
					memcpy(pEvent->pdata, &buf[ VSCP_UDP_POS_DATA ], pEvent->sizeData);

				}
			}

			// RX Statistics
			pClientItem->m_statistics.cntReceiveData += pEvent->sizeData;
			pClientItem->m_statistics.cntReceiveFrames++;


			// There must be room in the send queue
			if (m_pCtrlObject->m_maxItemsInClientReceiveQueue >
				m_pCtrlObject->m_clientOutputQueue.GetCount()) {
				m_pCtrlObject->m_mutexClientOutputQueue.Lock();
				m_pCtrlObject->m_clientOutputQueue.Append(pEvent);
				m_pCtrlObject->m_semClientOutputQueue.Post();
				m_pCtrlObject->m_mutexClientOutputQueue.Unlock();
			} else {
				pClientItem->m_statistics.cntOverruns++;
				deleteVSCPevent(pEvent);
			}

		}

	} // while

#ifdef WIN32
	_close(theSocket);
#else
	close(theSocket);
#endif

	// Remove the client
	m_pCtrlObject->m_wxClientMutex.Lock();
	m_pCtrlObject->removeClient(pClientItem);
	m_pCtrlObject->m_wxClientMutex.Unlock();

	return NULL;

}
Example #4
0
void *UDPSendThread::Entry()
{
	// Must have a valid pointer to the control object
	if (NULL == m_pCtrlObject) return NULL;

	// We need to create a clientobject and add this object to the list
	CClientItem *pClientItem = new CClientItem;
	if (NULL == pClientItem) return NULL;

	// This is an active client
	pClientItem->m_bOpen = true;
	pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_CLIENT_INTERNAL;
	pClientItem->m_strDeviceName = _("Internal UDP Transmit Client. Started at ");
	wxDateTime now = wxDateTime::Now();
	pClientItem->m_strDeviceName += now.FormatISODate();
	pClientItem->m_strDeviceName += _(" ");
	pClientItem->m_strDeviceName += now.FormatISOTime();

	// Add the client to the Client List
	m_pCtrlObject->m_wxClientMutex.Lock();
	m_pCtrlObject->addClient(pClientItem/*, CLIENT_ITEM_SPECIAL_ID_UDP*/);
	m_pCtrlObject->m_wxClientMutex.Unlock();

	// Create the socket for Level II UDP datagrams
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(0);

	// Using the INADDR_ANY interface datagrams will be sent on the first found interface
	// on a machine with multiple interfaces. If the ifaddress is set to another valid
	// address that interface will be used instead.
	if (0 != m_pCtrlObject->m_strUdpInterfaceAddress.Length()) {
#if ( WIN32 && (_WIN32_WINNT<0x0600) ) 
		addr.sin_addr.s_addr =
			inet_addr(m_pCtrlObject->m_strUdpBindInterfaceAddress.ToAscii());
#else
		inet_pton(AF_INET, m_pCtrlObject->m_strUdpInterfaceAddress.ToAscii(), (void *) &addr.sin_addr.s_addr);
#endif
	}

	if (-1 != (m_sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {

		int on = 1;
		setsockopt(m_sendsock,
			SOL_SOCKET,
			SO_BROADCAST,
			(const char*) &on,
			sizeof( on));

		on = 1; // As suggested by Charles Tewiah
		setsockopt(m_sendsock,
			SOL_SOCKET,
			SO_REUSEADDR,
			(const char *) &on,
			sizeof( on));

		if (1 == bind(m_sendsock, (struct sockaddr*) &addr, sizeof( addr))) {
			m_pCtrlObject->logMsg(_("vscpd: Faild to bind send socket. Functionality disabled."), DAEMON_LOGMSG_ERROR);
#ifdef WIN32
			if (NULL != m_sendsock) closesocket(m_sendsock);
			m_sendsock = NULL;
#else
			if (0 != m_sendsock) close(m_sendsock);
			m_sendsock = 0;
#endif

		}

	} else {
		m_pCtrlObject->logMsg(_("vscpd: Faild to create send socket. Functionality disabled."), DAEMON_LOGMSG_ERROR);
#ifdef WIN32
		m_sendsock = NULL;
#else
		m_sendsock = 0;
#endif
	}

	char szName[ 128 ];
#ifdef WIN32
	LPHOSTENT lpLocalHostEntry;
#else
	struct hostent *lpLocalHostEntry;
#endif
	gethostname(szName, sizeof( szName));
	lpLocalHostEntry = gethostbyname(szName);
	if (NULL == lpLocalHostEntry) {
		return NULL;
	}

	// Get all local addresses for interface
	int cntAddr = -1;
	void *pAddr;
	unsigned long localaddr[ 16 ]; // max 16 local addresses
	do {
		cntAddr++;
		localaddr[ cntAddr ] = 0;
		pAddr = lpLocalHostEntry->h_addr_list[ cntAddr ];
		if (NULL != pAddr) localaddr[ cntAddr ] = *((unsigned long *) pAddr);
	} while ((NULL != pAddr) && (cntAddr < 16));

	CLIENTEVENTLIST::compatibility_iterator nodeVSCP;
	vscpEvent *pvscpEvent = NULL;
	while (!TestDestroy() && !m_bQuit) {

		// Wait for event
		if (wxSEMA_TIMEOUT == pClientItem->m_semClientInputQueue.WaitTimeout(500)) continue;

		if (pClientItem->m_clientInputQueue.GetCount()) {
			pClientItem->m_mutexClientInputQueue.Lock();
			nodeVSCP = pClientItem->m_clientInputQueue.GetFirst();
			pvscpEvent = nodeVSCP->GetData();

			// Remove event from sendqueue
			pClientItem->m_clientInputQueue.DeleteNode(nodeVSCP);
			pClientItem->m_mutexClientInputQueue.Unlock();

			if ((NULL != pvscpEvent)) {
				sendUdpEvent(pvscpEvent);
			}

			// Delete the event
			deleteVSCPevent(pvscpEvent);

		}

	} // while

	// Remove the client
	m_pCtrlObject->m_wxClientMutex.Lock();
	m_pCtrlObject->removeClient(pClientItem);
	m_pCtrlObject->m_wxClientMutex.Unlock();

	return NULL;
}
extern "C" void WINAPI EXPORT vscp_deleteVSCPevent( vscpEvent *pEvent )
{
    return deleteVSCPevent( pEvent );
}
Example #6
0
void ctrlUpdate::eventThreadMessage( wxCommandEvent &event )
{
	int write_pointer,checksum16;
	unsigned long intflash_blocksize,max_intflash_blocknumber,extflash_blocksize,max_extflash_blocknumber;
	int block_number;
	int i = event.GetInt();
	int id = i & 0xFFFF;
	int type = (i >> 16) & 0xFFFF;
	CDeviceNode* pNode = m_plistNode->GetNodeByNickName(id);
	wxString strData = event.GetString();
	vscpEvent* pVscp = new vscpEvent;
	getVscpDataFromString( pVscp, strData );

	if(pNode != NULL)
	{
		if(event.GetExtraLong()==0)
		{
			switch(type)
			{
				case VSCP_TYPE_PROTOCOL_ACK_BOOT_LOADER:
					// pVscp->pdata[ 0 ] = 2;	MSB internal flash block size
					// pVscp->pdata[ 1 ] = 2;	MSB spi flash block size
					// pVscp->pdata[ 2 ] = 0;	LSB spi flash block size
					// pVscp->pdata[ 3 ] = 0;	LSB internal flash block size
					// pVscp->pdata[ 4 ] = 1;	MSB internal flash number of block avalaible
					// pVscp->pdata[ 5 ] = 4;	MSB spi flash number of block avalaible
					// pVscp->pdata[ 6 ] = 0;	LSB spi flash number of block avalaible
					// pVscp->pdata[ 7 ] = 0;	LSB internal flash number of block avalaible
					intflash_blocksize = (pVscp->pdata[0] << 8) | pVscp->pdata[3];
					extflash_blocksize = (pVscp->pdata[1] << 8) | pVscp->pdata[2];
					max_intflash_blocknumber = (pVscp->pdata[4] << 8) | pVscp->pdata[7];
					max_extflash_blocknumber = (pVscp->pdata[5] << 8) | pVscp->pdata[6];

					if((intflash_blocksize == BLOCKDATA_SIZE)	&&
				       (extflash_blocksize == BLOCKDATA_SIZE)	&&
					   (max_intflash_blocknumber >= (m_IntFlashBinaryLength/BLOCKDATA_SIZE))&&
					   (max_extflash_blocknumber >= (m_ExtFlashBinaryLength/BLOCKDATA_SIZE))
					  )
					{
						crcInit();
						m_nTotalChecksum = 0;
						m_nCurrentBlockNumber = 0;
						m_nCurrentFlashType = INT_FLASH;	// internal flash
						// attenzione: questo messaggio (VSCP_TYPE_PROTOCOL_ACK_BOOT_LOADER) è l'ultimo arrivato dal 
						// programma user, ora ha preso il controllo il bootloader; è probabile che sia necessario
						// un delay prima di trasmettere il messaggio di "start block transfer"
						wxMilliSleep( 2000 );//wxMilliSleep( 500 );//wxMilliSleep( 200 );
						StartBlockTransferMsg( pNode->GetNickName(), m_nCurrentBlockNumber, m_nCurrentFlashType );
					}
					else
					{
						UpdateError(pNode);
					}

					//::wxGetApp().logMsg ( _("event ack bootloader"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_START_BLOCK_ACK:
					// pVscp->pdata[0] MSB block number
					// pVscp->pdata[1] INTERNAL_FLASH/SPI_FLASH
					// pVscp->pdata[2]
					// pVscp->pdata[3] LSB block number
					if(m_nCurrentFlashType == pVscp->pdata[1])
					{
						switch(m_nCurrentFlashType)
						{
							case INT_FLASH:
								DataBlockTransferMsg();
								m_nChecksum = crcFast( &m_pIntFlashBinaryContent[USER_PROGRAM_ADDRESS + m_nCurrentBlockNumber*BLOCKDATA_SIZE], BLOCKDATA_SIZE );//crcFast( &m_pIntFlashBinaryContent[30208], BLOCKDATA_SIZE );//crcFast( &m_pIntFlashBinaryContent[USER_PROGRAM_ADDRESS + m_nCurrentBlockNumber*BLOCKDATA_SIZE], BLOCKDATA_SIZE );
								//m_nTotalChecksum += m_nChecksum;
								break;
							case EXT_FLASH:

								DataBlockTransferMsg();
								m_nChecksum = crcFast( &m_pExtFlashBinaryContent[m_nCurrentBlockNumber*BLOCKDATA_SIZE], BLOCKDATA_SIZE );
								break;
						}
					}
					else
					{
						UpdateError(pNode);
					}
					//::wxGetApp().logMsg ( _("event ack data block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_BLOCK_DATA_ACK:
					// pVscp->pdata[0] = (checksum16 >> 8) & 0xFF;		MSB 16 bit CRC for block
					// pVscp->pdata[1] = checksum16 & 0xFF;				LSB 16 bit CRC for block
					// pVscp->pdata[2] = (write_pointer >> 8) & 0xFF;	MSB of block number 
					// pVscp->pdata[3] = 0;
					// pVscp->pdata[4] = 0;
					// pVscp->pdata[5] = write_pointer & 0xFF;			LSB of block number
					checksum16 = (pVscp->pdata[0] << 8) | pVscp->pdata[1];
					write_pointer = (pVscp->pdata[2] << 8) | pVscp->pdata[5];
					if((checksum16 == m_nChecksum) && (write_pointer == m_nCurrentBlockNumber))
						BlockProgramMsg( m_nCurrentBlockNumber, m_nCurrentFlashType );
					else
					{
						// in questo caso di errore si ritrasmette il blocco
						StartBlockTransferMsg( pNode->GetNickName(), m_nCurrentBlockNumber, m_nCurrentFlashType );
						//UpdateError(pNode);
					}

					//::wxGetApp().logMsg ( _("event ack data block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_PROGRAM_BLOCK_DATA_ACK:
					// pVscp->pdata[0] MSB block number
					// pVscp->pdata[1] INTERNAL_FLASH/SPI_FLASH
					// pVscp->pdata[2]
					// pVscp->pdata[3] LSB block number
					block_number = (pVscp->pdata[0] << 8) | pVscp->pdata[3];
					if((block_number == m_nCurrentBlockNumber) && (pVscp->pdata[1] == m_nCurrentFlashType))
					{
						switch(m_nCurrentFlashType)
						{
							case INT_FLASH:
								m_nCurrentBlockNumber++;
								//::wxGetApp().logMsg ( _("event PROGRAM ACK"), DAEMON_LOGMSG_CRITICAL );
								m_nTotalChecksum += m_nChecksum;
								if(m_nCurrentBlockNumber == (int)((m_IntFlashBinaryLength - USER_PROGRAM_ADDRESS)/BLOCKDATA_SIZE))
								{
									m_nCurrentBlockNumber = 0;
									m_nCurrentFlashType = EXT_FLASH;
									
							//ActivateNewImageMsg();	// DEBUG!!
								}
							//else // DEBUG!!
							//{// DEBUG!!
								// avanzamento progress control della dialog
								pNode->FirmwareProgressStep();
								wxGetApp().Yield();
								StartBlockTransferMsg( pNode->GetNickName(), m_nCurrentBlockNumber, m_nCurrentFlashType );
							//}// DEBUG!!
								break;
							case EXT_FLASH:
								m_nCurrentBlockNumber++;
								if(m_nCurrentBlockNumber == (int)(m_ExtFlashBinaryLength/BLOCKDATA_SIZE))
								{
									ActivateNewImageMsg();
								}
								else
								{
									// avanzamento progress control della dialog
									pNode->FirmwareProgressStep();
									wxGetApp().Yield();
									StartBlockTransferMsg( pNode->GetNickName(), m_nCurrentBlockNumber, m_nCurrentFlashType );
								}
								break;
						}
					}
					else
					{
						UpdateError(pNode);
					}

					//::wxGetApp().logMsg ( _("event ack program block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_ACTIVATENEWIMAGE_ACK:
					// delay per attendere che il nodo remoto abbia finito la fase di 
					// inizializzazione altrimenti quando l'utente chiude la dialog di update
					// c'e' il rischio che il gestore dell' heartbeat non rilevi il nuovo stato (stato user)
					// del nodo
					wxMilliSleep( 8000 );

					m_tDoneUpgrade = wxDateTime::Now();
					::wxGetApp().logMsg ( wxT("Upgrade Finished... taking: ") + (m_tDoneUpgrade - m_tStartUpgrade).Format(), DAEMON_LOGMSG_CRITICAL );

					// avvisa la dialog che è finito il processo di update
					pNode->EndFirmwareProgress(FIRMWAREUPDATEOK);
					break;

				case VSCP_TYPE_PROTOCOL_NACK_BOOT_LOADER:
					UpdateError(pNode);
					::wxGetApp().logMsg ( _("event NACK bootloader"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_START_BLOCK_NACK:
					UpdateError(pNode);
					::wxGetApp().logMsg ( _("event NACK start block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_BLOCK_DATA_NACK:
					UpdateError(pNode);
					::wxGetApp().logMsg ( _("event NACK data block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_PROGRAM_BLOCK_DATA_NACK:
					UpdateError(pNode);
					::wxGetApp().logMsg ( _("event NACK program block"), DAEMON_LOGMSG_CRITICAL );
					break;
				case VSCP_TYPE_PROTOCOL_ACTIVATENEWIMAGE_NACK:
					UpdateError(pNode);
					::wxGetApp().logMsg ( _("event NACK activate new image"), DAEMON_LOGMSG_CRITICAL );
					break;
			}
		}
		else
		{
			UpdateError(pNode);
		}
	}

	deleteVSCPevent( pVscp );
}