Exemple #1
0
/*
*****************************************************************************
** FUNCTION NAME: HttpRequest
**
** FUNCTION INPUTS:
**  @char *hostname: host name. e.g. freedb.freedb.org
**  @int port: http request port. e.g. 80
**  @char *uriBuf: http request uri with http request header
**  @int timeout: timeout (unit:seconds) e.g. 30
**  @PHTTP_RESPONSE pHttp: HTTP_RESPONSE struct for return
**
** FUNCTION DESCRIPTION
**   This function will create socket by hostname and port, then it will send
** uriBuf to server and wait it until timeout. If get response success, parse
** it and return with HTTP_REPONSE struct.
**
** FUNCTION OUTPUTS:
**   ZAPP_SUCCESS -> success
**   ZAPP_TIMEOUT -> timeout
**   ZAPP_NETWORK -> cannot link to server
**   ZAPP_FAILED -> other reason
**
** HISTORY:
** 2008-7-3	Steven Leong	Created
*****************************************************************************
*/
int HttpRequest(char *hostname, int port, char *uriBuf, int timeout, PHTTP_RESPONSE pHttp)
{
	int nRet;
	int fd;
	/* timeout policy */
	int lefttime, starttime, curtime;

	if(hostname == NULL || uriBuf == NULL || pHttp == NULL)
		return ZAPP_FAILED;

	lefttime = timeout;
	starttime = GetUptime();

	/* Create socket */
	nRet = CreateTCPSenderByHostname(hostname, port, &fd, lefttime);
	if(nRet != ZAPP_SUCCESS){
		switch(nRet){
			case ZAPP_NETWORK:
				return ZAPP_NETWORK;
			case ZAPP_TIMEOUT:
				return ZAPP_TIMEOUT;
		}
		return ZAPP_FAILED;
	}

	// Calculate lefttime
	if((curtime = GetUptime()) > 0){
		lefttime -= curtime - starttime;
		starttime = curtime;
	}
	if(lefttime <= 0){
		close(fd);
		return ZAPP_TIMEOUT;
	}

	/* Send request */
	if(write(fd, uriBuf, strlen(uriBuf)) <= 0){
		close(fd);
		return ZAPP_FAILED;
	}
	nRet = HttpRead(fd, lefttime, pHttp);
	if(nRet != ZAPP_SUCCESS){
		close(fd);
		if(nRet == ZAPP_TIMEOUT)
			return ZAPP_TIMEOUT;
		return ZAPP_FAILED;
	}
	
	/* Free socket */
	close(fd);
	return ZAPP_SUCCESS;
}
Exemple #2
0
/*
*****************************************************************************
** FUNCTION NAME: CreateTCPSenderByHostname
**
** FUNCTION INPUTS:
**  @char *hostname: e.g. www.google.cn
**  @int port: port e.g. 80
**  @int *fd: fd for output
**  @int timeout: how many seconds to timeout
**
** FUNCTION DESCRIPTION
**   This function will create TCP sender with hostname
**
** FUNCTION OUTPUTS:
**   Returns ZAPP_SUCCESS on success, or ZAPP_FAILED on creating socket failed.
** or ZAPP_NETWORK on gethostbyname failed(Not network). or ZAPP_TIMEOUT on timeout.
**
** HISTORY:
** 2008-7-2	Steven Leong	Created
*****************************************************************************
*/
int CreateTCPSenderByHostname(char *hostname, int port, int *fd, int timeout)
{
	struct hostent *hptr;
	char **ptr;
	char strArray[32] = {0};
	char *ptrIpAddr = NULL;
	int  nAddrType, res;
	U32 lefttime, starttime, curtime;
	
	lefttime = timeout;
	starttime = GetUptime();
	
	*fd = -1;
	dprintf("hostname->%s\n", hostname);
	if((hptr = gethostbyname(hostname)) == NULL){
		return ZAPP_NETWORK;
	}
	
	if((curtime = GetUptime()) > 0){
		lefttime -= curtime - starttime;
		starttime = curtime;
	}

	nAddrType = hptr->h_addrtype;
	if(nAddrType == AF_INET || nAddrType == AF_INET6){
		ptr=hptr->h_addr_list;
		for(;*ptr!=NULL;ptr++){
			ptrIpAddr=(char*)inet_ntop(nAddrType,*ptr,strArray,(sizeof(strArray)));
			dprintf("IPAddr->%s\n", ptrIpAddr);
			
			res = CreateSocket(TCPSOCKET, SENDER, ptrIpAddr, port, fd, lefttime);
			if(res == ZAPP_SUCCESS)
				break;
			if((curtime = GetUptime()) > 0){
				lefttime -= curtime - starttime;
				starttime = curtime;
				if(lefttime <= 0){
					/* timeout */
					return ZAPP_TIMEOUT;
				}
			}
		}
	}

	if(*fd <= 0)
		return ZAPP_FAILED;

	return ZAPP_SUCCESS;
}
Exemple #3
0
int GetItemFromFourLight(ISmartFrame *pISMartFrame, Item *pitem)
{
	/*mac*/
	memcpy((void*)pitem->mac, &pISMartFrame->sourceMac[6], MAC_SIZE);
	/*类型*/
	pitem->type = pISMartFrame->funCode.dev;
	/*状态*/
	if (1 == pISMartFrame->data[0])
	{
		pitem->status |= 0x01; /*低1位*/
	}
	if (1 == pISMartFrame->data[1])
	{
		pitem->status |= 0x02; /*低2位*/
	}
	if (1 == pISMartFrame->data[2])
	{
		pitem->status |= 0x04; /*低3位*/
	}
	if (1 == pISMartFrame->data[3])
	{
		pitem->status |= 0x08; /*低4位*/
	}
	/*时间*/
	pitem->ntime = GetUptime();
	return ReturnSuccess;
}
Exemple #4
0
int GetItemFromAny(ISmartFrame *pISMartFrame, Item *pitem)
{
	/*mac*/
	memcpy((void*)pitem->mac, &pISMartFrame->sourceMac[6], MAC_SIZE);
	/*类型*/
	pitem->type = pISMartFrame->funCode.dev;
	/*状态*/
	pitem->status = pISMartFrame->data[0];
	/*时间*/
	pitem->ntime = GetUptime();

	return ReturnSuccess;
}
Exemple #5
0
int GetItemFromControlSocket(ISmartFrame *pISMartFrame, Item *pitem)
{
	/*mac*/
	memcpy((void*)pitem->mac, &pISMartFrame->sourceMac[6], MAC_SIZE);
	/*类型*/
	pitem->type = pISMartFrame->funCode.dev;
	/*状态*/
	if (1 == pISMartFrame->data[0])
	{
		pitem->status |= 0x01;
	}
	/*时间*/
	pitem->ntime = GetUptime();
	return ReturnSuccess;
}
Exemple #6
0
int PackGatewayNodeRet(ISmartFrame *pISMartFrame, unsigned int *pnLen)
{
	if (NULL == pISMartFrame || NULL == pnLen)
	{
		return ReturnError;
	}
	FillAA55(pISMartFrame);
	pISMartFrame->frameLength = htons(PACKAGE_SIZE_QUERYNODERET);
	pISMartFrame->dataLength = htons(PACKAGE_SIZE_QUERYNODERET - PACKAGE_SIZE_HEAD);
	*pnLen = PACKAGE_SIZE_QUERYNODERET;
	pISMartFrame->funCode.dev = PROTOCOL_TYPE_GATEWAY;
	pISMartFrame->funCode.ver = PROTOCOL_VERSION;
	pISMartFrame->funCode.fun = PROTOCOL_FUN_GATEWAY_QUERYNODERET;
	
	if (SourceMacNoInit == CheckInitSourceMac())
	{
		return ReturnError;
	}
	FillSourceMac(pISMartFrame);
    FillSourceMacToTarget(pISMartFrame);

	FillCRC(pISMartFrame);
	
	PNode pnode = g_pNodeList->front;
	unsigned int i = 0;
	for (; pnode && i < 80; pnode = pnode->next, i++)
	{
		/*前四个字节直接填充*/
		memcpy((void *)(pISMartFrame->data + 5 * i), (void *)(pnode->data), 4);
		/*第五个字节,需要用当前时间减去存储的时间,以获取时间差*/
		long time = (char)(GetUptime() - ((Item *)(pnode->data))->ntime);
		if (time > 255)
		{
			time = 255;
		}
		*(pISMartFrame->data + 5*i + 4) = time;
	}
	
	return ReturnSuccess;
	
}
Exemple #7
0
/*
*****************************************************************************
** FUNCTION NAME: HttpRead
**
** FUNCTION INPUTS:
**  @int fd: socket fd
**  @int timeout: timeout (unit:seconds) e.g. 30
**  @PHTTP_RESPONSE pHttp: HTTP_RESPONSE struct for return
**
** FUNCTION DESCRIPTION
**   This function will read http response from fd and package HTTP_RESPONSE.
**
** FUNCTION OUTPUTS:
**   ZAPP_SUCCESS -> success
**   ZAPP_TIMEOUT -> timeout
**   ZAPP_FAILED -> other reason
**
** HISTORY:
** 2008-7-3	Steven Leong	Created
*****************************************************************************
*/
int HttpRead(int fd, int timeout, PHTTP_RESPONSE pHttp)
{
	Z_BUF zBuf;
	fd_set  rdfds;
	struct  timeval tv;
	char bufArray[BUF_16_BITS];
	U32 lefttime, starttime, curtime;
	int n, nRet = ZAPP_SUCCESS;

	/* init */
	FD_ZERO (&rdfds);
	FD_SET (fd, &rdfds);

	tv.tv_usec = 0;

	ZUtilBufInit(&zBuf, 0);

	lefttime = timeout;
	starttime = GetUptime();

	memset(pHttp, 0, sizeof(HTTP_RESPONSE));

	while(1) {
		tv.tv_sec = lefttime;
		select (fd+1, &rdfds, NULL, NULL, &tv);
		if(FD_ISSET (fd, &rdfds)){
			memset(bufArray, 0, BUF_16_BITS);
			n = read(fd, bufArray, 1);
			//NOTE: This is very import!!! Don't remove.
			bufArray[n] = '\0';
			/* Calculate lefttime */
			if((curtime = GetUptime()) > 0){
				lefttime -= curtime - starttime;
				starttime = curtime;
			}
			if(lefttime <= 0){
				/* timeout */
				nRet = ZAPP_TIMEOUT;
				goto appOut;
			}
			
			if(n < 0){
				if( errno == EAGAIN)
					continue;
				else {
					/* pipe error */
					dprintf("pipe error.\n");
					nRet = ZAPP_FAILED;
					goto appOut;
				}
			}
			else if(n == 0){
				/* The server close the socket */
				//NOTE: we are reading the header. don't allow to close. */
				dprintf("The server close the socket.\n");
				nRet = ZAPP_FAILED;
				goto appOut;
			}
			//dprintf("Read Buf(%d)-> %s\n", n, bufArray);
			ZBufAttach(&zBuf, bufArray, n);
			
			/* Parse the header and choise parse content way */
			if(strstr(zBuf.buf, HEADER_DCRLF)!= NULL){
				dprintf(">>> Header buf-> %s\n", zBuf.buf);
				HttpPraseHeader(zBuf.buf,&pHttp->header);
				
				if(pHttp->header.transEncode == CHUNKED){
					dprintf(">>> Parsing chunked content.\n");
					nRet = ReadHttpContent(fd, &rdfds, lefttime, pHttp, 1);
				}
				else{
					dprintf(">>> Parsing normal content.\n");
					nRet = ReadHttpContent(fd, &rdfds, lefttime, pHttp, 0);
				}
				/* Return the result */
				break;
			}
		}
		else{
			/* timeout */
			nRet = ZAPP_TIMEOUT;
			goto appOut;
		}
	}

appOut:
	ZUtilBufDestroy(&zBuf);
	return nRet;
}
Exemple #8
0
/*
*****************************************************************************
** FUNCTION NAME: ReadHttpContent
**
** FUNCTION INPUTS:
**   @int fd: fd
**   @fd_set *prdfds: fd_set
**   @int timeout: timeout
**   @PHTTP_RESPONSE pHttp: 
**   @int chunked: 0=> not chunkd encoding, 1=> chunked encoding
**
** FUNCTION DESCRIPTION
**   This function will read http content from fd and package HTTP_RESPONSE.
**
** FUNCTION OUTPUTS:
**   ZAPP_SUCCESS -> success
**   ZAPP_TIMEOUT -> timeout
**   ZAPP_FAILED -> other reason
**
** HISTORY:
** 2008-7-11	Steven Leong	Created
*****************************************************************************
*/
int ReadHttpContent(int fd, fd_set *prdfds, int timeout, PHTTP_RESPONSE pHttp, int chunked)
{
	Z_BUF zBuf;
	struct  timeval tv;
	char bufArray[BUF_1024_BITS];
	U32 lefttime, starttime, curtime;
	int n, nRet = ZAPP_SUCCESS;
	//for chunked
	Z_BUF zBufChunk;
	char *ptr = NULL;
	int size;
	
	tv.tv_usec = 0;

	ZUtilBufInit(&zBuf, 0);
	ptr = &zBuf.buf[0];

	lefttime = timeout;
	starttime = GetUptime();

	while(1) {
		tv.tv_sec = lefttime;
		select (fd+1, prdfds, NULL, NULL, &tv);
		if(FD_ISSET (fd, prdfds)){
			memset(bufArray, 0, BUF_1024_BITS);
			n = read(fd, bufArray, BUF_1024_BITS-1);
			/* Calculate lefttime */
			if((curtime = GetUptime()) > 0){
				lefttime -= curtime - starttime;
				starttime = curtime;
			}
			if(lefttime <= 0){
				/* timeout */
				nRet = ZAPP_TIMEOUT;
				goto appOut;
			}
			if(n < 0){
				if( errno == EAGAIN)
					continue;
				else {
					/* pipe error */
					dprintf("pipe error.\n");
					nRet = ZAPP_FAILED;
					goto appOut;
				}
			}
			else if(n == 0){
				/* The server close the socket */
				//NOTE: we are reading the header. don't allow to close. */
				dprintf("The server close the socket.\n");
				if(chunked == 1)
					goto parseChunked;
				else
					goto readDone;
			}
			//dprintf("Read Buf(%d)-> %s\n", n, bufArray);
			ZBufAttach(&zBuf, bufArray, n);
			
			if(chunked == 1){
				/* Chunked encoding */
				//NOTE: "\r\n0\r\n" for end flag
				if(strstr(ptr, CRLF"0"CRLF) == NULL){
					/* NOTE:zBuf.length-10 is very import.
					e.g. If former read is "xxxx\r", and this
					time is "\n0\r\n\r\n", it will make right.*/
					if(zBuf.length > 10)
						ptr = &zBuf.buf[zBuf.length-10];
					else
						ptr = &zBuf.buf[0];
				}
				else
					goto parseChunked;
			}
			else{
				/* Normal */
				if(zBuf.length >= pHttp->header.contentLength)
					goto readDone;
			}
			
		}
		else{
			/* timeout */
			nRet = ZAPP_TIMEOUT;
			goto appOut;
		}
	}

appOut:
	ZUtilBufDestroy(&zBuf);
	return nRet;

readDone:
	//Done. Copy the content
	dprintf("Normal content Done.\n");
	pHttp->contentSize = pHttp->header.contentLength;
	pHttp->content = zBuf.buf;
	zBuf.buf = NULL;
	
	ZUtilBufDestroy(&zBuf);
	return ZAPP_SUCCESS;

parseChunked:
	dprintf("Chunk content done.\n");
	ZUtilBufInit(&zBufChunk, 0);
	ptr = &zBuf.buf[0];
	while(1){
		//Try to find out the chunked length
		//NOTE: chunked is the Hex format
		n = sscanf(ptr, "%x"CRLF, &size);
		if(n <= 0 || size == 0)
			break;
		dprintf(">>>>>> ChunkSize:%d(%x)\n", size, size);
		pHttp->header.contentLength += size;
		ptr += GotoNextLine(ptr)+strlen(CRLF);
		
		ZBufAttach(&zBufChunk, ptr, size);

		ptr += (size+1);
	};
	
	pHttp->header.contentLength = zBufChunk.length;
	pHttp->contentSize = pHttp->header.contentLength;
	pHttp->content = zBufChunk.buf;
	zBufChunk.buf = NULL;

	ZUtilBufDestroy(&zBufChunk);
	ZUtilBufDestroy(&zBuf);
	return ZAPP_SUCCESS;
}
Exemple #9
0
void CCommandProcessor::ParseCommand ( const char * const cmdBegin,
                                       const uint64_t currentTime )
{
  const char * const cmdEnd = SkipCharsNotInSet( cmdBegin, SPACE_AND_TAB );
  assert( cmdBegin != cmdEnd );

  const char * const paramBegin = SkipCharsInSet( cmdEnd, SPACE_AND_TAB );

  bool extraParamsFound = false;

  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_QUESTION_MARK, true, false, &extraParamsFound ) ||
       IsCmd( cmdBegin, cmdEnd, CMDNAME_HELP, false, false, &extraParamsFound ) )
  {
    PrintStr( "This console is similar to the Bus Pirate console." EOL );
    PrintStr( "Commands longer than 1 character are case insensitive." EOL );
    PrintStr( "WARNING: If a command takes too long to run, the watchdog may reset the board." EOL );
    PrintStr( "Commands are:" EOL );

    Printf( "  %s, %s: Show this help text." EOL, CMDNAME_QUESTION_MARK, CMDNAME_HELP );
    Printf( "  %s: Show version information." EOL, CMDNAME_I );
    Printf( "  %s: Test USB transfer speed." EOL, CMDNAME_USBSPEEDTEST );
    Printf( "  %s: Show JTAG pin status (read as inputs)." EOL, CMDNAME_JTAGPINS );
    Printf( "  %s: Test JTAG shift speed. WARNING: Do NOT connect any JTAG device." EOL, CMDNAME_JTAGSHIFTSPEEDTEST );
    Printf( "  %s: Exercises malloc()." EOL, CMDNAME_MALLOCTEST );
    Printf( "  %s: Exercises C++ exceptions." EOL, CMDNAME_CPP_EXCEPTION_TEST );
    Printf( "  %s: Shows memory usage." EOL, CMDNAME_MEMORY_USAGE );
    Printf( "  %s" EOL, CMDNAME_CPU_LOAD );
    Printf( "  %s" EOL, CMDNAME_UPTIME );
    Printf( "  %s" EOL, CMDNAME_RESET );
    Printf( "  %s" EOL, CMDNAME_RESET_CAUSE );
    Printf( "  %s <addr> <byte count>" EOL, CMDNAME_PRINT_MEMORY );
    Printf( "  %s <milliseconds>" EOL, CMDNAME_BUSY_WAIT );
    Printf( "  %s <command|protocol>" EOL, CMDNAME_SIMULATE_ERROR );

    return;
  }

  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_I, true, false, &extraParamsFound ) )
  {
    #ifndef NDEBUG
      const char buildType[] = "Debug build";
    #else
      const char buildType[] = "Release build";
    #endif

    Printf( "JtagDue %s" EOL, PACKAGE_VERSION );
    Printf( "%s, compiler version %s" EOL, buildType, __VERSION__ );
    Printf( "Watchdog %s" EOL, ENABLE_WDT ? "enabled" : "disabled" );

    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_RESET, false, false, &extraParamsFound ) )
  {
    // This message does not reach the other side, we would need to add some delay.
    //   UsbPrint( txBuffer, "Resetting the board..." EOL );
    __disable_irq();
    // Note that this message always goes to the serial port console,
    // even if the user is connected over USB. It might be possible to send
    // it over USB and then wait for the outgoing buffer to be empty.
    SerialSyncWriteStr( "Resetting the board..." EOL );
    SerialWaitForDataSent();
    ResetBoard( ENABLE_WDT );
    assert( false );  // We should never reach this point.
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_CPU_LOAD, false, false, &extraParamsFound ) )
  {
    if ( ENABLE_CPU_SLEEP )
      PrintStr( "CPU load statistics not available." EOL );
    else
      DisplayCpuLoad();

    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_UPTIME, false, false, &extraParamsFound ) )
  {
    char buffer[ CONVERT_TO_DEC_BUF_SIZE ];
    Printf( "Uptime: %s seconds." EOL, convert_unsigned_to_dec_th( GetUptime() / 1000, buffer, ',' ) );
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_RESET_CAUSE, false, false, &extraParamsFound ) )
  {
    DisplayResetCause();
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_PRINT_MEMORY, false, true, &extraParamsFound ) )
  {
    PrintMemory( paramBegin );
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_BUSY_WAIT, false, true, &extraParamsFound ) )
  {
    BusyWait( paramBegin );
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_USBSPEEDTEST, false, true, &extraParamsFound ) )
  {
    ProcessUsbSpeedTestCmd( paramBegin, currentTime );
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_JTAGPINS, false, false, &extraParamsFound ) )
  {
    PrintJtagPinStatus();
    return;
  }

  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_JTAGSHIFTSPEEDTEST, false, false, &extraParamsFound ) )
  {
    if ( !IsNativeUsbPort() )
      throw std::runtime_error( "This command is only available on the 'Native' USB port." );


    // Fill the Rx buffer with some test data.
    assert( m_rxBuffer != NULL );

    m_rxBuffer->Reset();
    for ( uint32_t i = 0; !m_rxBuffer->IsFull(); ++i )
    {
      m_rxBuffer->WriteElem( CUsbRxBuffer::ElemType( i ) );
    }


    // If the mode is set to MODE_HIZ, you cannot see the generated signal with the oscilloscope.
    // Note also that the built-in pull-ups on the Atmel ATSAM3X8 are too weak (between 50 and 100 KOhm,
    // yields too slow a rising time) to be of any use.

    const bool oldPullUps = GetJtagPullups();
    SetJtagPullups( false );

    const JtagPinModeEnum oldMode = GetJtagPinMode();
    SetJtagPinMode ( MODE_JTAG );


    // Each JTAG transfer needs 2 bits in the Rx buffer, TMS and TDI,
    // but produces only 1 bit, TDO.
    const uint32_t jtagByteCount = m_rxBuffer->GetElemCount() / 2;

    const uint16_t bitCount = jtagByteCount * 8;

    // Shift all JTAG data through several times.

    const uint64_t startTime = GetUptime();
    const uint32_t iterCount = 50;

    for ( uint32_t i = 0; i < iterCount; ++i )
    {
      // We hope that this will not clear the buffer contents.
      assert( m_rxBuffer != NULL );
      assert( m_txBuffer != NULL );

      m_rxBuffer->Reset();
      m_rxBuffer->CommitWrittenElements( jtagByteCount * 2 );

      m_txBuffer->Reset();

      ShiftJtagData( m_rxBuffer,
                     m_txBuffer,
                     bitCount );

      assert( m_txBuffer->GetElemCount() == jtagByteCount );
    }

    const uint64_t finishTime = GetUptime();
    const uint32_t elapsedTime = uint32_t( finishTime - startTime );

    m_rxBuffer->Reset();
    m_txBuffer->Reset();
    const unsigned kBitsPerSec = unsigned( uint64_t(bitCount) * iterCount * 1000 / elapsedTime / 1024 );

    SetJtagPinMode( oldMode );
    SetJtagPullups( oldPullUps );

    // I am getting 221 KiB/s with GCC 4.7.3 and optimisation level "-O3".
    Printf( EOL "Finished JTAG shift speed test, throughput %u Kbits/s (%u KiB/s)." EOL,
               kBitsPerSec, kBitsPerSec / 8 );

    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_MALLOCTEST, false, false, &extraParamsFound ) )
  {
    PrintStr( "Allocalling memory..." EOL );

    volatile uint32_t * const volatile mallocTest = (volatile uint32_t *) malloc(123);
    *mallocTest = 123;

    PrintStr( "Releasing memory..." EOL );

    free( const_cast< uint32_t * >( mallocTest ) );

    PrintStr( "Test finished." EOL );

    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_CPP_EXCEPTION_TEST, false, false, &extraParamsFound ) )
  {
    try
    {
      PrintStr( "Throwing integer exception..." EOL );
      throw 123;
      PrintStr( "Throw did not work." EOL );
      assert( false );
    }
    catch ( ... )
    {
      PrintStr( "Caught integer exception." EOL );
    }
    PrintStr( "Test finished." EOL );

    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_SIMULATE_ERROR, false, true, &extraParamsFound ) )
  {
    SimulateError( paramBegin );
    return;
  }


  if ( IsCmd( cmdBegin, cmdEnd, CMDNAME_MEMORY_USAGE, false, false, &extraParamsFound ) )
  {
    const unsigned heapSize = unsigned( GetHeapEndAddr() - uintptr_t( &_end ) );

    Printf( "Partitions: malloc heap: %u bytes, free: %u bytes, stack: %u bytes." EOL,
               heapSize,
               GetStackStartAddr() - GetHeapEndAddr(),
               STACK_SIZE );

    Printf( "Used stack (estimated): %u from %u bytes." EOL,
               unsigned( GetStackSizeUsageEstimate() ),
               STACK_SIZE );

    const struct mallinfo mi = mallinfo();
    const unsigned heapSizeAccordingToNewlib = unsigned( mi.arena );

    Printf( "Heap: %u allocated from %u bytes." EOL,
               unsigned( mi.uordblks ),
               unsigned( mi.arena ) );

    assert( heapSize == heapSizeAccordingToNewlib );
    UNUSED_IN_RELEASE( heapSizeAccordingToNewlib );

    return;
  }

  if ( extraParamsFound )
    Printf( "Command \"%.*s\" does not take any parameters." EOL, cmdEnd - cmdBegin, cmdBegin );
  else
    Printf( "Unknown command \"%.*s\"." EOL, cmdEnd - cmdBegin, cmdBegin );
}