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:
17:3ffb2e3e3bec
Parent:
16:e283810b53c3
Child:
18:75ddf12d93b6
--- a/XBusServo.cpp	Wed Oct 08 07:39:19 2014 +0000
+++ b/XBusServo.cpp	Thu Oct 30 05:11:46 2014 +0000
@@ -16,7 +16,10 @@
 
 #define kXBusBaudrate           250000          // bps
 
+#define kPacketHeaderFooterSize 3
+#define kPacketPreDataSize      3
 #define kStartOffsetOfCHData    4
+
 #define kCHDataSize             4
 #define kCHDataPacketCommand    0
 #define kCHDataPacketLength     1
@@ -43,7 +46,7 @@
 } XBusCmd;
 
 
-// XBUS device mode
+// XBus device mode
 typedef enum {
     kXBusMode_Operate =         0x01,
     kXBusMode_IDSet =           0x02
@@ -63,27 +66,44 @@
 
 /****************************************************************************
     XBusServo::XBusServo
-    
+
     @param tx           pin name for tx
     @param rx           pin name for rx
     @param maxServoNum  max number of servo that you want to connect.
                         (limit 50)
-                        this does just to resetve the buffer.  you need to
+                        this does just to reserve the buffer.  you need to
                         add XBus servo at the beginning of your sketch
 
     @bref               Constructor
 
     @note               2014/09/02 : move from Arduino lib by Sawa
 *****************************************************************************/
-XBusServo::XBusServo(PinName tx, PinName rx, uint8_t maxServoNum)
-    : XBusPort(tx, rx)
+XBusServo::XBusServo(PinName tx, PinName rx, PinName sw, uint8_t maxServoNum)
+    : XBusPort(tx, rx), TxSwitch(sw, 0)
 {
     DBG("XBusServo::XBusServo\n");
 
     // initialize serial
     txPin = tx;
-    txOnly = (rx == NC);
+    txOnly = false;
+    if (rx == NC)
+        txOnly = true;
     maxServo = maxServoNum;
+
+    // initialise vars
+    numOfServo = 0;
+    if (maxServo > kXBusMaxServoNum)
+        maxServo = kXBusMaxServoNum;
+    else if (maxServo == 0)
+        maxServo = 1;
+    dirty = false;
+    serialCommandBusy = false;
+    recieveBufferPointer = 0;
+    modifyServosNow = false;
+    sendLength = 0;
+    need2ReadData = false;
+    chPacketBuffer = NULL;
+    sendBuffer = NULL;
 }
 
 
@@ -101,23 +121,22 @@
 
     DBG("XBusServo::start\n");
 
-    // initialise vars
-    numOfServo = 0;
-    if (maxServo > kXBusMaxServoNum)
-        maxServo = kXBusMaxServoNum;
-    else if (maxServo == 0)
-        maxServo = 1;
-    dirty = 0;
-    serialWriteBusy = 0;
-    recieveBufferPointer = 0;
-    modifyServosNow = 0;
-    sendLength = 0;
+    // allocate my buffer
     bufferSize = kStartOffsetOfCHData + maxServo * kCHDataSize + 1;     // add 1 for CRC
     if (bufferSize < kCmdDataPacketSize)
         bufferSize = kCmdDataPacketSize;
 
-    chPacketBuffer = (uint8_t*)malloc(bufferSize);
-    sendBuffer = (uint8_t*)malloc(bufferSize);
+    chPacketBuffer = new uint8_t[bufferSize];
+    if (chPacketBuffer == NULL) {
+        stop();
+        return kXBusError_MemoryFull;
+    }
+
+    sendBuffer = new uint8_t[bufferSize];
+    if (sendBuffer == NULL) {
+        stop();
+        return kXBusError_MemoryFull;
+    }
 
     // initialize channel packer buffer
     chPacketBuffer[kCHDataPacketCommand]    = kXBusCmd_ModeA;
@@ -127,7 +146,7 @@
 
     // initialize serial
     XBusPort.baud(kXBusBaudrate);
-    XBusPort.format(8, RawSerial::None, 1);
+    XBusPort.format(8, Serial::None, 1);
 #if DEVICE_SERIAL_FC
     XBusPort.set_flow_control(RawSerial::Disabled, NC, NC);
 #endif
@@ -137,13 +156,13 @@
 #else
     XBusPort.attach(this, &XBusServo::TxIrqHandler, RawSerial::TxIrq);
 #endif
-    XBusPort.attach(this, &XBusServo::RxIrqHandler, RawSerial::RxIrq);
 
     serial_pinout_tx(txPin);
 
     return kXBusError_NoError;
 }
 
+
 //****************************************************************************
 //  XBusServo::stop
 //    return :    none
@@ -156,10 +175,14 @@
 {
     DBG("XBusServo::stop\n");
 
-    free(chPacketBuffer);
-    free(sendBuffer);
+    delete[] chPacketBuffer;
+    chPacketBuffer = NULL;
+
+    delete[] sendBuffer;
+    sendBuffer = NULL;
 }
 
+
 //****************************************************************************
 //  XBusServo::write
 //    return :    none
@@ -173,22 +196,24 @@
 {
 //  DBG("XBusServo::write\n");
 
-    if (serialWriteBusy)
+    if (serialCommandBusy)
         return;
 
-    serialWriteBusy = 1;
+    serialCommandBusy = true;
     XBusServo::sendLength = length;
     sendBufferPointer = buffer;
 
     if (XBusPort.putc(*sendBufferPointer++) < 0) {
-        serialWriteBusy = 0;
+        serialCommandBusy = false;
         XBusServo::sendLength = 0;
     } else {
         XBusServo::sendLength--;
+    }
+
 #ifdef TARGET_KL25Z
-        XBusPort.attach(this, &XBusServo::TxIrqHandler, RawSerial::TxIrq);
+    XBusPort.attach(this, &XBusServo::TxIrqHandler, RawSerial::TxIrq);
 #endif
-    }
+
 }
 
 
@@ -197,48 +222,76 @@
 //    return :    none
 //    parameter : none
 //
-//    wait to send all packet data
+//    wait to send all packet data.  never call from interrupt.
 //    2014/09/30 : first write by Sawa
 //****************************************************************************
 void XBusServo::flush(void)
 {
 //    DBG("XBusServo::flush\n");
 
-    while(serialWriteBusy)
+    while(serialCommandBusy)
         ;
 }
 
 
 //****************************************************************************
+//  XBusServo::TxSwitchHandler
+//    return :    none
+//    parameter : none
+//
+//    handler for Tx switch
+//    2014/10/29 : first write by Sawa
+//****************************************************************************
+void XBusServo::TxSwitchHandler(void)
+{
+    TxSwitch.write(1);
+}
+
+
+//****************************************************************************
 //  XBusServo::TxIrqHandler
 //    return :    none
 //    parameter : none
 //
 //    handler for Tx buffer empty
 //    2014/09/30 : first write by Sawa
+//    2014/10/24 : add to setup reading for command data packet
 //****************************************************************************
 void XBusServo::TxIrqHandler(void)
+//void XBusServo::TxIrqHandler(MODSERIAL_IRQ_INFO *q)
 {
+    int             result = 0;
 //    DBG("XBusServo::TxIrqHandler\n");
 
-    if (! serialWriteBusy)
+    if (! serialCommandBusy)
+        return;                                       // Is it noise ?
+
+    if (XBusServo::sendLength > 0) {
+        result = XBusPort.putc(*sendBufferPointer++);
+        if (result < 0) {
+            // error occured
+            XBusServo::sendLength = 0;
+            serialCommandBusy = false;
+        } else {
+            XBusServo::sendLength--;
+            return;
+        }
+    }
+
+#ifdef TARGET_KL25Z
+    XBusPort.attach(NULL, RawSerial::TxIrq);
+#endif
+
+    if (result < 0)
         return;
 
-    if (XBusServo::sendLength <= 0) {
-        serialWriteBusy = 0;
+    if (need2ReadData) {
 #ifdef TARGET_KL25Z
-        XBusPort.attach(NULL, RawSerial::TxIrq);
+        TxSwitchTimer.attach_us(this, &XBusServo::TxSwitchHandler, 27);
 #endif
-    } else {
-        if (XBusPort.putc(*sendBufferPointer++) < 0) {
-            serialWriteBusy = 0;
-            XBusServo::sendLength = 0;
-#ifdef TARGET_KL25Z
-            XBusPort.attach(NULL, RawSerial::TxIrq);
-#endif
-        } else
-            XBusServo::sendLength--;
     }
+
+    serialCommandBusy = false;
 }
 
 
@@ -249,18 +302,22 @@
 //
 //    handler for Rx buffer full
 //    2014/09/30 : first write by Sawa
+//    2014/10/21 : add to ignore the data myself
+//    2014/10/24 : modify to get the data from 1st byte of buffer
 //****************************************************************************
 void XBusServo::RxIrqHandler(void)
+//void XBusServo::RxIrqHandler(MODSERIAL_IRQ_INFO *q)
 {
 //    DBG("XBusServo::RxIrqHandler\n");
 
-    recieveBuffer[recieveBufferPointer++] = XBusPort.getc();
-    if (recieveBufferPointer >= kRecieveBufferSize)
-        recieveBufferPointer = 0;
+    while (XBusPort.readable()) {
+        recieveBuffer[recieveBufferPointer++] = XBusPort.getc();
+        if (recieveBufferPointer >= kRecieveBufferSize)
+            recieveBufferPointer = 0;
+    }
 }
 
 
-
 //****************************************************************************
 //  XBusServo::sendChannelDataPacket
 //    return :    none
@@ -279,11 +336,12 @@
 
     if (numOfServo > 0) {
         if (dirty) {
-            memcpy(sendBuffer, chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 3);
-            dirty = 0;
+            memcpy(sendBuffer, chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + kPacketHeaderFooterSize);
+            dirty = false;
         }
 
-        write(sendBuffer, sendBuffer[kCHDataPacketLength] + 3);
+        need2ReadData = false;
+        write(sendBuffer, sendBuffer[kCHDataPacketLength] + kPacketHeaderFooterSize);
     }
 }
 
@@ -297,20 +355,21 @@
 //                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
+//    This should NOT be called on interrupt handler 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;
+    int                 prevData = -1;
+    uint8_t             dummy;
 
     DBG("XBusServo::sendCommandDataPacket\n");
 
     // setup command
     sendBuffer[kCmdDataPacketCommand] = command;
-    sendBuffer[kCmdDataPacketLength] = valueSize + 3;
+    sendBuffer[kCmdDataPacketLength] = valueSize + kPacketPreDataSize;
     sendBuffer[kCmdDataPacketKey] = 0x00;
     sendBuffer[kCmdDataPacketCH_ID] = channelID;
     sendBuffer[kCmdDataPacketOrder] = order;
@@ -324,49 +383,64 @@
     }
 
     // to recover channel data packet when you call sendChannelDataPacket after this
-    dirty = 1;
+    dirty = true;
+
+    // prepair recieve data
+    XBusPort.attach(this, &XBusServo::RxIrqHandler, RawSerial::RxIrq);
+    while (XBusPort.readable())
+        dummy = XBusPort.getc();
+    recieveBufferPointer = 0;                                   // reset recieve buffer
 
     // send command
-    recieveBufferPointer = 0;                                   // reset recieve buffer
-    sendSize = sendBuffer[kCmdDataPacketLength] + 3;
+    sendSize = sendBuffer[kCmdDataPacketLength] + kPacketHeaderFooterSize;
+    need2ReadData = ((! txOnly) && (channelID != 0));
+    recieveBuffer[sendSize + kCmdDataPacketLength] = 5;            // dummy to get real packet size
     write(sendBuffer, sendSize);
-    flush();                                                    // wait to send all bytes
-
-    // if it's tx only mode, it done
-    if (txOnly)
-        return kXBusError_NoError;
+//    DBG("XBusServo::sendCommandDataPacket 2\n");
 
-    if (channelID != 0) {
-        // change bus direction to Rx mode
-//       DigitalInOut::input();
+    // if it's tx only mode or ID=0, it done
+    if (! need2ReadData) {
+        flush();
+        return kXBusError_NoError;
+    }
 
-        recievedPacket = &(recieveBuffer[sendSize]);
-
-        // wait to read all packet
-        while(recieveBufferPointer < (sendSize + kCmdDataPacketSize))
-            ;
+// wait to read all packet
+    while(recieveBufferPointer < (recieveBuffer[sendSize + kCmdDataPacketLength] + kPacketHeaderFooterSize + sendSize)) {
+        if (prevData != recieveBufferPointer) {
+            prevData = recieveBufferPointer;
+//           DBGF("XBusServo::sendCommandDataPacket 3 %02d %02X \n", recieveBufferPointer, recieveBuffer[recieveBufferPointer - 1]);
+        }
+        //                                           need to add time out
+    }
 
-        // change bus direction to Tx mode
-        serial_pinout_tx(txPin);
+    TxSwitch.write(0);
+//    DBG("XBusServo::sendCommandDataPacket 4\n");
+    // change bus direction to Tx mode
+    XBusPort.attach(NULL, RawSerial::RxIrq);
+    need2ReadData = false;
+    serialCommandBusy = false;
 
-        // check CRC
-        if (crc8(recievedPacket, recievedPacket[kCHDataPacketLength] + 3) != 0)
-            return kXBusError_CRCError;
-
-        // check unsupported
-        if (recievedPacket[kCmdDataPacketOrder] == kXBusOrder_1_Unsupported)
-            return kXBusError_Unsupported;
+    // check CRC
+    if (crc8(recieveBuffer, recieveBuffer[kCHDataPacketLength] + 3) != 0) {
+        DBG("XBusServo::sendCommandDataPacket kXBusError_CRCError\n");
+        return kXBusError_CRCError;
+    }
 
-        // 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];
-        }
+    // check unsupported
+    if (recieveBuffer[kCmdDataPacketOrder] == kXBusOrder_1_Unsupported) {
+        DBG("XBusServo::sendCommandDataPacket kXBusError_Unsupported\n");
+        return kXBusError_Unsupported;
+    }
+
+    // send back the value
+    if (valueSize == 1) {                   // 1 byte value
+        *value = recieveBuffer[sendSize + kCmdDataPacketData1];
+        if (*value & 0x0080)
+            *value |= 0xFF00;
+    } else {
+        *value = recieveBuffer[sendSize + kCmdDataPacketData1];
+        *value <<= 8;
+        *value |= recieveBuffer[sendSize + kCmdDataPacketData2];
     }
 
     return kXBusError_NoError;
@@ -406,7 +480,7 @@
     }
 
     // atomic flag on
-    modifyServosNow = 1;
+    modifyServosNow = true;
 
     // add new servo
     dataOffset = kStartOffsetOfCHData + kCHDataSize * numOfServo;
@@ -420,10 +494,10 @@
 
     // calc CRC
     chPacketBuffer[dataOffset + 4] = crc8(chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 2);
-    dirty = 1;
+    dirty = true;
 
     // atomic flag off
-    modifyServosNow = 0;
+    modifyServosNow = false;
 
     return kXBusError_NoError;
 }
@@ -455,7 +529,7 @@
         for (servoNo = 0; servoNo < numOfServo; servoNo++)
             if (chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * servoNo] == channelID) {
                 // atomic flag on
-                modifyServosNow = 1;
+                modifyServosNow = true;
 
                 // copy data after that
                 if (servoNo < (numOfServo - 1))
@@ -470,10 +544,10 @@
                 // calc CRC
                 chPacketBuffer[kStartOffsetOfCHData + kCHDataSize * numOfServo]
                 = crc8(chPacketBuffer, chPacketBuffer[kCHDataPacketLength] + 2);
-                dirty = 1;
+                dirty = true;
 
                 // atomic flag off
-                modifyServosNow = 0;
+                modifyServosNow = false;
 
                 return kXBusError_NoError;
             }
@@ -511,7 +585,7 @@
 
             if (chPacketBuffer[dataOffset] == channelID) {
                 // atomic flag on
-                modifyServosNow = 1;
+                modifyServosNow = true;
 
                 // set value
                 chPacketBuffer[dataOffset + 2] = (value >> 8) & 0x00FF;
@@ -523,7 +597,7 @@
                 dirty = 1;
 
                 // atomic flag off
-                modifyServosNow = 0;
+                modifyServosNow = false;
 
                 return kXBusError_NoError;
             }