Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 228 → Rev 229

/bioloid/cli/SerialBus.h
1,120 → 1,120
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.h
*
* @brief Implements a bioloid bus using posix serial. This typically
* assumes that an FTDI USB-to-serial adapter is being used
* to do the RS-485 management.
*
****************************************************************************/
 
#if !defined( SERIALBUS_H )
#define SERIALBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
#include "SerialPort.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SerialBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
SerialBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SerialBus();
 
//------------------------------------------------------------------------
// Sets the serial port which will be used for communications
 
void SetSerialPort( SerialPort *serPort );
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Reads a packet. Returns true if a packet was read successfully,
// false if a timeout or error occurred.
 
virtual bool ReadStatusPacket( BioloidPacket *pkt );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
//------------------------------------------------------------------------
// Send the checksum. Since the checksum byte is the last byte of the
// packet, this function is made virtual to allow bus drivers to
// buffer the packet bytes until the entire packet is ready to send.
 
virtual void SendCheckSum();
 
//------------------------------------------------------------------------
// Sends the command header, which is common to all of the commands.
// 2 is added to paramLen (to cover the length and cmd bytes). This
// way the caller is only responsible for figuring out how many extra
// parameter bytes are being sent.
 
virtual void SendCmdHeader( Bioloid::ID_t id, uint8_t paramLen, Bioloid::Command cmd );
 
//------------------------------------------------------------------------
// Sets the debug mode
 
void SetDebug( bool debug ) { m_debug = debug; }
 
private:
 
//------------------------------------------------------------------------
// Adds a byte to the buffer of data to send.
 
void BufferByte( uint8_t data );
 
//------------------------------------------------------------------------
// Writes all of the buffered bytes to the serial port.
 
void WriteBuffer();
 
//------------------------------------------------------------------------
 
SerialPort *m_serialPort;
 
bool m_debug;
 
int m_fd;
int m_dataBytes;
uint8_t m_data[ 128 ];
 
};
 
/** @} */
 
#endif /* SERIALBUS_H */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.h
*
* @brief Implements a bioloid bus using posix serial. This typically
* assumes that an FTDI USB-to-serial adapter is being used
* to do the RS-485 management.
*
****************************************************************************/
 
#if !defined( SERIALBUS_H )
#define SERIALBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
#include "SerialPort.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SerialBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
SerialBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SerialBus();
 
//------------------------------------------------------------------------
// Sets the serial port which will be used for communications
 
void SetSerialPort( SerialPort *serPort );
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Reads a packet. Returns true if a packet was read successfully,
// false if a timeout or error occurred.
 
virtual bool ReadStatusPacket( BioloidPacket *pkt );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
//------------------------------------------------------------------------
// Send the checksum. Since the checksum byte is the last byte of the
// packet, this function is made virtual to allow bus drivers to
// buffer the packet bytes until the entire packet is ready to send.
 
virtual void SendCheckSum();
 
//------------------------------------------------------------------------
// Sends the command header, which is common to all of the commands.
// 2 is added to paramLen (to cover the length and cmd bytes). This
// way the caller is only responsible for figuring out how many extra
// parameter bytes are being sent.
 
virtual void SendCmdHeader( Bioloid::ID_t id, uint8_t paramLen, Bioloid::Command cmd );
 
//------------------------------------------------------------------------
// Sets the debug mode
 
void SetDebug( bool debug ) { m_debug = debug; }
 
private:
 
//------------------------------------------------------------------------
// Adds a byte to the buffer of data to send.
 
void BufferByte( uint8_t data );
 
//------------------------------------------------------------------------
// Writes all of the buffered bytes to the serial port.
 
void WriteBuffer();
 
//------------------------------------------------------------------------
 
SerialPort *m_serialPort;
 
bool m_debug;
 
int m_fd;
int m_dataBytes;
uint8_t m_data[ 128 ];
 
};
 
/** @} */
 
#endif /* SERIALBUS_H */
 
/bioloid/cli/NetBus.cpp
1,418 → 1,418
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file NetBus.cpp
*
* @brief This file implements the NetBus class, which talks to the
* bioloid bus using a network interface.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "DumpMem.h"
#include "NetBus.h"
#include "Str.h"
#include "StrToken.h"
#include "Error.h"
 
#if defined( WIN32 )
#include <WinSock2.h>
#endif
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
NetBus::NetBus()
: m_dataBytes( 0 ),
m_debug( false ),
m_initialized( false )
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
NetBus::~NetBus()
{
}
 
//***************************************************************************
/**
* Adds a byte to the buffer of data to send.
*/
 
void NetBus::BufferByte( uint8_t data )
{
m_data[ m_dataBytes++ ] = data;
 
if ( m_dataBytes >= sizeof( m_data ))
{
WriteBuffer();
}
}
 
//***************************************************************************
/**
* Sets the serial port that will be used for talking with the bioloid
* devices.
*/
 
bool NetBus::Open( const char *hostStr )
{
uint32_t err;
char errStr[ 200 ];
 
if ( !m_initialized )
{
#if defined( WIN32 )
WSADATA wsaData;
 
if (( err = WSAStartup( 0x0202, &wsaData )) != 0 )
{
LogError( "Error initializing Windows Sockets: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
#endif
m_initialized = true;
}
 
char *endPtr;
 
// Extract the hostname and portname.
 
char token[ 200 ];
 
char *hostName = NULL;
 
// NextToken parses skips leading delimiters
 
if ( *hostStr == ':' )
{
hostName = "";
hostStr++;
}
 
// If it's all digits, then assume it's a port number
 
if ( strspn( hostStr, "0123456789" ) == strlen( hostStr ))
{
hostName = "";
}
 
StrTokenizer tokenizer( hostStr, token, sizeof( token ));
 
if ( hostName == NULL )
{
hostName = tokenizer.NextToken( ":" );
}
 
if ( hostName == NULL )
{
LogError( "No hostname specified" );
return false;
}
 
// Check to see if the servername is only made up of numbers and dots.
 
if ( strspn( hostName, ".0123456789" ) == strlen( hostName ))
{
int seg;
char *segStr = hostName;
char *endPtr;
 
// The hostname is only made up of numbers and dots. We'll parse
// it ourselves.
//
// We expect it to be of the form a.b.c.d, where a, b, c, and d are
// all positive integers in the range 0 thru 255.
 
for ( seg = 0; seg < 4; seg++ )
{
long longByte = strtol( segStr, &endPtr, 10 );
 
if (( longByte < 0 ) || ( longByte > 255 ))
{
LogError( "Expecting a positive number between 0 and 255, found: '%s'\n", segStr );
return false;
}
if (( endPtr == segStr )
|| (( *endPtr == '.' ) && ( seg == 3 ))
|| (( *endPtr != '.' ) && ( seg < 3 )))
{
LogError( "Expecting IP address of the form a.b.c.d, found: '%s'\n", hostName );
return false;
}
 
m_sockAddr.sin_addr.S_un.S_addr <<= 8;
m_sockAddr.sin_addr.S_un.S_addr += (unsigned char)longByte;
 
segStr = endPtr + 1;
}
m_sockAddr.sin_addr.S_un.S_addr = htonl( m_sockAddr.sin_addr.S_un.S_addr );
}
else
{
// The server name was specified symbolically, see if we can translate it
 
struct hostent *hostent;
 
hostent = gethostbyname( hostName );
if ( hostent == NULL )
{
LogError( "Unable to translate hostname '%s' into an IP address.\n", hostName );
return false;
}
m_sockAddr.sin_addr.S_un.S_addr = *((long *)hostent->h_addr_list[ 0 ]);
}
 
// Now parse the port (if present)
 
const char *portStr = tokenizer.Remainder();
 
if ( *portStr == '\0' )
{
// No port specified
 
m_sockAddr.sin_port = htons( m_defaultPort );
}
else
{
long longPort;
 
if ( strspn( portStr, "0123456789" ) == strlen( portStr ))
{
// The port string is all numeric
 
longPort = strtol( portStr, &endPtr, 0 );
if ( *endPtr != '\0' )
{
LogError( "Expecting a positive numeric port specifier; Found '%s'.\n", portStr );
return false;
}
}
else
{
struct servent *servent;
 
servent = getservbyname( portStr, "tcp" );
if ( servent == NULL )
{
LogError( "Unable to translate service '%s' into a port number.", portStr );
return false;
}
longPort = ntohs( servent->s_port );
}
 
if (( longPort <= 0 ) || ( longPort > 65535 ))
{
LogError( "Expecting port to be between 1 and 65535; Found: %ld\n", longPort );
return false;
}
m_sockAddr.sin_port = htons( (short)longPort );
}
m_sockAddr.sin_family = AF_INET;
 
// We now have an IP address and port number
 
// Open a socket
 
m_socket = socket( AF_INET, SOCK_STREAM, 0 );
if ( m_socket == INVALID_SOCKET )
{
err = WSAGetLastError();
LogError( "Error calling socket: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
 
// Connect to the server
 
if ( connect( m_socket, (struct sockaddr *)&m_sockAddr, sizeof( m_sockAddr )) != 0 )
{
err = WSAGetLastError();
LogError( "Error calling connect: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
 
StrPrintf( m_connectionInfo, sizeof( m_connectionInfo ),
"%s (%d.%d.%d.%d:%d)", hostStr,
m_sockAddr.sin_addr.S_un.S_un_b.s_b1,
m_sockAddr.sin_addr.S_un.S_un_b.s_b2,
m_sockAddr.sin_addr.S_un.S_un_b.s_b3,
m_sockAddr.sin_addr.S_un.S_un_b.s_b4,
ntohs( m_sockAddr.sin_port ));
 
Log( "Connected to %s\n", m_connectionInfo );
}
 
//***************************************************************************
/**
* Writes all of the buffered bytes to the serial port.
*/
 
void NetBus::WriteBuffer()
{
size_t bytesWritten;
 
if ( m_debug )
{
DumpMem( "W", 0, m_data, m_dataBytes );
}
 
#if 0
if (( bytesWritten = m_serialPort->Write( m_data, m_dataBytes )) != m_dataBytes )
{
LogError( "Error writing %d bytes to serial port", m_dataBytes );
}
#endif
 
m_dataBytes = 0;
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool NetBus::ReadByte( uint8_t *ch )
{
bool rc;
 
#if 1
rc = true;
#else
rc = m_serialPort->Read( ch, 1 ) == 1;
#endif
 
if ( rc )
{
if ( m_dataBytes < sizeof( m_data ))
{
m_data[ m_dataBytes++ ] = *ch;
}
}
 
return rc;
}
 
//***************************************************************************
/**
* Reads a packet. Returns true if a packet was read successfully,
* false if a timeout or error occurred.
*
* virtual
*/
 
bool NetBus::ReadStatusPacket( BioloidPacket *pkt )
{
bool rc;
 
m_dataBytes = 0;
 
rc = BioloidBus::ReadStatusPacket( pkt );
 
if ( m_debug )
{
if ( m_dataBytes > 0 )
{
DumpMem( "R", 0, m_data, m_dataBytes );
}
#if 0
if ( !rc )
{
LogError( "Packet Error\n" );
}
#endif
}
 
return rc;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void NetBus::SendByte( uint8_t data )
{
m_checksum += data;
 
BufferByte( data );
}
 
//***************************************************************************
/**
* Send the checksum. Since the checksum byte is the last byte of the
* packet, this function is made virtual to allow bus drivers to
* buffer the packet bytes until the entire packet is ready to send.
*
* virtual
*/
 
void NetBus::SendCheckSum()
{
SendByte( ~m_checksum );
 
WriteBuffer();
}
 
//***************************************************************************
/**
* Sends the command header, which is common to all of the commands.
* 2 is added to paramLen (to cover the length and cmd bytes). This
* way the caller is only responsible for figuring out how many extra
* parameter bytes are being sent.
*
* virtual
*/
 
void NetBus::SendCmdHeader
(
Bioloid::ID_t id,
uint8_t paramLen,
Bioloid::Command cmd
)
{
m_dataBytes = 0;
 
BioloidBus::SendCmdHeader( id, paramLen, cmd );
}
 
/** @} */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file NetBus.cpp
*
* @brief This file implements the NetBus class, which talks to the
* bioloid bus using a network interface.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "DumpMem.h"
#include "NetBus.h"
#include "Str.h"
#include "StrToken.h"
#include "Error.h"
 
#if defined( WIN32 )
#include <WinSock2.h>
#endif
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
NetBus::NetBus()
: m_dataBytes( 0 ),
m_debug( false ),
m_initialized( false )
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
NetBus::~NetBus()
{
}
 
//***************************************************************************
/**
* Adds a byte to the buffer of data to send.
*/
 
void NetBus::BufferByte( uint8_t data )
{
m_data[ m_dataBytes++ ] = data;
 
if ( m_dataBytes >= sizeof( m_data ))
{
WriteBuffer();
}
}
 
//***************************************************************************
/**
* Sets the serial port that will be used for talking with the bioloid
* devices.
*/
 
bool NetBus::Open( const char *hostStr )
{
uint32_t err;
char errStr[ 200 ];
 
if ( !m_initialized )
{
#if defined( WIN32 )
WSADATA wsaData;
 
if (( err = WSAStartup( 0x0202, &wsaData )) != 0 )
{
LogError( "Error initializing Windows Sockets: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
#endif
m_initialized = true;
}
 
char *endPtr;
 
// Extract the hostname and portname.
 
char token[ 200 ];
 
char *hostName = NULL;
 
// NextToken parses skips leading delimiters
 
if ( *hostStr == ':' )
{
hostName = "";
hostStr++;
}
 
// If it's all digits, then assume it's a port number
 
if ( strspn( hostStr, "0123456789" ) == strlen( hostStr ))
{
hostName = "";
}
 
StrTokenizer tokenizer( hostStr, token, sizeof( token ));
 
if ( hostName == NULL )
{
hostName = tokenizer.NextToken( ":" );
}
 
if ( hostName == NULL )
{
LogError( "No hostname specified" );
return false;
}
 
// Check to see if the servername is only made up of numbers and dots.
 
if ( strspn( hostName, ".0123456789" ) == strlen( hostName ))
{
int seg;
char *segStr = hostName;
char *endPtr;
 
// The hostname is only made up of numbers and dots. We'll parse
// it ourselves.
//
// We expect it to be of the form a.b.c.d, where a, b, c, and d are
// all positive integers in the range 0 thru 255.
 
for ( seg = 0; seg < 4; seg++ )
{
long longByte = strtol( segStr, &endPtr, 10 );
 
if (( longByte < 0 ) || ( longByte > 255 ))
{
LogError( "Expecting a positive number between 0 and 255, found: '%s'\n", segStr );
return false;
}
if (( endPtr == segStr )
|| (( *endPtr == '.' ) && ( seg == 3 ))
|| (( *endPtr != '.' ) && ( seg < 3 )))
{
LogError( "Expecting IP address of the form a.b.c.d, found: '%s'\n", hostName );
return false;
}
 
m_sockAddr.sin_addr.S_un.S_addr <<= 8;
m_sockAddr.sin_addr.S_un.S_addr += (unsigned char)longByte;
 
segStr = endPtr + 1;
}
m_sockAddr.sin_addr.S_un.S_addr = htonl( m_sockAddr.sin_addr.S_un.S_addr );
}
else
{
// The server name was specified symbolically, see if we can translate it
 
struct hostent *hostent;
 
hostent = gethostbyname( hostName );
if ( hostent == NULL )
{
LogError( "Unable to translate hostname '%s' into an IP address.\n", hostName );
return false;
}
m_sockAddr.sin_addr.S_un.S_addr = *((long *)hostent->h_addr_list[ 0 ]);
}
 
// Now parse the port (if present)
 
const char *portStr = tokenizer.Remainder();
 
if ( *portStr == '\0' )
{
// No port specified
 
m_sockAddr.sin_port = htons( m_defaultPort );
}
else
{
long longPort;
 
if ( strspn( portStr, "0123456789" ) == strlen( portStr ))
{
// The port string is all numeric
 
longPort = strtol( portStr, &endPtr, 0 );
if ( *endPtr != '\0' )
{
LogError( "Expecting a positive numeric port specifier; Found '%s'.\n", portStr );
return false;
}
}
else
{
struct servent *servent;
 
servent = getservbyname( portStr, "tcp" );
if ( servent == NULL )
{
LogError( "Unable to translate service '%s' into a port number.", portStr );
return false;
}
longPort = ntohs( servent->s_port );
}
 
if (( longPort <= 0 ) || ( longPort > 65535 ))
{
LogError( "Expecting port to be between 1 and 65535; Found: %ld\n", longPort );
return false;
}
m_sockAddr.sin_port = htons( (short)longPort );
}
m_sockAddr.sin_family = AF_INET;
 
// We now have an IP address and port number
 
// Open a socket
 
m_socket = socket( AF_INET, SOCK_STREAM, 0 );
if ( m_socket == INVALID_SOCKET )
{
err = WSAGetLastError();
LogError( "Error calling socket: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
 
// Connect to the server
 
if ( connect( m_socket, (struct sockaddr *)&m_sockAddr, sizeof( m_sockAddr )) != 0 )
{
err = WSAGetLastError();
LogError( "Error calling connect: %s\n", GetErrorStr( err, errStr, sizeof( errStr )));
return false;
}
 
StrPrintf( m_connectionInfo, sizeof( m_connectionInfo ),
"%s (%d.%d.%d.%d:%d)", hostStr,
m_sockAddr.sin_addr.S_un.S_un_b.s_b1,
m_sockAddr.sin_addr.S_un.S_un_b.s_b2,
m_sockAddr.sin_addr.S_un.S_un_b.s_b3,
m_sockAddr.sin_addr.S_un.S_un_b.s_b4,
ntohs( m_sockAddr.sin_port ));
 
Log( "Connected to %s\n", m_connectionInfo );
}
 
//***************************************************************************
/**
* Writes all of the buffered bytes to the serial port.
*/
 
void NetBus::WriteBuffer()
{
size_t bytesWritten;
 
if ( m_debug )
{
DumpMem( "W", 0, m_data, m_dataBytes );
}
 
#if 0
if (( bytesWritten = m_serialPort->Write( m_data, m_dataBytes )) != m_dataBytes )
{
LogError( "Error writing %d bytes to serial port", m_dataBytes );
}
#endif
 
m_dataBytes = 0;
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool NetBus::ReadByte( uint8_t *ch )
{
bool rc;
 
#if 1
rc = true;
#else
rc = m_serialPort->Read( ch, 1 ) == 1;
#endif
 
if ( rc )
{
if ( m_dataBytes < sizeof( m_data ))
{
m_data[ m_dataBytes++ ] = *ch;
}
}
 
return rc;
}
 
//***************************************************************************
/**
* Reads a packet. Returns true if a packet was read successfully,
* false if a timeout or error occurred.
*
* virtual
*/
 
bool NetBus::ReadStatusPacket( BioloidPacket *pkt )
{
bool rc;
 
m_dataBytes = 0;
 
rc = BioloidBus::ReadStatusPacket( pkt );
 
if ( m_debug )
{
if ( m_dataBytes > 0 )
{
DumpMem( "R", 0, m_data, m_dataBytes );
}
#if 0
if ( !rc )
{
LogError( "Packet Error\n" );
}
#endif
}
 
return rc;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void NetBus::SendByte( uint8_t data )
{
m_checksum += data;
 
BufferByte( data );
}
 
//***************************************************************************
/**
* Send the checksum. Since the checksum byte is the last byte of the
* packet, this function is made virtual to allow bus drivers to
* buffer the packet bytes until the entire packet is ready to send.
*
* virtual
*/
 
void NetBus::SendCheckSum()
{
SendByte( ~m_checksum );
 
WriteBuffer();
}
 
//***************************************************************************
/**
* Sends the command header, which is common to all of the commands.
* 2 is added to paramLen (to cover the length and cmd bytes). This
* way the caller is only responsible for figuring out how many extra
* parameter bytes are being sent.
*
* virtual
*/
 
void NetBus::SendCmdHeader
(
Bioloid::ID_t id,
uint8_t paramLen,
Bioloid::Command cmd
)
{
m_dataBytes = 0;
 
BioloidBus::SendCmdHeader( id, paramLen, cmd );
}
 
/** @} */
 
/bioloid/cli/SimBus.cpp
1,88 → 1,88
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.cpp
*
* @brief This file implements the SimBus class, which is a simulated
* bioloid bus, that just prints out the contents of the packets received.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "SimBus.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SimBus::SimBus()
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SimBus::~SimBus()
{
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool SimBus::ReadByte( uint8_t *ch )
{
return false;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void SimBus::SendByte( uint8_t data )
{
m_checksum += data;
 
m_packet.ProcessChar( data );
}
 
/** @} */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.cpp
*
* @brief This file implements the SimBus class, which is a simulated
* bioloid bus, that just prints out the contents of the packets received.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "SimBus.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SimBus::SimBus()
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SimBus::~SimBus()
{
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool SimBus::ReadByte( uint8_t *ch )
{
return false;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void SimBus::SendByte( uint8_t data )
{
m_checksum += data;
 
m_packet.ProcessChar( data );
}
 
/** @} */
 
/bioloid/cli/DevTypeParser.h
1,67 → 1,67
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file DevTypeParser.h
*
* @brief Implements a parser for parsing device type files.
*
****************************************************************************/
 
#if !defined( DEVTYPEPARSER_H )
#define DEVTYPEPARSER_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include <stdio.h>
 
#include "Log.h"
#include "bioloid-reg.h"
#include "StrToken.h"
 
// ---- Class Declarations --------------------------------------------------
 
class DevTypeParser
{
public:
DevTypeParser();
 
~DevTypeParser();
 
typedef void (*AddDevTypeFunc)( BLD_DevType_t *devType );
 
bool ParseFile( const char *fileName, AddDevTypeFunc addDevTypeFunc );
 
private:
 
bool ParseLine();
bool ParseRegister( BLD_Reg_t *reg );
 
FILE *m_fs;
BLD_DevType_t *m_devType;
const char *m_fileName;
char m_lineBuf[ 200 ];
char m_token[ 20 ];
StrTokenizer m_line;
unsigned m_lineNum;
 
unsigned m_allocRegs;
 
AddDevTypeFunc m_addDevTypeFunc;
};
 
 
#endif // DEVTYPEPARSER_H
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file DevTypeParser.h
*
* @brief Implements a parser for parsing device type files.
*
****************************************************************************/
 
#if !defined( DEVTYPEPARSER_H )
#define DEVTYPEPARSER_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include <stdio.h>
 
#include "Log.h"
#include "bioloid-reg.h"
#include "StrToken.h"
 
// ---- Class Declarations --------------------------------------------------
 
class DevTypeParser
{
public:
DevTypeParser();
 
~DevTypeParser();
 
typedef void (*AddDevTypeFunc)( BLD_DevType_t *devType );
 
bool ParseFile( const char *fileName, AddDevTypeFunc addDevTypeFunc );
 
private:
 
bool ParseLine();
bool ParseRegister( BLD_Reg_t *reg );
 
FILE *m_fs;
BLD_DevType_t *m_devType;
const char *m_fileName;
char m_lineBuf[ 200 ];
char m_token[ 20 ];
StrTokenizer m_line;
unsigned m_lineNum;
 
unsigned m_allocRegs;
 
AddDevTypeFunc m_addDevTypeFunc;
};
 
 
#endif // DEVTYPEPARSER_H
 
/bioloid/cli/NetBus.h
1,125 → 1,125
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.h
*
* @brief Implements a bioloid bus using posix serial. This typically
* assumes that an FTDI USB-to-serial adapter is being used
* to do the RS-485 management.
*
****************************************************************************/
 
#if !defined( NETBUS_H )
#define NETBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
 
#if defined( WIN32 )
#include <windows.h>
#endif
 
/**
* @addtogroup bioloid
* @{
*/
 
class NetBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
NetBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~NetBus();
 
//------------------------------------------------------------------------
// Sets the serial port which will be used for communications
 
bool Open( const char *hostStr );
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Reads a packet. Returns true if a packet was read successfully,
// false if a timeout or error occurred.
 
virtual bool ReadStatusPacket( BioloidPacket *pkt );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
//------------------------------------------------------------------------
// Send the checksum. Since the checksum byte is the last byte of the
// packet, this function is made virtual to allow bus drivers to
// buffer the packet bytes until the entire packet is ready to send.
 
virtual void SendCheckSum();
 
//------------------------------------------------------------------------
// Sends the command header, which is common to all of the commands.
// 2 is added to paramLen (to cover the length and cmd bytes). This
// way the caller is only responsible for figuring out how many extra
// parameter bytes are being sent.
 
virtual void SendCmdHeader( Bioloid::ID_t id, uint8_t paramLen, Bioloid::Command cmd );
 
//------------------------------------------------------------------------
// Sets the debug mode
 
void SetDebug( bool debug ) { m_debug = debug; }
 
private:
 
//------------------------------------------------------------------------
// Adds a byte to the buffer of data to send.
 
void BufferByte( uint8_t data );
 
//------------------------------------------------------------------------
// Writes all of the buffered bytes to the serial port.
 
void WriteBuffer();
 
//------------------------------------------------------------------------
 
bool m_debug;
 
bool m_initialized;
 
int m_socket; ///< Socket handle
int m_dataBytes;
uint8_t m_data[ 128 ];
unsigned short m_defaultPort; ///< Default Port number (if none specified)
struct sockaddr_in m_sockAddr; ///< Socket address for the remote end
char m_connectionInfo[ 100 ]; ///< Describes the hostname etc.
};
 
/** @} */
 
#endif /* NETBUS_H */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.h
*
* @brief Implements a bioloid bus using posix serial. This typically
* assumes that an FTDI USB-to-serial adapter is being used
* to do the RS-485 management.
*
****************************************************************************/
 
#if !defined( NETBUS_H )
#define NETBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
 
#if defined( WIN32 )
#include <windows.h>
#endif
 
/**
* @addtogroup bioloid
* @{
*/
 
class NetBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
NetBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~NetBus();
 
//------------------------------------------------------------------------
// Sets the serial port which will be used for communications
 
bool Open( const char *hostStr );
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Reads a packet. Returns true if a packet was read successfully,
// false if a timeout or error occurred.
 
virtual bool ReadStatusPacket( BioloidPacket *pkt );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
//------------------------------------------------------------------------
// Send the checksum. Since the checksum byte is the last byte of the
// packet, this function is made virtual to allow bus drivers to
// buffer the packet bytes until the entire packet is ready to send.
 
virtual void SendCheckSum();
 
//------------------------------------------------------------------------
// Sends the command header, which is common to all of the commands.
// 2 is added to paramLen (to cover the length and cmd bytes). This
// way the caller is only responsible for figuring out how many extra
// parameter bytes are being sent.
 
virtual void SendCmdHeader( Bioloid::ID_t id, uint8_t paramLen, Bioloid::Command cmd );
 
//------------------------------------------------------------------------
// Sets the debug mode
 
void SetDebug( bool debug ) { m_debug = debug; }
 
private:
 
//------------------------------------------------------------------------
// Adds a byte to the buffer of data to send.
 
void BufferByte( uint8_t data );
 
//------------------------------------------------------------------------
// Writes all of the buffered bytes to the serial port.
 
void WriteBuffer();
 
//------------------------------------------------------------------------
 
bool m_debug;
 
bool m_initialized;
 
int m_socket; ///< Socket handle
int m_dataBytes;
uint8_t m_data[ 128 ];
unsigned short m_defaultPort; ///< Default Port number (if none specified)
struct sockaddr_in m_sockAddr; ///< Socket address for the remote end
char m_connectionInfo[ 100 ]; ///< Describes the hostname etc.
};
 
/** @} */
 
#endif /* NETBUS_H */
 
/bioloid/cli/SimBus.h
1,73 → 1,73
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.h
*
* @brief Implements a simulated bioloid bus which is useful for some
* types of debugging.
*
* The simulated bus prints out all of the packets that would be
* sent over the bus.
*
****************************************************************************/
 
#if !defined( SIMBUS_H )
#define SIMBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
#include "SimPacket.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SimBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
SimBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SimBus();
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
private:
 
SimPacket m_packet;
 
};
 
/** @} */
 
#endif /* SIMBUS_H */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.h
*
* @brief Implements a simulated bioloid bus which is useful for some
* types of debugging.
*
* The simulated bus prints out all of the packets that would be
* sent over the bus.
*
****************************************************************************/
 
#if !defined( SIMBUS_H )
#define SIMBUS_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidBus.h"
#include "SimPacket.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SimBus : public BioloidBus
{
public:
//------------------------------------------------------------------------
// Default constructor
 
SimBus();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SimBus();
 
//------------------------------------------------------------------------
// Reads a byte.
 
virtual bool ReadByte( uint8_t *ch );
 
//------------------------------------------------------------------------
// Sends a byte. This will automatically accumulate the byte into
// the checksum
 
virtual void SendByte( uint8_t data );
 
private:
 
SimPacket m_packet;
 
};
 
/** @} */
 
#endif /* SIMBUS_H */
 
/bioloid/cli/Config.h
1,39 → 1,39
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file Config.h
*
* @brief Global Configuration information.
*
****************************************************************************/
 
#if !defined( CONFIG_H )
#define CONFIG_H /**< Include Guard */
 
/* ---- Include Files ---------------------------------------------------- */
 
/* ---- Constants and Types ---------------------------------------------- */
 
/**
* Sets Logging parameters
*/
 
#define CFG_LOG_TO_BUFFER 0
 
/** @} */
 
#endif // CONFIG_H
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file Config.h
*
* @brief Global Configuration information.
*
****************************************************************************/
 
#if !defined( CONFIG_H )
#define CONFIG_H /**< Include Guard */
 
/* ---- Include Files ---------------------------------------------------- */
 
/* ---- Constants and Types ---------------------------------------------- */
 
/**
* Sets Logging parameters
*/
 
#define CFG_LOG_TO_BUFFER 0
 
/** @} */
 
#endif // CONFIG_H
 
/bioloid/cli/SimPacket.cpp
1,96 → 1,96
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimPacket.cpp
*
* @brief This file implements the SimPacket class. The PacketReceived
* method will be called whenever a packet is sent and it will
* print the contents of the packet.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "SimPacket.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SimPacket::SimPacket()
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SimPacket::~SimPacket()
{
}
 
//***************************************************************************
/**
* Called to run a character through the packet processor. We log the
* character.
*
* virtual
*/
 
void SimPacket::ProcessChar( uint8_t ch )
{
Log( "%02x ", ch );
 
BioloidPacket::ProcessChar( ch );
}
 
//***************************************************************************
/**
* Called when a packet is parsed.
*
* virtual
*/
 
void SimPacket::PacketReceived( Bioloid::Error err )
{
if ( err == Bioloid::ERROR_NONE )
{
Log( "good\n" );
}
else
{
Log( "*** ERROR ***\n" );
}
}
 
/** @} */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimPacket.cpp
*
* @brief This file implements the SimPacket class. The PacketReceived
* method will be called whenever a packet is sent and it will
* print the contents of the packet.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "SimPacket.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SimPacket::SimPacket()
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SimPacket::~SimPacket()
{
}
 
//***************************************************************************
/**
* Called to run a character through the packet processor. We log the
* character.
*
* virtual
*/
 
void SimPacket::ProcessChar( uint8_t ch )
{
Log( "%02x ", ch );
 
BioloidPacket::ProcessChar( ch );
}
 
//***************************************************************************
/**
* Called when a packet is parsed.
*
* virtual
*/
 
void SimPacket::PacketReceived( Bioloid::Error err )
{
if ( err == Bioloid::ERROR_NONE )
{
Log( "good\n" );
}
else
{
Log( "*** ERROR ***\n" );
}
}
 
/** @} */
 
/bioloid/cli/bioloid.cpp
1,395 → 1,395
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file bioloid.cpp
*
* @brief Implements a PC version of the bioloid command line interface
* which allows bioloid commands to be sent to either a real
* bioloid bus, or a simulated one.
*
****************************************************************************/
 
#if defined( AVR )
#define USE_COMMAND_LINE 0
#define USE_NETBUS 0
#else
#define USE_COMMAND_LINE 1
#define USE_NETBUS 1
#endif
 
// ---- Include Files -------------------------------------------------------
 
#include <stdio.h>
#include <stdlib.h>
 
#if USE_COMMAND_LINE
#include <getopt.h>
#endif
 
#include <libgen.h>
 
#include "Log.h"
#include "BioloidBus.h"
#include "BioloidDevice.h"
#include "BioloidCommandLine.h"
#include "bioloid-reg-servo.h"
#include "SerialPort.h"
#include "SerialBus.h"
#include "DevTypeParser.h"
 
#if USE_NETBUS
# include "NetBus.h"
#endif
 
#if defined( WIN32 )
# include <windows.h>
#else
# include <fnmatch.h>
# include <dirent.h>
#endif
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
 
#define DEFAULT_BAUD "1000000"
 
#if defined( linux )
# define DEFAULT_PORT "ttyUSB0"
#else
# define DEFAULT_PORT "com1"
#endif
 
// ---- Private Variables ---------------------------------------------------
 
enum
{
// Options assigned a single character code can use that charater code
// as a short option.
 
OPT_BAUD = 'b',
OPT_DEBUG = 'd',
OPT_PORT = 'p',
OPT_NET = 'n',
OPT_VERBOSE = 'v',
OPT_HELP = 'h',
 
// Options from this point onwards don't have any short option equivalents
 
OPT_FIRST_LONG_OPT = 0x80,
 
};
 
#if USE_COMMAND_LINE
static struct option gOption[] =
{
{ "baud", required_argument, NULL, OPT_BAUD },
{ "debug", no_argument, NULL, OPT_DEBUG },
{ "help", no_argument, NULL, OPT_HELP },
{ "port", required_argument, NULL, OPT_PORT },
{ "net", required_argument, NULL, OPT_NET },
{ "verbose", no_argument, NULL, OPT_VERBOSE },
{ NULL }
};
#endif
 
SerialPort gSerialPort;
SerialBus gSerialBus;
 
bool gUseSerial = false;
 
#if USE_NETBUS
NetBus gNetBus;
bool gUseNet = false;
#endif
 
#define MAX_DEV_TYPES 20
 
static unsigned gNumDevTypes;
static BLD_DevType_t *gDevType[ MAX_DEV_TYPES ];
 
// ---- Private Function Prototypes -----------------------------------------
 
// ---- Functions -----------------------------------------------------------
 
/***************************************************************************/
/**
* Adds a device type to the list of device types that we know about.
*/
void AddDevType( BLD_DevType_t *devType )
{
int devTypeIdx;
 
if ( gNumDevTypes >= MAX_DEV_TYPES )
{
LogError( "Too many device types (max of %d)\n", MAX_DEV_TYPES );
return;
}
 
// Make sure this isn't a duplicate
 
for ( devTypeIdx = 0; devTypeIdx < gNumDevTypes; devTypeIdx++ )
{
if ( stricmp( gDevType[ devTypeIdx ]->devTypeStr, devType->devTypeStr ) == 0 )
{
LogError( "Device Type '%s' already registered\n", devType->devTypeStr );
return;
}
}
 
// Not a device type we know about - add it to the list
 
gDevType[ gNumDevTypes ] = devType;
gNumDevTypes++;
}
 
/***************************************************************************/
/**
* Read device types and registers
*/
 
bool ReadRegisterFiles( const char *exeDir )
{
#if defined( __WIN32__ )
HANDLE dir;
WIN32_FIND_DATA fd;
char pathName[ MAX_PATH ];
 
_makepath( pathName, "", exeDir, "reg-*", "bld" );
 
if (( dir = FindFirstFile( pathName, &fd )) != INVALID_HANDLE_VALUE )
{
do
{
DevTypeParser dtp;
 
if ( !dtp.ParseFile( fd.cFileName, AddDevType ))
{
return false;
}
 
} while ( FindNextFile( dir, &fd ));
}
#else
DIR *dir;
struct dirent *de;
 
if (( dir = opendir( exeDir )) == NULL )
{
LogError( "Unable to open '%s'\n", exeDir );
return false;
}
 
while (( de = readdir( dir )) != NULL )
{
if ( fnmatch( "reg-*.bld", de->d_name, FNM_CASEFOLD ) == 0 )
{
DevTypeParser dtp;
 
if ( !dtp.ParseFile( de->d_name, AddDevType ))
{
return false;
}
}
}
 
closedir( dir );
#endif
return true;
}
 
/***************************************************************************/
/**
* Print out the program usage.
*/
 
#if USE_COMMAND_LINE
void Usage()
{
fprintf( stderr, "Usage: bioloid <option(s)>\n" );
fprintf( stderr, " Send commands to bioloid devices\n" );
fprintf( stderr, "\n" );
fprintf( stderr, " -b, --baud=baud Set the baudrate used\n" );
fprintf( stderr, " -p, --port=name Set the serial port to use\n" );
fprintf( stderr, " -n, --net=name[:port] Set the network host to use\n" );
fprintf( stderr, " -d, --debug Enable debug features\n" );
fprintf( stderr, " -h, --help Display this message\n" );
fprintf( stderr, " -v, --verbose Turn on verbose messages\n" );
 
} // Usage
#endif
 
//***************************************************************************
/**
* main
*/
 
int main( int argc, char **argv )
{
#if USE_COMMAND_LINE
char shortOptsStr[ sizeof( gOption ) / sizeof( gOption[ 0 ] ) + 1 ];
char *shortOpts = shortOptsStr;
struct option *scanOpt;
int opt;
int arg;
const char *baudStr = DEFAULT_BAUD;
const char *portStr = DEFAULT_PORT;
#endif
#if USE_NETBUS
const char *hostStr = NULL;
#endif
char line[ 80 ];
BioloidCommandLine cmdLine;
 
#if USE_COMMAND_LINE
 
// Figure out which directory our executable came from
 
char *exeDir = dirname( argv[0] );
 
// Figure out the short options from our options structure
 
for ( scanOpt = gOption; scanOpt->name != NULL; scanOpt++ )
{
if (( scanOpt->flag == NULL ) && ( scanOpt->val < OPT_FIRST_LONG_OPT ))
{
*shortOpts++ = (char)scanOpt->val;
 
if ( scanOpt->has_arg != no_argument )
{
*shortOpts++ = ':';
}
}
}
*shortOpts++ = '\0';
 
// Parse the command line options
 
while (( opt = getopt_long( argc, argv, shortOptsStr, gOption, NULL )) != -1 )
{
switch ( opt )
{
case 0:
{
// getopt_long returns 0 for entries where flag is non-NULL
 
break;
}
 
case OPT_BAUD:
{
baudStr = optarg;
break;
}
 
case OPT_DEBUG:
{
gDebug = 1;
break;
}
 
case OPT_PORT:
{
portStr = optarg;
gUseSerial = true;
break;
}
 
#if USE_NETBUS
case OPT_NET:
{
hostStr = optarg;
gUseNet = true;
break;
}
#endif
 
case OPT_VERBOSE:
{
gVerbose = 1;
break;
}
 
case '?':
default:
{
fprintf( stderr, "opt:%d\n", opt );
}
case OPT_HELP:
{
Usage();
exit( 1 );
}
}
}
argc -= optind;
argv += optind;
 
LogDebug( "Debug enabled\n" );
LogVerbose( "Verbose enabled\n" );
#endif
 
if ( gUseSerial && gUseNet )
{
LogError( "Only specify network or serial, not both\n" );
exit( 1 );
}
 
// Read in all of the reg-*.bld files
 
ReadRegisterFiles( exeDir );
 
#if USE_NETBUS
if ( gUseNet )
{
if ( !gNetBus.Open( hostStr ))
{
exit( 1 );
}
gNetBus.SetDebug( gDebug != 0 );
cmdLine.SetBus( &gNetBus );
}
else
#endif
{
// Default to serial if no network specified
 
if ( !gSerialPort.Open( portStr, baudStr ))
{
exit( 1 );
}
gSerialBus.SetSerialPort( &gSerialPort );
gSerialBus.SetDebug( gDebug != 0 );
cmdLine.SetBus( &gSerialBus );
}
 
cmdLine.RegisterDeviceTypes( gNumDevTypes, gDevType );
 
printf( "> " );
while ( fgets( line, sizeof( line ), stdin ) != NULL )
{
fflush( stdout );
if ( !cmdLine.ProcessLine( line ))
{
break;
}
 
printf( "> " );
}
 
exit( 0 );
return 0;
}
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file bioloid.cpp
*
* @brief Implements a PC version of the bioloid command line interface
* which allows bioloid commands to be sent to either a real
* bioloid bus, or a simulated one.
*
****************************************************************************/
 
#if defined( AVR )
#define USE_COMMAND_LINE 0
#define USE_NETBUS 0
#else
#define USE_COMMAND_LINE 1
#define USE_NETBUS 1
#endif
 
// ---- Include Files -------------------------------------------------------
 
#include <stdio.h>
#include <stdlib.h>
 
#if USE_COMMAND_LINE
#include <getopt.h>
#endif
 
#include <libgen.h>
 
#include "Log.h"
#include "BioloidBus.h"
#include "BioloidDevice.h"
#include "BioloidCommandLine.h"
#include "bioloid-reg-servo.h"
#include "SerialPort.h"
#include "SerialBus.h"
#include "DevTypeParser.h"
 
#if USE_NETBUS
# include "NetBus.h"
#endif
 
#if defined( WIN32 )
# include <windows.h>
#else
# include <fnmatch.h>
# include <dirent.h>
#endif
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
 
#define DEFAULT_BAUD "1000000"
 
#if defined( linux )
# define DEFAULT_PORT "ttyUSB0"
#else
# define DEFAULT_PORT "com1"
#endif
 
// ---- Private Variables ---------------------------------------------------
 
enum
{
// Options assigned a single character code can use that charater code
// as a short option.
 
OPT_BAUD = 'b',
OPT_DEBUG = 'd',
OPT_PORT = 'p',
OPT_NET = 'n',
OPT_VERBOSE = 'v',
OPT_HELP = 'h',
 
// Options from this point onwards don't have any short option equivalents
 
OPT_FIRST_LONG_OPT = 0x80,
 
};
 
#if USE_COMMAND_LINE
static struct option gOption[] =
{
{ "baud", required_argument, NULL, OPT_BAUD },
{ "debug", no_argument, NULL, OPT_DEBUG },
{ "help", no_argument, NULL, OPT_HELP },
{ "port", required_argument, NULL, OPT_PORT },
{ "net", required_argument, NULL, OPT_NET },
{ "verbose", no_argument, NULL, OPT_VERBOSE },
{ NULL }
};
#endif
 
SerialPort gSerialPort;
SerialBus gSerialBus;
 
bool gUseSerial = false;
 
#if USE_NETBUS
NetBus gNetBus;
bool gUseNet = false;
#endif
 
#define MAX_DEV_TYPES 20
 
static unsigned gNumDevTypes;
static BLD_DevType_t *gDevType[ MAX_DEV_TYPES ];
 
// ---- Private Function Prototypes -----------------------------------------
 
// ---- Functions -----------------------------------------------------------
 
/***************************************************************************/
/**
* Adds a device type to the list of device types that we know about.
*/
void AddDevType( BLD_DevType_t *devType )
{
int devTypeIdx;
 
if ( gNumDevTypes >= MAX_DEV_TYPES )
{
LogError( "Too many device types (max of %d)\n", MAX_DEV_TYPES );
return;
}
 
// Make sure this isn't a duplicate
 
for ( devTypeIdx = 0; devTypeIdx < gNumDevTypes; devTypeIdx++ )
{
if ( stricmp( gDevType[ devTypeIdx ]->devTypeStr, devType->devTypeStr ) == 0 )
{
LogError( "Device Type '%s' already registered\n", devType->devTypeStr );
return;
}
}
 
// Not a device type we know about - add it to the list
 
gDevType[ gNumDevTypes ] = devType;
gNumDevTypes++;
}
 
/***************************************************************************/
/**
* Read device types and registers
*/
 
bool ReadRegisterFiles( const char *exeDir )
{
#if defined( __WIN32__ )
HANDLE dir;
WIN32_FIND_DATA fd;
char pathName[ MAX_PATH ];
 
_makepath( pathName, "", exeDir, "reg-*", "bld" );
 
if (( dir = FindFirstFile( pathName, &fd )) != INVALID_HANDLE_VALUE )
{
do
{
DevTypeParser dtp;
 
if ( !dtp.ParseFile( fd.cFileName, AddDevType ))
{
return false;
}
 
} while ( FindNextFile( dir, &fd ));
}
#else
DIR *dir;
struct dirent *de;
 
if (( dir = opendir( exeDir )) == NULL )
{
LogError( "Unable to open '%s'\n", exeDir );
return false;
}
 
while (( de = readdir( dir )) != NULL )
{
if ( fnmatch( "reg-*.bld", de->d_name, FNM_CASEFOLD ) == 0 )
{
DevTypeParser dtp;
 
if ( !dtp.ParseFile( de->d_name, AddDevType ))
{
return false;
}
}
}
 
closedir( dir );
#endif
return true;
}
 
/***************************************************************************/
/**
* Print out the program usage.
*/
 
#if USE_COMMAND_LINE
void Usage()
{
fprintf( stderr, "Usage: bioloid <option(s)>\n" );
fprintf( stderr, " Send commands to bioloid devices\n" );
fprintf( stderr, "\n" );
fprintf( stderr, " -b, --baud=baud Set the baudrate used\n" );
fprintf( stderr, " -p, --port=name Set the serial port to use\n" );
fprintf( stderr, " -n, --net=name[:port] Set the network host to use\n" );
fprintf( stderr, " -d, --debug Enable debug features\n" );
fprintf( stderr, " -h, --help Display this message\n" );
fprintf( stderr, " -v, --verbose Turn on verbose messages\n" );
 
} // Usage
#endif
 
//***************************************************************************
/**
* main
*/
 
int main( int argc, char **argv )
{
#if USE_COMMAND_LINE
char shortOptsStr[ sizeof( gOption ) / sizeof( gOption[ 0 ] ) + 1 ];
char *shortOpts = shortOptsStr;
struct option *scanOpt;
int opt;
int arg;
const char *baudStr = DEFAULT_BAUD;
const char *portStr = DEFAULT_PORT;
#endif
#if USE_NETBUS
const char *hostStr = NULL;
#endif
char line[ 80 ];
BioloidCommandLine cmdLine;
 
#if USE_COMMAND_LINE
 
// Figure out which directory our executable came from
 
char *exeDir = dirname( argv[0] );
 
// Figure out the short options from our options structure
 
for ( scanOpt = gOption; scanOpt->name != NULL; scanOpt++ )
{
if (( scanOpt->flag == NULL ) && ( scanOpt->val < OPT_FIRST_LONG_OPT ))
{
*shortOpts++ = (char)scanOpt->val;
 
if ( scanOpt->has_arg != no_argument )
{
*shortOpts++ = ':';
}
}
}
*shortOpts++ = '\0';
 
// Parse the command line options
 
while (( opt = getopt_long( argc, argv, shortOptsStr, gOption, NULL )) != -1 )
{
switch ( opt )
{
case 0:
{
// getopt_long returns 0 for entries where flag is non-NULL
 
break;
}
 
case OPT_BAUD:
{
baudStr = optarg;
break;
}
 
case OPT_DEBUG:
{
gDebug = 1;
break;
}
 
case OPT_PORT:
{
portStr = optarg;
gUseSerial = true;
break;
}
 
#if USE_NETBUS
case OPT_NET:
{
hostStr = optarg;
gUseNet = true;
break;
}
#endif
 
case OPT_VERBOSE:
{
gVerbose = 1;
break;
}
 
case '?':
default:
{
fprintf( stderr, "opt:%d\n", opt );
}
case OPT_HELP:
{
Usage();
exit( 1 );
}
}
}
argc -= optind;
argv += optind;
 
LogDebug( "Debug enabled\n" );
LogVerbose( "Verbose enabled\n" );
#endif
 
if ( gUseSerial && gUseNet )
{
LogError( "Only specify network or serial, not both\n" );
exit( 1 );
}
 
// Read in all of the reg-*.bld files
 
ReadRegisterFiles( exeDir );
 
#if USE_NETBUS
if ( gUseNet )
{
if ( !gNetBus.Open( hostStr ))
{
exit( 1 );
}
gNetBus.SetDebug( gDebug != 0 );
cmdLine.SetBus( &gNetBus );
}
else
#endif
{
// Default to serial if no network specified
 
if ( !gSerialPort.Open( portStr, baudStr ))
{
exit( 1 );
}
gSerialBus.SetSerialPort( &gSerialPort );
gSerialBus.SetDebug( gDebug != 0 );
cmdLine.SetBus( &gSerialBus );
}
 
cmdLine.RegisterDeviceTypes( gNumDevTypes, gDevType );
 
printf( "> " );
while ( fgets( line, sizeof( line ), stdin ) != NULL )
{
fflush( stdout );
if ( !cmdLine.ProcessLine( line ))
{
break;
}
 
printf( "> " );
}
 
exit( 0 );
return 0;
}
 
/bioloid/cli/SimPacket.h
1,67 → 1,67
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.h
*
* @brief Implements a simulated bioloid bus which is useful for some
* types of debugging.
*
* The simulated bus prints out all of the packets that would be
* sent over the bus.
*
****************************************************************************/
 
#if !defined( SIMPACKET_H )
#define SIMPACKET_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidPacket.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SimPacket : public BioloidPacket
{
public:
 
//------------------------------------------------------------------------
// Default constructor
 
SimPacket();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SimPacket();
 
//------------------------------------------------------------------------
// Called whenever a character is received on the bus
 
virtual void ProcessChar( uint8_t ch );
 
//------------------------------------------------------------------------
// Called when a packet has been parsed.
 
virtual void PacketReceived( Bioloid::Error err );
};
 
/** @} */
 
#endif /* SIMPACKET_H */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SimBus.h
*
* @brief Implements a simulated bioloid bus which is useful for some
* types of debugging.
*
* The simulated bus prints out all of the packets that would be
* sent over the bus.
*
****************************************************************************/
 
#if !defined( SIMPACKET_H )
#define SIMPACKET_H /**< Include Guard */
 
// ---- Include Files -------------------------------------------------------
 
#include "BioloidPacket.h"
 
/**
* @addtogroup bioloid
* @{
*/
 
class SimPacket : public BioloidPacket
{
public:
 
//------------------------------------------------------------------------
// Default constructor
 
SimPacket();
 
//------------------------------------------------------------------------
// Destructor
 
virtual ~SimPacket();
 
//------------------------------------------------------------------------
// Called whenever a character is received on the bus
 
virtual void ProcessChar( uint8_t ch );
 
//------------------------------------------------------------------------
// Called when a packet has been parsed.
 
virtual void PacketReceived( Bioloid::Error err );
};
 
/** @} */
 
#endif /* SIMPACKET_H */
 
/bioloid/cli/SerialBus.cpp
1,230 → 1,230
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.cpp
*
* @brief This file implements the SerialBus class, which talks to the
* bioloid bus using a serial port, typically through an FTDI
* USB-to-serial adapter.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "DumpMem.h"
#include "SerialBus.h"
#include "Error.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SerialBus::SerialBus()
: m_serialPort( NULL ),
m_dataBytes( 0 ),
m_debug( false )
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SerialBus::~SerialBus()
{
}
 
//***************************************************************************
/**
* Adds a byte to the buffer of data to send.
*/
 
void SerialBus::BufferByte( uint8_t data )
{
m_data[ m_dataBytes++ ] = data;
 
if ( m_dataBytes >= sizeof( m_data ))
{
WriteBuffer();
}
}
 
//***************************************************************************
/**
* Writes all of the buffered bytes to the serial port.
*/
 
void SerialBus::WriteBuffer()
{
size_t bytesWritten;
 
if ( m_debug )
{
DumpMem( "W", 0, m_data, m_dataBytes );
}
 
if (( bytesWritten = m_serialPort->Write( m_data, m_dataBytes )) != m_dataBytes )
{
LogError( "Error writing %d bytes to serial port", m_dataBytes );
}
 
m_dataBytes = 0;
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool SerialBus::ReadByte( uint8_t *ch )
{
bool rc;
 
rc = m_serialPort->Read( ch, 1 ) == 1;
 
if ( rc )
{
if ( m_dataBytes < sizeof( m_data ))
{
m_data[ m_dataBytes++ ] = *ch;
}
}
 
return rc;
}
 
//***************************************************************************
/**
* Reads a packet. Returns true if a packet was read successfully,
* false if a timeout or error occurred.
*
* virtual
*/
 
bool SerialBus::ReadStatusPacket( BioloidPacket *pkt )
{
bool rc;
 
m_dataBytes = 0;
 
rc = BioloidBus::ReadStatusPacket( pkt );
 
if ( m_debug )
{
if ( m_dataBytes > 0 )
{
DumpMem( "R", 0, m_data, m_dataBytes );
}
#if 0
if ( !rc )
{
LogError( "Packet Error\n" );
}
#endif
}
 
return rc;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void SerialBus::SendByte( uint8_t data )
{
m_checksum += data;
 
BufferByte( data );
}
 
//***************************************************************************
/**
* Send the checksum. Since the checksum byte is the last byte of the
* packet, this function is made virtual to allow bus drivers to
* buffer the packet bytes until the entire packet is ready to send.
*
* virtual
*/
 
void SerialBus::SendCheckSum()
{
SendByte( ~m_checksum );
 
WriteBuffer();
}
 
//***************************************************************************
/**
* Sends the command header, which is common to all of the commands.
* 2 is added to paramLen (to cover the length and cmd bytes). This
* way the caller is only responsible for figuring out how many extra
* parameter bytes are being sent.
*
* virtual
*/
 
void SerialBus::SendCmdHeader
(
Bioloid::ID_t id,
uint8_t paramLen,
Bioloid::Command cmd
)
{
m_dataBytes = 0;
 
BioloidBus::SendCmdHeader( id, paramLen, cmd );
}
 
//***************************************************************************
/**
* Sets the serial port that will be used for talking with the bioloid
* devices.
*/
 
void SerialBus::SetSerialPort( SerialPort *serPort )
{
m_serialPort = serPort;
 
// 15 gives intermittent failures on my Dell laptop. 50 seems
// to work reliably
 
m_serialPort->SetTimeout( 50 );
}
 
/** @} */
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file SerialBus.cpp
*
* @brief This file implements the SerialBus class, which talks to the
* bioloid bus using a serial port, typically through an FTDI
* USB-to-serial adapter.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include "Log.h"
#include "DumpMem.h"
#include "SerialBus.h"
#include "Error.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
//***************************************************************************
/**
* Constructor
*/
 
SerialBus::SerialBus()
: m_serialPort( NULL ),
m_dataBytes( 0 ),
m_debug( false )
{
}
 
//***************************************************************************
/**
* Destructor
*
* virtual
*/
 
SerialBus::~SerialBus()
{
}
 
//***************************************************************************
/**
* Adds a byte to the buffer of data to send.
*/
 
void SerialBus::BufferByte( uint8_t data )
{
m_data[ m_dataBytes++ ] = data;
 
if ( m_dataBytes >= sizeof( m_data ))
{
WriteBuffer();
}
}
 
//***************************************************************************
/**
* Writes all of the buffered bytes to the serial port.
*/
 
void SerialBus::WriteBuffer()
{
size_t bytesWritten;
 
if ( m_debug )
{
DumpMem( "W", 0, m_data, m_dataBytes );
}
 
if (( bytesWritten = m_serialPort->Write( m_data, m_dataBytes )) != m_dataBytes )
{
LogError( "Error writing %d bytes to serial port", m_dataBytes );
}
 
m_dataBytes = 0;
}
 
//***************************************************************************
/**
* Reads a byte.
*
* virtual
*/
 
bool SerialBus::ReadByte( uint8_t *ch )
{
bool rc;
 
rc = m_serialPort->Read( ch, 1 ) == 1;
 
if ( rc )
{
if ( m_dataBytes < sizeof( m_data ))
{
m_data[ m_dataBytes++ ] = *ch;
}
}
 
return rc;
}
 
//***************************************************************************
/**
* Reads a packet. Returns true if a packet was read successfully,
* false if a timeout or error occurred.
*
* virtual
*/
 
bool SerialBus::ReadStatusPacket( BioloidPacket *pkt )
{
bool rc;
 
m_dataBytes = 0;
 
rc = BioloidBus::ReadStatusPacket( pkt );
 
if ( m_debug )
{
if ( m_dataBytes > 0 )
{
DumpMem( "R", 0, m_data, m_dataBytes );
}
#if 0
if ( !rc )
{
LogError( "Packet Error\n" );
}
#endif
}
 
return rc;
}
 
//***************************************************************************
/**
* Sends a byte. This will automatically accumulate the byte into
* the checksum)
*
* virtual
*/
 
void SerialBus::SendByte( uint8_t data )
{
m_checksum += data;
 
BufferByte( data );
}
 
//***************************************************************************
/**
* Send the checksum. Since the checksum byte is the last byte of the
* packet, this function is made virtual to allow bus drivers to
* buffer the packet bytes until the entire packet is ready to send.
*
* virtual
*/
 
void SerialBus::SendCheckSum()
{
SendByte( ~m_checksum );
 
WriteBuffer();
}
 
//***************************************************************************
/**
* Sends the command header, which is common to all of the commands.
* 2 is added to paramLen (to cover the length and cmd bytes). This
* way the caller is only responsible for figuring out how many extra
* parameter bytes are being sent.
*
* virtual
*/
 
void SerialBus::SendCmdHeader
(
Bioloid::ID_t id,
uint8_t paramLen,
Bioloid::Command cmd
)
{
m_dataBytes = 0;
 
BioloidBus::SendCmdHeader( id, paramLen, cmd );
}
 
//***************************************************************************
/**
* Sets the serial port that will be used for talking with the bioloid
* devices.
*/
 
void SerialBus::SetSerialPort( SerialPort *serPort )
{
m_serialPort = serPort;
 
// 15 gives intermittent failures on my Dell laptop. 50 seems
// to work reliably
 
m_serialPort->SetTimeout( 50 );
}
 
/** @} */
 
/bioloid/cli/Makefile
1,89 → 1,89
###########################################################################
#
# Makefile to build the bioloid command line interface
#
###########################################################################
 
MK_OS = host
#MK_OS = avr
 
ifeq ($(MK_OS),avr)
MK_AVR_MCU = m168
MK_AVR_FREQ = 8MHz
endif
 
ifeq ($(MK_OS),host)
MK_HOST_OS = mingw
endif
 
MK_ELF_TARGET = bioloid
 
MK_SRC_FILES = \
bioloid.cpp \
Log.c \
BioloidBus.cpp \
BioloidDevice.cpp \
BioloidPacket.cpp \
SerialPort.cpp \
SerialBus.cpp \
Error.cpp \
NetBus.cpp \
bioloid-reg.cpp \
StrPrintf.c \
BioloidCommandLine.cpp \
bioloid-reg.c \
DevTypeParser.cpp \
DumpMem.c \
Str.c \
StrToken.cpp
 
ifeq ($(MK_OS),avr)
MK_SRC_FILES += c++-support.cpp
endif
 
MK_ADD_SYMBOLS := 1
 
#CFLAGS += $(OPTS)
#CXXFLAGS += $(OPTS)
 
ifeq ($(MK_HOST_OS),mingw)
LDLIBS += -lwsock32
endif
 
include ../../rules/mkRules.mk
 
#
# bioloid.exe looks in the directory with the executable to find
# the register (reg-*.bld) files. So we need to copy them.
#
 
all: copy-files
 
MK_DEVICE_TYPE_FILES := $(wildcard reg-*.bld)
MK_HTM_FILES := $(wildcard *.htm)
MK_NSI_FILES := $(wildcard *.nsi) $(wildcard *.nsh)
MK_ICO_FILES := $(wildcard *.ico)
 
MK_COPY_FILES := $(addprefix $(MK_BIN_DIR)/,$(MK_NSI_FILES) $(MK_HTM_FILES) $(MK_DEVICE_TYPE_FILES) $(MK_ICO_FILES))
 
$(MK_COPY_FILES) : $(MK_BIN_DIR)/% : %
@echo "Copying $< to $@ ..."
cp $< $@
 
copy-files: $(MK_COPY_FILES)
#
# Now go and build an installer.
#
# We build the installer from withing the bin directory, so
# filenames need to be relative to that
#
 
MK_INSTALL_FILES := $(MK_ELF_TARGET)$(MK_ELF_EXT)
MK_INSTALL_FILES += $(MK_HTM_FILES)
MK_INSTALL_FILES += $(MK_DEVICE_TYPE_FILES)
 
installer : copy-files
@$(ECHO) -e "file $(subst $(space),\nfile ,$(MK_INSTALL_FILES))" > $(MK_BIN_DIR)/file-list.nsh
@$(ECHO) -e "delete \$$INSTDIR\\\\$(subst $(space),\ndelete \$$INSTDIR\\\\,$(MK_INSTALL_FILES))" > $(MK_BIN_DIR)/file-delete.nsh
(cd $(MK_BIN_DIR); makensis installer.nsi)
###########################################################################
#
# Makefile to build the bioloid command line interface
#
###########################################################################
 
MK_OS = host
#MK_OS = avr
 
ifeq ($(MK_OS),avr)
MK_AVR_MCU = m168
MK_AVR_FREQ = 8MHz
endif
 
ifeq ($(MK_OS),host)
MK_HOST_OS = mingw
endif
 
MK_ELF_TARGET = bioloid
 
MK_SRC_FILES = \
bioloid.cpp \
Log.c \
BioloidBus.cpp \
BioloidDevice.cpp \
BioloidPacket.cpp \
SerialPort.cpp \
SerialBus.cpp \
Error.cpp \
NetBus.cpp \
bioloid-reg.cpp \
StrPrintf.c \
BioloidCommandLine.cpp \
bioloid-reg.c \
DevTypeParser.cpp \
DumpMem.c \
Str.c \
StrToken.cpp
 
ifeq ($(MK_OS),avr)
MK_SRC_FILES += c++-support.cpp
endif
 
MK_ADD_SYMBOLS := 1
 
#CFLAGS += $(OPTS)
#CXXFLAGS += $(OPTS)
 
ifeq ($(MK_HOST_OS),mingw)
LDLIBS += -lwsock32
endif
 
include ../../rules/mkRules.mk
 
#
# bioloid.exe looks in the directory with the executable to find
# the register (reg-*.bld) files. So we need to copy them.
#
 
all: copy-files
 
MK_DEVICE_TYPE_FILES := $(wildcard reg-*.bld)
MK_HTM_FILES := $(wildcard *.htm)
MK_NSI_FILES := $(wildcard *.nsi) $(wildcard *.nsh)
MK_ICO_FILES := $(wildcard *.ico)
 
MK_COPY_FILES := $(addprefix $(MK_BIN_DIR)/,$(MK_NSI_FILES) $(MK_HTM_FILES) $(MK_DEVICE_TYPE_FILES) $(MK_ICO_FILES))
 
$(MK_COPY_FILES) : $(MK_BIN_DIR)/% : %
@echo "Copying $< to $@ ..."
cp $< $@
 
copy-files: $(MK_COPY_FILES)
#
# Now go and build an installer.
#
# We build the installer from withing the bin directory, so
# filenames need to be relative to that
#
 
MK_INSTALL_FILES := $(MK_ELF_TARGET)$(MK_ELF_EXT)
MK_INSTALL_FILES += $(MK_HTM_FILES)
MK_INSTALL_FILES += $(MK_DEVICE_TYPE_FILES)
 
installer : copy-files
@$(ECHO) -e "file $(subst $(space),\nfile ,$(MK_INSTALL_FILES))" > $(MK_BIN_DIR)/file-list.nsh
@$(ECHO) -e "delete \$$INSTDIR\\\\$(subst $(space),\ndelete \$$INSTDIR\\\\,$(MK_INSTALL_FILES))" > $(MK_BIN_DIR)/file-delete.nsh
(cd $(MK_BIN_DIR); makensis installer.nsi)
/bioloid/cli/DevTypeParser.cpp
1,358 → 1,358
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file BioloidCommandLine.cpp
*
* @brief This file implements the BioloidCommandLine class, which
* parses command lines and sends the commands to devices on the
* bioloid bus.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include <string.h>
 
#include "Str.h"
#include "DevTypeParser.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
 
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
typedef struct
{
const char *name;
BLD_RegFmtFunc fmtFunc;
BLD_RegParseFunc parseFunc;
 
} FieldType_t;
 
static FieldType_t gFieldType[] =
{
{ "BaudRate", BLD_RegFmtBaud, BLD_RegParseBaud },
{ "RDT", BLD_RegFmtRDT, BLD_RegParseRDT },
{ "Angle", BLD_RegFmtAngle, BLD_RegParseAngle },
{ "Temperature", BLD_RegFmtTemp, BLD_RegParseTemp },
{ "Voltage", BLD_RegFmtVolt, BLD_RegParseVolt },
{ "StatusRet", BLD_RegFmtStatusRet, BLD_RegParseStatusRet },
{ "Alarm", BLD_RegFmtAlarm, NULL},
{ "OnOff", BLD_RegFmtOnOff, BLD_RegParseOnOff },
{ "AngularVelocity", BLD_RegFmtVelocity, BLD_RegParseVelocity },
{ "Load", BLD_RegFmtLoad, NULL },
{ NULL }
};
 
//***************************************************************************
/**
* Constructor
*/
 
DevTypeParser::DevTypeParser()
: m_fs( NULL ),
m_devType( NULL ),
m_allocRegs( 0 ),
m_addDevTypeFunc( NULL )
{
}
 
//***************************************************************************
/**
* Destructor
*/
 
DevTypeParser::~DevTypeParser()
{
if ( m_devType != NULL )
{
free( m_devType->reg );
}
delete m_devType;
 
if ( m_fs != NULL )
{
fclose( m_fs );
}
}
 
//***************************************************************************
/**
* Parses a device type file
*/
 
bool DevTypeParser::ParseFile( const char *fileName, AddDevTypeFunc addDevTypeFunc )
{
m_addDevTypeFunc = addDevTypeFunc;
m_fileName = fileName;
m_lineNum = 0;
 
if (( m_fs = fopen( fileName, "r" )) == NULL )
{
LogError( "Unable to open '%s' for reading\n", fileName );
return false;
}
 
while ( fgets( m_lineBuf, sizeof( m_lineBuf ), m_fs ) != NULL )
{
char *s;
 
m_lineNum++;
 
// Strip off comments
 
if (( s = strchr( m_lineBuf, '#' )) != NULL )
{
*s = '\0';
}
 
m_line.Init( m_lineBuf, m_token, sizeof( m_token ));
 
if ( !ParseLine())
{
return false;
}
}
}
 
//***************************************************************************
/**
* Parses one line from the device type file
*/
 
bool DevTypeParser::ParseLine()
{
const char *token = m_line.NextToken();
 
if ( token == NULL )
{
// Ignore blank lines
 
return true;
}
 
if ( m_devType != NULL )
{
if ( stricmp( token, "Model:" ) == 0 )
{
if ( !m_line.NextNum( &m_devType->model ))
{
LogError( "Numeric model required: found '%s' %s:%d\n", m_line.PrevToken(), m_fileName, m_lineNum );
return false;
}
 
return true;
}
 
if ( stricmp( token, "Register:" ) == 0 )
{
BLD_Reg_t reg;
 
if ( !ParseRegister( &reg ))
{
return false;
}
 
if ( m_devType->numRegs >= m_allocRegs )
{
m_allocRegs += 8;
m_devType->reg = (BLD_Reg_t *)realloc( m_devType->reg, m_allocRegs * sizeof( m_devType->reg[0] ));
}
m_devType->reg[ m_devType->numRegs ] = reg;
m_devType->numRegs++;
 
return true;
}
 
if ( stricmp( token, "EndDeviceType" ) == 0 )
{
LogVerbose( "Parsed device type: '%s' %d registers\n",
m_devType->devTypeStr, m_devType->numRegs );
 
m_addDevTypeFunc( m_devType );
m_devType = NULL;
 
return true;
}
 
LogError( "Unrecognized keyword: '%s' %s:%d\n", token, m_fileName, m_lineNum );
return false;
}
 
if ( stricmp( token, "DeviceType:" ) == 0 )
{
if ( m_devType != NULL )
{
LogError( "Duplicate DeviceType or missing EndDeviceType %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
m_devType = new BLD_DevType_t;
memset( m_devType, 0, sizeof( *m_devType ));
 
const char *devTypeStr = m_line.NextToken();
 
if ( devTypeStr == NULL )
{
LogError( "DeviceType: requires a device type string: %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
StrMaxCpy( m_devType->devTypeStr, devTypeStr, sizeof( m_devType->devTypeStr ));
return true;
}
 
LogError( "Unrecognized keyword: '%s' %s:%d\n", token, m_fileName, m_lineNum );
return false;
}
 
//***************************************************************************
/**
* Parses A register line
*/
 
bool DevTypeParser::ParseRegister( BLD_Reg_t *reg )
{
char *s;
uint8_t numBytes;
 
memset( reg, 0, sizeof( *reg ));
 
// offset name numBytes ro/rw min max type
 
if ( !m_line.NextNum( &reg->address))
{
LogError( "Invalid register address %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
if (( s = m_line.NextToken()) == NULL )
{
LogError( "No register name specified %s:%d\n", m_fileName, m_lineNum );
return false;
}
StrMaxCpy( reg->name, s, sizeof( reg->name ));
if ( !m_line.NextNum( &numBytes ))
{
LogError( "Register %s: Invalid numBytes %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
if (( numBytes < 1 ) || ( numBytes > 2 ))
{
LogError( "Register %s: numBytes must be 1 or 2, found: %d %s:%d\n", reg->name, numBytes, m_fileName, m_lineNum );
return false;
}
reg->flags = 0;
if ( numBytes == 2 )
{
reg->flags |= BLD_REG_FLAG_16BIT;
}
 
if ( reg->address + numBytes > m_devType->numRegBytes )
{
m_devType->numRegBytes = reg->address + numBytes;
}
 
if (( s = m_line.NextToken()) == NULL )
{
LogError( "Register %s: No mode specified (ro/rw) %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
 
if ( stricmp( s, "ro" ) == 0 )
{
reg->flags |= BLD_REG_FLAG_RD;
}
else
if ( stricmp( s, "rw" ) == 0 )
{
reg->flags |= BLD_REG_FLAG_RW;
}
else
{
LogError( "Register %s: Invalid mode specified. Expecting ro/rw, found: '%s' %s:%d\n", reg->name, s, m_fileName, m_lineNum );
return false;
}
 
// min/max fields are optional for read-only files
 
uint16_t minVal;
uint16_t maxVal;
 
if ( !m_line.NextNum( &minVal ))
{
if (( reg->flags & BLD_REG_FLAG_WR ) != 0 )
{
LogError( "Register %s: Min and Max required for writable registers %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
 
// No more tokens - we're done successfully for Read-Only
 
return true;
}
 
if ( !m_line.NextNum( &maxVal ))
{
LogError( "Register %s: must specify max val when using min val %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
if ( maxVal < minVal )
{
LogError( "Register %s: maxVal (%u) must be >= minVal (%u) %s:%d\n", reg->name, maxVal, minVal, m_fileName, m_lineNum );
return false;
}
if ((( reg->flags & BLD_REG_FLAG_16BIT ) == 0 ) && ( maxVal > 255 ))
{
LogError( "Register %s: maxVal (%u) must be <= 255 for 1 byte fields %s:%d\n", reg->name, maxVal, m_fileName, m_lineNum );
return false;
}
reg->minVal = minVal;
reg->maxVal = maxVal;
 
if (( s = m_line.NextToken()) != NULL )
{
FieldType_t *fieldType;
 
// Check for support formats.
 
for ( fieldType = gFieldType; fieldType->name != NULL; fieldType++ )
{
if ( stricmp( s, fieldType->name ) == 0 )
{
reg->fmtFunc = fieldType->fmtFunc;
reg->parseFunc = fieldType->parseFunc;
 
return true;
}
}
 
LogError( "Register %s: unrecognized field type: '%s' %s:%d\n", reg->name, s, m_fileName, m_lineNum );
return false;
}
 
return true;
}
 
/****************************************************************************
*
* Copyright (c) 2009 Dave Hylands <dhylands@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
****************************************************************************/
/**
*
* @file BioloidCommandLine.cpp
*
* @brief This file implements the BioloidCommandLine class, which
* parses command lines and sends the commands to devices on the
* bioloid bus.
*
****************************************************************************/
 
// ---- Include Files -------------------------------------------------------
 
#include <string.h>
 
#include "Str.h"
#include "DevTypeParser.h"
 
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
// ---- Private Variables ---------------------------------------------------
 
// ---- Private Function Prototypes -----------------------------------------
// ---- Functions -----------------------------------------------------------
 
/**
* @addtogroup bioloid
* @{
*/
 
typedef struct
{
const char *name;
BLD_RegFmtFunc fmtFunc;
BLD_RegParseFunc parseFunc;
 
} FieldType_t;
 
static FieldType_t gFieldType[] =
{
{ "BaudRate", BLD_RegFmtBaud, BLD_RegParseBaud },
{ "RDT", BLD_RegFmtRDT, BLD_RegParseRDT },
{ "Angle", BLD_RegFmtAngle, BLD_RegParseAngle },
{ "Temperature", BLD_RegFmtTemp, BLD_RegParseTemp },
{ "Voltage", BLD_RegFmtVolt, BLD_RegParseVolt },
{ "StatusRet", BLD_RegFmtStatusRet, BLD_RegParseStatusRet },
{ "Alarm", BLD_RegFmtAlarm, NULL},
{ "OnOff", BLD_RegFmtOnOff, BLD_RegParseOnOff },
{ "AngularVelocity", BLD_RegFmtVelocity, BLD_RegParseVelocity },
{ "Load", BLD_RegFmtLoad, NULL },
{ NULL }
};
 
//***************************************************************************
/**
* Constructor
*/
 
DevTypeParser::DevTypeParser()
: m_fs( NULL ),
m_devType( NULL ),
m_allocRegs( 0 ),
m_addDevTypeFunc( NULL )
{
}
 
//***************************************************************************
/**
* Destructor
*/
 
DevTypeParser::~DevTypeParser()
{
if ( m_devType != NULL )
{
free( m_devType->reg );
}
delete m_devType;
 
if ( m_fs != NULL )
{
fclose( m_fs );
}
}
 
//***************************************************************************
/**
* Parses a device type file
*/
 
bool DevTypeParser::ParseFile( const char *fileName, AddDevTypeFunc addDevTypeFunc )
{
m_addDevTypeFunc = addDevTypeFunc;
m_fileName = fileName;
m_lineNum = 0;
 
if (( m_fs = fopen( fileName, "r" )) == NULL )
{
LogError( "Unable to open '%s' for reading\n", fileName );
return false;
}
 
while ( fgets( m_lineBuf, sizeof( m_lineBuf ), m_fs ) != NULL )
{
char *s;
 
m_lineNum++;
 
// Strip off comments
 
if (( s = strchr( m_lineBuf, '#' )) != NULL )
{
*s = '\0';
}
 
m_line.Init( m_lineBuf, m_token, sizeof( m_token ));
 
if ( !ParseLine())
{
return false;
}
}
}
 
//***************************************************************************
/**
* Parses one line from the device type file
*/
 
bool DevTypeParser::ParseLine()
{
const char *token = m_line.NextToken();
 
if ( token == NULL )
{
// Ignore blank lines
 
return true;
}
 
if ( m_devType != NULL )
{
if ( stricmp( token, "Model:" ) == 0 )
{
if ( !m_line.NextNum( &m_devType->model ))
{
LogError( "Numeric model required: found '%s' %s:%d\n", m_line.PrevToken(), m_fileName, m_lineNum );
return false;
}
 
return true;
}
 
if ( stricmp( token, "Register:" ) == 0 )
{
BLD_Reg_t reg;
 
if ( !ParseRegister( &reg ))
{
return false;
}
 
if ( m_devType->numRegs >= m_allocRegs )
{
m_allocRegs += 8;
m_devType->reg = (BLD_Reg_t *)realloc( m_devType->reg, m_allocRegs * sizeof( m_devType->reg[0] ));
}
m_devType->reg[ m_devType->numRegs ] = reg;
m_devType->numRegs++;
 
return true;
}
 
if ( stricmp( token, "EndDeviceType" ) == 0 )
{
LogVerbose( "Parsed device type: '%s' %d registers\n",
m_devType->devTypeStr, m_devType->numRegs );
 
m_addDevTypeFunc( m_devType );
m_devType = NULL;
 
return true;
}
 
LogError( "Unrecognized keyword: '%s' %s:%d\n", token, m_fileName, m_lineNum );
return false;
}
 
if ( stricmp( token, "DeviceType:" ) == 0 )
{
if ( m_devType != NULL )
{
LogError( "Duplicate DeviceType or missing EndDeviceType %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
m_devType = new BLD_DevType_t;
memset( m_devType, 0, sizeof( *m_devType ));
 
const char *devTypeStr = m_line.NextToken();
 
if ( devTypeStr == NULL )
{
LogError( "DeviceType: requires a device type string: %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
StrMaxCpy( m_devType->devTypeStr, devTypeStr, sizeof( m_devType->devTypeStr ));
return true;
}
 
LogError( "Unrecognized keyword: '%s' %s:%d\n", token, m_fileName, m_lineNum );
return false;
}
 
//***************************************************************************
/**
* Parses A register line
*/
 
bool DevTypeParser::ParseRegister( BLD_Reg_t *reg )
{
char *s;
uint8_t numBytes;
 
memset( reg, 0, sizeof( *reg ));
 
// offset name numBytes ro/rw min max type
 
if ( !m_line.NextNum( &reg->address))
{
LogError( "Invalid register address %s:%d\n", m_fileName, m_lineNum );
return false;
}
 
if (( s = m_line.NextToken()) == NULL )
{
LogError( "No register name specified %s:%d\n", m_fileName, m_lineNum );
return false;
}
StrMaxCpy( reg->name, s, sizeof( reg->name ));
if ( !m_line.NextNum( &numBytes ))
{
LogError( "Register %s: Invalid numBytes %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
if (( numBytes < 1 ) || ( numBytes > 2 ))
{
LogError( "Register %s: numBytes must be 1 or 2, found: %d %s:%d\n", reg->name, numBytes, m_fileName, m_lineNum );
return false;
}
reg->flags = 0;
if ( numBytes == 2 )
{
reg->flags |= BLD_REG_FLAG_16BIT;
}
 
if ( reg->address + numBytes > m_devType->numRegBytes )
{
m_devType->numRegBytes = reg->address + numBytes;
}
 
if (( s = m_line.NextToken()) == NULL )
{
LogError( "Register %s: No mode specified (ro/rw) %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
 
if ( stricmp( s, "ro" ) == 0 )
{
reg->flags |= BLD_REG_FLAG_RD;
}
else
if ( stricmp( s, "rw" ) == 0 )
{
reg->flags |= BLD_REG_FLAG_RW;
}
else
{
LogError( "Register %s: Invalid mode specified. Expecting ro/rw, found: '%s' %s:%d\n", reg->name, s, m_fileName, m_lineNum );
return false;
}
 
// min/max fields are optional for read-only files
 
uint16_t minVal;
uint16_t maxVal;
 
if ( !m_line.NextNum( &minVal ))
{
if (( reg->flags & BLD_REG_FLAG_WR ) != 0 )
{
LogError( "Register %s: Min and Max required for writable registers %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
 
// No more tokens - we're done successfully for Read-Only
 
return true;
}
 
if ( !m_line.NextNum( &maxVal ))
{
LogError( "Register %s: must specify max val when using min val %s:%d\n", reg->name, m_fileName, m_lineNum );
return false;
}
if ( maxVal < minVal )
{
LogError( "Register %s: maxVal (%u) must be >= minVal (%u) %s:%d\n", reg->name, maxVal, minVal, m_fileName, m_lineNum );
return false;
}
if ((( reg->flags & BLD_REG_FLAG_16BIT ) == 0 ) && ( maxVal > 255 ))
{
LogError( "Register %s: maxVal (%u) must be <= 255 for 1 byte fields %s:%d\n", reg->name, maxVal, m_fileName, m_lineNum );
return false;
}
reg->minVal = minVal;
reg->maxVal = maxVal;
 
if (( s = m_line.NextToken()) != NULL )
{
FieldType_t *fieldType;
 
// Check for support formats.
 
for ( fieldType = gFieldType; fieldType->name != NULL; fieldType++ )
{
if ( stricmp( s, fieldType->name ) == 0 )
{
reg->fmtFunc = fieldType->fmtFunc;
reg->parseFunc = fieldType->parseFunc;
 
return true;
}
}
 
LogError( "Register %s: unrecognized field type: '%s' %s:%d\n", reg->name, s, m_fileName, m_lineNum );
return false;
}
 
return true;
}