Library for XBus servo (under construction)

Dependents:   mbed_XBus_Test mbed_XBus_MotionTest XBusServoTest ControlYokutan2017_2 ... more

It's pre-opened page. it's still a little bit unstable to use command packet but mostly work. Tested only on KL25Z

暫定版ページです。 まだコマンドパケット使用時に時々不安定になりますが、概ね動作しています。 KL25Z上でのみ、動作確認しています

Revision:
0:381d475cfd6c
Child:
1:bd80d3e8f3a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBusServo.cpp	Thu Oct 02 08:46:53 2014 +0000
@@ -0,0 +1,720 @@
+/* XBusServo.cpp file
+ *
+ * for mbed
+ *
+ * Copyright (c) 2014-2014 JR PROPO
+ * by Zak Sawa
+ */
+
+#include "XBusServo.h"
+#include "pinmap.h"
+
+
+#define kXBusBaudrate           250000          // bps
+
+#define kStartOffsetOfCHData    4
+#define kCHDataSize             4
+#define kCHDataPacketCommand    0
+#define kCHDataPacketLength     1
+#define kCHDataPacketKey        2
+#define kCHDataPacketType       3
+
+#define kCmdDataPacketSize      8
+#define kCmdDataPacketCommand   0
+#define kCmdDataPacketLength    1
+#define kCmdDataPacketKey       2
+#define kCmdDataPacketCH_ID     3
+#define kCmdDataPacketOrder     4
+#define kCmdDataPacketData1     5
+#define kCmdDataPacketData2     6
+#define kCmdDataPacketCRC       7
+
+
+// XBus Command
+typedef enum {
+    kXBusCmd_Set =              0x20,
+    kXBusCmd_Get =              0x21,
+    kXBusCmd_Status =           0x22,
+    kXBusCmd_ModeA =            0xa4
+} XBusCmd;
+
+
+// XBUS device mode
+typedef enum {
+    kXBusMode_Operate =         0x01,
+    kXBusMode_IDSet =           0x02
+} XBusMode;
+
+
+#define DEBUG
+
+#ifdef DEBUG
+Serial      pc(USBTX, USBRX); // tx, rx
+#define DBG(fmt) pc.printf(fmt)
+#define DBGF(fmt, ...) pc.printf(fmt, __VA_ARGS__)
+#else
+#define DBG(...)
+#define DBGF(...)
+#endif
+
+
+
+//****************************************************************************
+//  XBusServo::XBusServo
+//    return :    none
+//    parameter : tx           pin name for tx
+//                rx           pin name for rx
+//                maxServoNum  max number of servo that you want to connect.
+//                             (limit 50)
+//                             this does just to resetve the buffer.  you need to
+//                             add XBus servo at the beginning of your sketch
+//
+//    Constructor
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusServo::XBusServo(PinName tx, PinName rx, uint8_t maxServoNum)
+    : RawSerial(tx, rx)                 //, DigitalInOut(tx)
+{
+    int        bufferSize;            // channel data packet buffer size
+
+    DBG("XBusServo::XBusServo\n");
+
+    // initialize serial
+    txPin = tx;
+    txOnly = (rx == NC);
+
+    // initialise vars
+    numOfServo = 0;
+    maxServo = maxServoNum;
+    if (maxServo > kXBusMaxServoNum)
+        maxServo = kXBusMaxServoNum;
+    else if (maxServo == 0)
+        maxServo = 1;
+    dirty = 0;
+    serialWriteBusy = 0;
+    recieveBufferPointer = 0;
+    modifyServosNow = 0;
+    sendLength = 0;
+    bufferSize = kStartOffsetOfCHData + maxServo * kCHDataSize + 1;     // add 1 for CRC
+    if (bufferSize < kCmdDataPacketSize)
+        bufferSize = kCmdDataPacketSize;
+    chPacketBuffer = (uint8_t*)malloc(bufferSize);
+    sendBuffer = (uint8_t*)malloc(bufferSize);
+
+    // initialize channel packer buffer
+    chPacketBuffer[kCHDataPacketCommand]    = kXBusCmd_ModeA;
+    chPacketBuffer[kCHDataPacketLength]     = 0x00;
+    chPacketBuffer[kCHDataPacketKey]        = 0x00;
+    chPacketBuffer[kCHDataPacketType]       = 0x00;
+
+    // initialize serial
+    RawSerial::baud(kXBusBaudrate);
+    RawSerial::format(8, RawSerial::None, 1);
+#if DEVICE_SERIAL_FC
+    RawSerial::set_flow_control(RawSerial::Disabled, NC, NC);
+#endif
+    RawSerial::attach(this, &XBusServo::TxIrqHandler, RawSerial::TxIrq);
+    RawSerial::attach(this, &XBusServo::RxIrqHandler, RawSerial::RxIrq);
+
+//    DigitalInOut::mode(PullNone);
+//    DigitalInOut::input();
+    serial_pinout_tx(txPin);
+}
+
+
+//****************************************************************************
+//  XBusServo::~XBusServo
+//    return :    none
+//    parameter : none
+//
+//    Destructor
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusServo::~XBusServo()
+{
+    DBG("XBusServo::~XBusServo\n");
+
+    free(chPacketBuffer);
+    free(sendBuffer);
+}
+
+
+//****************************************************************************
+//  XBusServo::write
+//    return :    none
+//    parameter : buffer      data buffer to send
+//                length      data length on the buffer
+//
+//    start to send all packet data
+//    2014/09/30 : first write by Sawa
+//****************************************************************************
+void XBusServo::write(uint8_t* buffer, uint8_t length)
+{
+ //  DBG("XBusServo::write\n");
+
+    if (serialWriteBusy)
+        return;
+
+    serialWriteBusy = 1;
+    XBusServo::sendLength = length;
+    sendBufferPointer = buffer;
+
+    if (putc(*sendBufferPointer++) < 0) {
+        serialWriteBusy = 0;
+        XBusServo::sendLength = 0;
+    } else
+        XBusServo::sendLength--;
+}
+
+
+//****************************************************************************
+//  XBusServo::flush
+//    return :    none
+//    parameter : none
+//
+//    wait to send all packet data
+//    2014/09/30 : first write by Sawa
+//****************************************************************************
+void XBusServo::flush(void)
+{
+//    DBG("XBusServo::flush\n");
+
+    while(serialWriteBusy)
+        ;
+}
+
+
+//****************************************************************************
+//  XBusServo::TxIrqHandler
+//    return :    none
+//    parameter : none
+//
+//    handler for Tx buffer empty
+//    2014/09/30 : first write by Sawa
+//****************************************************************************
+void XBusServo::TxIrqHandler(void)
+{
+//    DBG("XBusServo::TxIrqHandler\n");
+
+    if (! serialWriteBusy)
+        return;
+
+    if (XBusServo::sendLength <= 0)
+        serialWriteBusy = 0;
+    else {
+        if (putc(*sendBufferPointer++) < 0) {
+            serialWriteBusy = 0;
+            XBusServo::sendLength = 0;
+        } else
+            XBusServo::sendLength--;
+    }
+}
+
+
+//****************************************************************************
+//  XBusServo::RxIrqHandler
+//    return :    none
+//    parameter : none
+//
+//    handler for Rx buffer full
+//    2014/09/30 : first write by Sawa
+//****************************************************************************
+void XBusServo::RxIrqHandler(void)
+{
+//    DBG("XBusServo::RxIrqHandler\n");
+
+    recieveBuffer[recieveBufferPointer++] = getc();
+    if (recieveBufferPointer >= kRecieveBufferSize)
+        recieveBufferPointer = 0;
+}
+
+
+
+//****************************************************************************
+//  XBusServo::sendChannelDataPacket
+//    return :    none
+//    parameter : none
+//
+//    This should be called on the timer handler like MsTimer2 when you
+//    use the XBus servo.
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+void XBusServo::sendChannelDataPacket(void)
+{
+//    DBG("XBusServo::sendChannelDataPacket\n");
+
+    if (modifyServosNow)
+        return;
+
+    if (numOfServo > 0) {
+        if (dirty) {
+            memcpy(sendBuffer, chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 3);
+            dirty = 0;
+        }
+
+        write(sendBuffer, sendBuffer[kCHDataPacketLength] + 3);
+    }
+}
+
+
+//****************************************************************************
+//  XBusServo::sendCommandDataPacket
+//    return :    error code
+//    parameter : command     The commnad that you want to send
+//                channelID   The channel ID of the XBus servo that you want to set up
+//                order       The order that you want to set up
+//                value       The value that you want to set / get
+//                valueSize   The value size.  1 byte(char) or 2 byte(int)
+//
+//    This should NOT be called on the timer handler like MsTimer2 when you
+//    setup the XBus servo.
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::sendCommandDataPacket(uint8_t command, uint8_t channelID, uint8_t order, int16_t* value, uint8_t valueSize)
+{
+    int                 sendSize;
+    uint8_t*            recievedPacket;
+
+    DBG("XBusServo::sendCommandDataPacket\n");
+
+    // setup command
+    sendBuffer[kCmdDataPacketCommand] = command;
+    sendBuffer[kCmdDataPacketLength] = valueSize + 3;
+    sendBuffer[kCmdDataPacketKey] = 0x00;
+    sendBuffer[kCmdDataPacketCH_ID] = channelID;
+    sendBuffer[kCmdDataPacketOrder] = order;
+    if (valueSize == 1) {                   // 1 byte value
+        sendBuffer[kCmdDataPacketData1] = *value & 0x00FF;
+        sendBuffer[kCmdDataPacketData2] = crc8(sendBuffer, sendBuffer[kCHDataPacketLength] + 2);
+    } else {
+        sendBuffer[kCmdDataPacketData1] = (*value >> 8) & 0x00FF;
+        sendBuffer[kCmdDataPacketData2] = *value & 0x00FF;
+        sendBuffer[kCmdDataPacketCRC] = crc8(sendBuffer, sendBuffer[kCHDataPacketLength] + 2);
+    }
+
+    // to recover channel data packet when you call sendChannelDataPacket after this
+    dirty = 1;
+
+    // send command
+    recieveBufferPointer = 0;                                   // reset recieve buffer
+    sendSize = sendBuffer[kCmdDataPacketLength] + 3;
+    write(sendBuffer, sendSize);
+    flush();                                                    // wait to send all bytes
+
+    // if it's tx only mode, it done
+    if (txOnly)
+        return kXBusError_NoError;
+
+    if (channelID != 0) {
+        // change bus direction to Rx mode
+//       DigitalInOut::input();
+
+        recievedPacket = &(recieveBuffer[sendSize]);
+
+        // wait to read all packet
+        while(recieveBufferPointer < (sendSize + kCmdDataPacketSize))
+            ;
+
+        // change bus direction to Tx mode
+        serial_pinout_tx(txPin);
+
+        // check CRC
+        if (crc8(recievedPacket, recievedPacket[kCHDataPacketLength] + 3) != 0)
+            return kXBusError_CRCError;
+
+        // check unsupported
+        if (recievedPacket[kCmdDataPacketOrder] == kXBusOrder_1_Unsupported)
+            return kXBusError_Unsupported;
+
+        // send back the value
+        if (valueSize == 1) {                   // 1 byte value
+            *value = recievedPacket[kCmdDataPacketData1];
+            if (*value & 0x0080)
+                *value |= 0xFF00;
+        } else {
+            *value = recievedPacket[kCmdDataPacketData1];
+            *value <<= 8;
+            *value |= recievedPacket[kCmdDataPacketData2];
+        }
+    }
+
+    return kXBusError_NoError;
+}
+
+
+//****************************************************************************
+//  XBusServo::addServo
+//    return :    error code
+//    parameter : channelID   channel ID of the XBus servo that you want to use
+//                initValue   initial value of this XBus servo
+//                            use kXbusServoNeutral for center of the XBus servo
+//
+//    add new servo to the buffer on this library
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::addServo(uint8_t channelID, uint16_t initValue)
+{
+    uint16_t         dataOffset;
+
+    DBG("XBusServo::addServo\n");
+
+    // max check
+    if (numOfServo >= maxServo)
+        return kXBusError_ServoNumOverflow;
+
+    // convert to servo ID
+    channelID &= 0x3F;
+
+    // scan servo ID that is already added
+    if (numOfServo > 0) {
+        uint16_t     servoNo;
+
+        for (servoNo = 0; servoNo < numOfServo; servoNo++)
+            if (chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * servoNo] == channelID)
+                return kXBusError_AddWithSameID;                            // found same servo ID
+    }
+
+    // atomic flag on
+    modifyServosNow = 1;
+
+    // add new servo
+    dataOffset = kStartOffsetOfCHData + kCHDataSize * numOfServo;
+    numOfServo++;
+    chPacketBuffer[kCHDataPacketLength] = numOfServo * kCHDataSize + 2;     // add 2 for key and type
+
+    chPacketBuffer[dataOffset] = channelID;
+    chPacketBuffer[dataOffset + 1] = 0x00;
+    chPacketBuffer[dataOffset + 2] = (initValue >> 8) & 0x00FF;
+    chPacketBuffer[dataOffset + 3] = initValue & 0x00FF;
+
+    // calc CRC
+    chPacketBuffer[dataOffset + 4] = crc8(chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 2);
+    dirty = 1;
+
+    // atomic flag off
+    modifyServosNow = 0;
+
+    return kXBusError_NoError;
+}
+
+
+//****************************************************************************
+//  XBusServo::removeServo
+//    return :    error code
+//    parameter : channelID   channel ID of the XBus servo that you want to remove
+//
+//    remove the servo from the buffer on this library
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::removeServo(uint8_t channelID)
+{
+    DBG("XBusServo::removeServo\n");
+
+    // min check
+    if (numOfServo == 0)
+        return kXBusError_ServoNumIsZero;
+
+    // convert to servo ID
+    channelID &= 0x3F;
+
+    // scan servo ID that is already added
+    if (numOfServo > 0) {
+        uint16_t     servoNo;
+
+        for (servoNo = 0; servoNo < numOfServo; servoNo++)
+            if (chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * servoNo] == channelID) {
+                // atomic flag on
+                modifyServosNow = 1;
+
+                // copy data after that
+                if (servoNo < (numOfServo - 1))
+                    memcpy(&(chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * servoNo]),
+                           &(chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * (servoNo + 1)]),
+                           kCHDataSize * (numOfServo - servoNo - 1));
+
+                // update packet size
+                numOfServo--;
+                chPacketBuffer[kCHDataPacketLength] = numOfServo * kCHDataSize + 2;     // add 2 for key and type
+
+                // calc CRC
+                chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * numOfServo]
+                = crc8(chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 2);
+                dirty = 1;
+
+                // atomic flag off
+                modifyServosNow = 0;
+
+                return kXBusError_NoError;
+            }
+    }
+
+    return kXBusError_IDNotFound;
+}
+
+
+//****************************************************************************
+//  XBusServo::setServo
+//    return :    error code
+//    parameter : channelID   channel ID of the XBus servo that you want to set
+//                value       value of this XBus servo
+//                            use kXbusServoNeutral for center of the XBus servo
+//
+//    remove the servo from the buffer on this library
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::setServo(uint8_t channelID, uint16_t value)
+{
+    uint16_t         dataOffset;
+
+    DBG("XBusServo::setServo\n");
+
+    // convert to servo ID
+    channelID &= 0x3F;
+
+    // scan servo ID that is already added
+    if (numOfServo > 0) {
+        int     servoNo;
+
+        for (servoNo = 0; servoNo < numOfServo; servoNo++) {
+            dataOffset = kStartOffsetOfCHData + kCHDataSize * servoNo;
+
+            if (chPacketBuffer[dataOffset] == channelID) {
+                // atomic flag on
+                modifyServosNow = 1;
+
+                // set value
+                chPacketBuffer[dataOffset + 2] = (value >> 8) & 0x00FF;
+                chPacketBuffer[dataOffset + 3] = value & 0x00FF;
+
+                // calc CRC
+                chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * numOfServo]
+                = crc8(chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 2);
+                dirty = 1;
+
+                // atomic flag off
+                modifyServosNow = 0;
+
+                return kXBusError_NoError;
+            }
+        }
+    }
+
+    return kXBusError_IDNotFound;
+}
+
+
+//****************************************************************************
+//  XBusServo::setChannelID
+//    return :    error code
+//    parameter : oldChannelID    channel IDof the XBus servo to change the ID
+//                newChannelID    new channel ID for the XBus servo
+//
+//    set new channel ID to the XBus servo
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::setChannelID(uint8_t oldChannelID, uint8_t newChannelID)
+{
+    XBusError       result;
+    int16_t         value;
+
+    DBG("XBusServo::setChannelID\n");
+
+    value = kXBusMode_IDSet;
+    result = sendCommandDataPacket(kXBusCmd_Set, oldChannelID, kXBusOrder_1_Mode, &value, 1);
+    if (result != kXBusError_NoError)
+        return result;
+
+    value = newChannelID;
+    result = sendCommandDataPacket(kXBusCmd_Set, oldChannelID, kXBusOrder_1_ID, &value, 1);
+
+    return result;
+}
+
+
+//****************************************************************************
+//  XBusServo::setChannelID
+//    return :    error code
+//    parameter : newChannelID    new channel ID for the XBus servo
+//
+//    set new channel ID to the XBus servo
+//    this is only for TX only mode
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::setChannelID(uint8_t newChannelID)
+{
+    XBusError       result;
+    int16_t         value;
+
+    DBG("XBusServo::setChannelID\n");
+
+    if (txOnly)
+        return kXBusError_OnlyForTxOnlyMode;
+
+    value = kXBusMode_IDSet;
+    result = sendCommandDataPacket(kXBusCmd_Set, 0, kXBusOrder_1_Mode, &value, 1);
+    if (result != kXBusError_NoError)
+        return result;
+
+    value = newChannelID;
+    result = sendCommandDataPacket(kXBusCmd_Set, 0, kXBusOrder_1_ID, &value, 1);
+
+    return result;
+}
+
+
+//****************************************************************************
+//  XBusServo::getDataSize
+//    return :    data size for this order
+//    parameter : order       the order that you want to know
+//
+//    get the data size of this order
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+uint8_t XBusServo::getDataSize(uint8_t order)
+{
+    uint8_t        dataSize = 1;
+
+    DBG("XBusServo::getDataSize\n");
+
+    switch(order) {
+        case kXBusOrder_2_Version:      // only for get
+        case kXBusOrder_2_Product:      // only for get
+        case kXBusOrder_2_Reset:        // only for set
+        case kXBusOrder_2_ParamWrite:   // only for set
+        case kXBusOrder_2_Reverse:
+        case kXBusOrder_2_Neutral:
+        case kXBusOrder_2_H_Travel:
+        case kXBusOrder_2_L_Travel:
+        case kXBusOrder_2_H_Limit:
+        case kXBusOrder_2_L_Limit:
+        case kXBusOrder_2_PowerOffset:
+        case kXBusOrder_2_AlarmDelay:
+        case kXBusOrder_2_CurrentPos:   // only for get
+        case kXBusOrder_2_MaxInteger:
+            dataSize = 2;
+    }
+
+    return dataSize;
+}
+
+
+//****************************************************************************
+//  XBusServo::setCommand
+//    return :    error code
+//    parameter : channelID   channel ID of the XBus servo that you want to set to
+//                order       the order that you want
+//                value       the value that you want to set and return current value
+//
+//    send set command to the XBus servo
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::setCommand(uint8_t channelID, uint8_t order, int16_t* value)
+{
+    DBG("XBusServo::setCommand\n");
+
+    return sendCommandDataPacket(kXBusCmd_Set, channelID, order, value, getDataSize(order));
+}
+
+
+//****************************************************************************
+//  XBusServo::getCommand
+//    return :    error code
+//    parameter : channelID   channel ID of the XBus servo that you want to get from
+//                order       the order that you want
+//                value       the value that you want to get from
+//
+//    send get command to the XBus servo
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::getCommand(uint8_t channelID, uint8_t order, int16_t* value)
+{
+    DBG("XBusServo::getCommand\n");
+
+    return sendCommandDataPacket(kXBusCmd_Get, channelID, order, value, getDataSize(order));
+}
+
+
+//****************************************************************************
+//  XBusServo::setCommand
+//    return :    error code
+//    parameter : order       the order that you want
+//                value       the value that you want to set and return current value
+//
+//    send set command to the XBus servo
+//    this is only for TX only mode
+//    2014/09/02 : move from Arduino lib by Sawa
+//****************************************************************************
+XBusError XBusServo::setCommand(uint8_t order, int16_t* value)
+{
+    DBG("XBusServo::setCommand\n");
+
+    if (txOnly)
+        return kXBusError_OnlyForTxOnlyMode;
+
+    return sendCommandDataPacket(kXBusCmd_Set, 0, order, value, getDataSize(order));
+}
+
+
+
+
+
+
+//****************************************************************************
+// for CRC
+static uint8_t s_crc_array[256] = {
+    0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83,
+    0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
+    0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
+    0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc,
+    0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0,
+    0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62,
+    0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d,
+    0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff,
+    0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5,
+    0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07,
+    0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58,
+    0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a,
+    0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6,
+    0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24,
+    0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b,
+    0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9,
+    0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f,
+    0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd,
+    0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92,
+    0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50,
+    0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c,
+    0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee,
+    0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1,
+    0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73,
+    0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49,
+    0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b,
+    0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4,
+    0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16,
+    0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a,
+    0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8,
+    0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7,
+    0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35,
+};
+
+
+uint8_t XBusServo::crc_table(uint8_t  data, uint8_t  crc)
+{
+    uint16_t  index = (data ^ crc) & 0xff;
+
+    crc = s_crc_array[index];
+    return crc;
+}
+
+
+uint8_t XBusServo::crc8(uint8_t* buffer, uint8_t  length)
+{
+    uint8_t  crc = 0;
+
+    while (length-- > 0)
+        crc = crc_table(*buffer++, crc);
+    return crc;
+}
+
+
+
+