SLCAN/CAN-USB implementation for mbed targets
Embed:
(wiki syntax)
Show/hide line numbers
slcan.cpp
00001 #include "slcan.h" 00002 00003 // Helper methods for parsing commands 00004 static bool parse_hex_digits(const char* input, uint8_t num_digits, uint32_t* value_out) { 00005 bool success = true; 00006 uint32_t value = 0; 00007 00008 uint8_t i; 00009 for (i=0; i < num_digits; i++) { 00010 uint32_t nibble = 0; 00011 if (input[i] >= '0' && input[i] <= '9') { 00012 nibble = 0x0 + (input[i] - '0'); 00013 } else if (input[i] >= 'a' && input[i] <= 'f') { 00014 nibble = 0xA + (input[i] - 'a'); 00015 } else if (input[i] >= 'A' && input[i] <= 'F') { 00016 nibble = 0xA + (input[i] - 'A'); 00017 } else { 00018 success = false; 00019 break; 00020 } 00021 uint8_t offset = 4*(num_digits-i-1); 00022 value |= (nibble << offset); 00023 } 00024 00025 if (success) { 00026 *value_out = value; 00027 } 00028 00029 return success; 00030 } 00031 00032 static bool parse_hex_values(const char* input, uint8_t num_values, uint8_t* values_out) { 00033 uint8_t i; 00034 for (i=0; i < num_values; i++) { 00035 uint32_t value; 00036 if (parse_hex_digits(input, 2, &value)) { 00037 values_out[i] = (uint8_t)value; 00038 } else { 00039 return false; 00040 } 00041 input += 2; 00042 } 00043 00044 return true; 00045 } 00046 00047 static bool parse_dec_digit(const char* input, uint8_t* value_out) { 00048 if (input[0] >= '0' && input[0] <= '9') { 00049 *value_out = 0 + (input[0] - '0'); 00050 return true; 00051 } else { 00052 return false; 00053 } 00054 } 00055 00056 static inline char format_nibble(uint8_t x) { 00057 uint8_t nibble = x & 0x0F; 00058 return (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); 00059 } 00060 00061 static inline char format_digit(uint8_t d) { 00062 return '0' + d; 00063 } 00064 00065 SLCANBase::SLCANBase() { 00066 00067 } 00068 00069 SLCANBase::~SLCANBase() { 00070 00071 } 00072 00073 uint8_t SLCANBase::getFirmwareVersion() { 00074 // firmware version in BCD 00075 return 0x10; 00076 } 00077 00078 uint8_t SLCANBase::getHardwareVersion() { 00079 // hardware version in BCD 00080 return 0x10; 00081 } 00082 00083 const char* SLCANBase::getSerialString() { 00084 // 4 character serial number 00085 return "C254"; 00086 } 00087 00088 bool SLCANBase::update() { 00089 bool active = false; 00090 if (processCommands()) { 00091 active = true; 00092 } 00093 if (processCANMessages()) { 00094 active = true; 00095 } 00096 00097 if (active) { 00098 flush(); 00099 } 00100 00101 return active; 00102 } 00103 00104 size_t SLCANBase::formattedCANMessageLength(const CANMessage& msg) { 00105 size_t len; 00106 if (msg.format == CANStandard) { 00107 len = 1 + 3 + 1 + (2 * msg.len) + 1; 00108 } else { 00109 len = 1 + 8 + 1 + (2 * msg.len) + 1; 00110 } 00111 00112 return len; 00113 } 00114 00115 size_t SLCANBase::formatCANMessage(const CANMessage& msg, char* buf, size_t max_len) { 00116 size_t len = formattedCANMessageLength(msg); 00117 if (len > max_len) { 00118 return 0; 00119 } 00120 00121 if (msg.format == CANStandard) { 00122 *buf++ = (msg.type == CANData) ? 't' : 'r'; 00123 *buf++ = format_nibble((uint8_t)(msg.id >> 8)); 00124 *buf++ = format_nibble((uint8_t)(msg.id >> 4)); 00125 *buf++ = format_nibble((uint8_t)(msg.id >> 0)); 00126 *buf++ = format_digit(msg.len); 00127 } else { 00128 *buf++ = (msg.type == CANData) ? 'T' : 'R'; 00129 *buf++ = format_nibble((uint8_t)(msg.id >> 28)); 00130 *buf++ = format_nibble((uint8_t)(msg.id >> 24)); 00131 *buf++ = format_nibble((uint8_t)(msg.id >> 20)); 00132 *buf++ = format_nibble((uint8_t)(msg.id >> 16)); 00133 *buf++ = format_nibble((uint8_t)(msg.id >> 12)); 00134 *buf++ = format_nibble((uint8_t)(msg.id >> 8)); 00135 *buf++ = format_nibble((uint8_t)(msg.id >> 4)); 00136 *buf++ = format_nibble((uint8_t)(msg.id >> 0)); 00137 *buf++ = format_digit(msg.len); 00138 } 00139 00140 for (unsigned char i=0; i < msg.len; i++) { 00141 *buf++ = format_nibble((uint8_t)(msg.data[i] >> 4)); 00142 *buf++ = format_nibble((uint8_t)(msg.data[i] >> 0)); 00143 } 00144 00145 *buf++ = '\r'; 00146 00147 return len; 00148 } 00149 00150 size_t SLCANBase::commandResponseLength(const char* command) { 00151 switch (command[0]) { 00152 case 'N': 00153 case 'V': { 00154 return 6; 00155 } 00156 case 'v': 00157 case 'F': { 00158 return 4; 00159 } 00160 case 'T': 00161 case 't': 00162 case 'R': 00163 case 'r': { 00164 return 2; 00165 } 00166 default: { 00167 return 1; 00168 } 00169 } 00170 } 00171 00172 bool SLCANBase::execCommand(const char* command, char* response) { 00173 bool success = false; 00174 if (response) { 00175 response[0] = '\0'; 00176 } 00177 00178 switch (command[0]) { 00179 // Configuration commands 00180 case 'S': 00181 case 's': 00182 case 'O': 00183 case 'L': 00184 case 'l': 00185 case 'C': 00186 case 'Z': 00187 case 'M': 00188 case 'm': { 00189 success = execConfigCommand(command); 00190 break; 00191 } 00192 // Transmission commands 00193 case 't': 00194 case 'T': 00195 case 'r': 00196 case 'R': { 00197 success = execTransmitCommand(command, response); 00198 break; 00199 } 00200 // Diagnostic commands 00201 case 'V': 00202 case 'v': 00203 case 'N': 00204 case 'W': 00205 case 'F': 00206 success = execDiagnosticCommand(command, response); 00207 break; 00208 default: { 00209 success = false; 00210 break; 00211 } 00212 } 00213 00214 return success; 00215 } 00216 00217 bool SLCANBase::execConfigCommand(const char* command) { 00218 bool success = false; 00219 size_t len = strlen(command); 00220 00221 // Validate command length 00222 if (command[0] == 'M' || command[0] == 'm') { 00223 if (len != 9) { 00224 return false; 00225 } 00226 } else if (command[0] == 's') { 00227 if (!((len == 5) || (len == 7))) { 00228 return false; 00229 } 00230 } else if (command[0] == 'S' || command[0] == 'Z') { 00231 if (len != 2) { 00232 return false; 00233 } 00234 } else if (len != 1) { 00235 return false; 00236 } 00237 00238 switch (command[0]) { 00239 case 'S': { 00240 bool known = true; 00241 int baudrate; 00242 switch (command[1]) { 00243 case '0': baudrate = 10000; break; 00244 case '1': baudrate = 20000; break; 00245 case '2': baudrate = 50000; break; 00246 case '3': baudrate = 100000; break; 00247 case '4': baudrate = 125000; break; 00248 case '5': baudrate = 250000; break; 00249 case '6': baudrate = 500000; break; 00250 case '7': baudrate = 800000; break; 00251 case '8': baudrate = 1000000; break; 00252 default: known = false; break; 00253 } 00254 00255 if (known) { 00256 success = setBaudrate(baudrate); 00257 } 00258 00259 break; 00260 } 00261 case 'O': { 00262 success = setMode(CAN::Normal); 00263 break; 00264 } 00265 case 'L': { 00266 success = setMode(CAN::Silent); 00267 break; 00268 } 00269 case 'l': { 00270 success = setMode(CAN::SilentTest); 00271 break; 00272 } 00273 case 'C': { 00274 success = setMode(CAN::Reset); 00275 break; 00276 } 00277 case 's': { 00278 // TODO: implement direct BTR control 00279 success = true; 00280 break; 00281 } 00282 case 'M': 00283 case 'm': { 00284 // TODO: implement filtering 00285 success = true; 00286 break; 00287 } 00288 case 'Z': { 00289 // TODO: implement timestamping 00290 success = true; 00291 break; 00292 } 00293 default: { 00294 success = false; 00295 break; 00296 } 00297 } 00298 00299 return success; 00300 } 00301 00302 bool SLCANBase::execTransmitCommand(const char* command, char* response) { 00303 bool success = false; 00304 00305 size_t len = strlen(command); 00306 00307 bool validMessage = false; 00308 CANMessage msg; 00309 00310 if (command[0] == 't' || command[0] == 'T') { 00311 msg.type = CANData; 00312 msg.format = (command[0] == 't') ? CANStandard : CANExtended; 00313 size_t idLen = msg.format == CANStandard ? 3 : 8; 00314 if ((len >= idLen + 2) && 00315 parse_hex_digits(&command[1], idLen, (uint32_t*)&msg.id) && 00316 parse_dec_digit(&command[idLen + 1], &msg.len)) { 00317 if ((len == idLen + 2 + 2*msg.len) && 00318 (msg.len <= 8) && 00319 parse_hex_values(&command[idLen + 2], msg.len, msg.data)) { 00320 validMessage = true; 00321 } 00322 } 00323 } else if (command[0] == 'r' || command[0] == 'R') { 00324 msg.type = CANRemote; 00325 msg.format = (command[0] == 'r') ? CANStandard : CANExtended; 00326 size_t idLen = msg.format == CANStandard ? 3 : 8; 00327 if ((len == idLen + 2) && 00328 parse_hex_digits(&command[1], idLen, (uint32_t*)(&msg.id)) && 00329 parse_dec_digit(&command[idLen + 1], &msg.len)) { 00330 if (msg.len <= 8) { 00331 validMessage = true; 00332 } 00333 } 00334 } 00335 00336 if (validMessage) { 00337 if (command[0] == 'T' || command[0] == 'R') { 00338 response[0] = 'Z'; 00339 response[1] = '\0'; 00340 } else if (command[0] == 't' || command[0] == 'r') { 00341 response[0] = 'z'; 00342 response[1] = '\0'; 00343 } 00344 success = transmitMessage(msg); 00345 } 00346 00347 return success; 00348 } 00349 00350 bool SLCANBase::execDiagnosticCommand(const char* command, char* response) { 00351 bool success = false; 00352 size_t len = strlen(command); 00353 00354 // Validate command length 00355 if (command[0] == 'W') { 00356 if (len != 5) { 00357 return false; 00358 } 00359 } else if (len != 1) { 00360 return false; 00361 } 00362 00363 if (!response) { 00364 return false; 00365 } 00366 00367 switch (command[0]) { 00368 case 'V': { 00369 success = true; 00370 uint8_t hwVersion = getHardwareVersion(); 00371 uint8_t fwVersion = getFirmwareVersion(); 00372 00373 response[0] = 'V'; 00374 response[1] = format_nibble(hwVersion >> 4); 00375 response[2] = format_nibble(hwVersion >> 0); 00376 response[3] = format_nibble(fwVersion >> 4); 00377 response[4] = format_nibble(fwVersion >> 0); 00378 response[5] = '\0'; 00379 break; 00380 } 00381 case 'v': { 00382 success = true; 00383 uint8_t fwVersion = getFirmwareVersion(); 00384 response[0] = 'v'; 00385 response[1] = format_nibble(fwVersion >> 4); 00386 response[2] = format_nibble(fwVersion >> 0); 00387 response[3] = '\0'; 00388 break; 00389 } 00390 case 'N': { 00391 success = true; 00392 const char* serial = getSerialString(); 00393 size_t index = 0; 00394 response[index++] = 'N'; 00395 for (int i=0; i < 4; i++) { 00396 char c = serial[i]; 00397 if (c == '\0') { 00398 break; 00399 } else { 00400 response[index++] = c; 00401 } 00402 } 00403 response[index] = '\0'; 00404 break; 00405 } 00406 case 'F': { 00407 success = true; 00408 uint8_t status = 0x00; 00409 response[0] = 'F'; 00410 response[1] = format_nibble(status >> 4); 00411 response[2] = format_nibble(status >> 0); 00412 response[3] = '\0'; 00413 } 00414 case 'W': { 00415 // Just swallow the MCP2515 register write command 00416 success = true; 00417 break; 00418 } 00419 default: { 00420 success = false; 00421 break; 00422 } 00423 } 00424 00425 return success; 00426 } 00427 00428 USBSLCAN::USBSLCAN(USBSerial& stream, CAN& can) 00429 : stream(stream), 00430 can(can), 00431 messageQueued(false), 00432 commandQueued(false), 00433 commandOverflow(false), 00434 inputCommandLen(0), 00435 outputPacketLen(0) { 00436 00437 } 00438 00439 bool USBSLCAN::setBaudrate(int baudrate) { 00440 return (can.frequency(baudrate) == 1); 00441 } 00442 00443 bool USBSLCAN::setMode(CAN::Mode mode) { 00444 return (can.mode(mode) == 1); 00445 } 00446 00447 bool USBSLCAN::transmitMessage(CANMessage& msg) { 00448 return (can.write(msg) == 1); 00449 } 00450 00451 bool USBSLCAN::getNextCANMessage(CANMessage& msg) { 00452 return (can.read(msg) == 1); 00453 } 00454 00455 /* Parse and execute a single SLCAN command and enqueue the response */ 00456 bool USBSLCAN::processCommands() { 00457 bool active = false; 00458 00459 // Buffer an entire command 00460 while (!commandQueued && stream.readable()) { 00461 char c = (char)stream.getc(); 00462 if (c == '\r') { 00463 if (commandOverflow) { 00464 // Replace with a dummy invalid command so we return an error 00465 inputCommandBuffer[0] = '!'; 00466 inputCommandBuffer[1] = '\0'; 00467 inputCommandLen = 0; 00468 commandOverflow = false; 00469 active = true; 00470 } else { 00471 // Null-terminate the buffered command 00472 inputCommandBuffer[inputCommandLen] = '\0'; 00473 inputCommandLen = 0; 00474 active = true; 00475 } 00476 commandQueued = true; 00477 } else if (c == '\n' && inputCommandLen == 0) { 00478 // Ignore line feeds immediately after a carriage return 00479 } else if (commandOverflow) { 00480 // Swallow the rest of the command when overflow occurs 00481 } else { 00482 // Append to the end of the command 00483 inputCommandBuffer[inputCommandLen++] = c; 00484 00485 if (inputCommandLen >= sizeof(inputCommandBuffer)) { 00486 commandOverflow = true; 00487 } 00488 } 00489 } 00490 00491 // Process the current command if there's space to send the response 00492 if (commandQueued) { 00493 size_t responseLength = commandResponseLength(inputCommandBuffer); 00494 if ((outputPacketLen + responseLength) <= sizeof(outputPacketBuffer)) { 00495 char outputResponseBuffer[32]; 00496 outputResponseBuffer[0] = '\0'; 00497 if (execCommand(inputCommandBuffer, outputResponseBuffer)) { 00498 // Success 00499 for (char* s = outputResponseBuffer; *s != '\0'; s++) { 00500 outputPacketBuffer[outputPacketLen++] = *s; 00501 } 00502 outputPacketBuffer[outputPacketLen++] = '\r'; 00503 } else { 00504 // Failure 00505 outputPacketBuffer[outputPacketLen++] = '\a'; 00506 } 00507 commandQueued = false; 00508 active = true; 00509 } 00510 } 00511 00512 return active; 00513 } 00514 00515 /* Read and enqueue as many received CAN messages as will fit */ 00516 bool USBSLCAN::processCANMessages() { 00517 bool active = false; 00518 00519 size_t bytesAvailable = sizeof(outputPacketBuffer) - outputPacketLen; 00520 char* packetTail = &outputPacketBuffer[outputPacketLen]; 00521 00522 if (messageQueued) { 00523 size_t bytesConsumed = formatCANMessage(queuedMessage, packetTail, bytesAvailable); 00524 if (bytesConsumed > 0) { 00525 active = true; 00526 messageQueued = false; 00527 bytesAvailable -= bytesConsumed; 00528 packetTail += bytesConsumed; 00529 outputPacketLen += bytesConsumed; 00530 } 00531 } 00532 00533 if (!messageQueued) { 00534 while (getNextCANMessage(queuedMessage)) { 00535 size_t bytesConsumed = formatCANMessage(queuedMessage, packetTail, bytesAvailable); 00536 if (bytesConsumed > 0) { 00537 active = true; 00538 bytesAvailable -= bytesConsumed; 00539 packetTail += bytesConsumed; 00540 outputPacketLen += bytesConsumed; 00541 } else { 00542 messageQueued = true; 00543 break; 00544 } 00545 } 00546 } 00547 00548 return active; 00549 } 00550 00551 /* Attempt to transmit the output queue */ 00552 bool USBSLCAN::flush() { 00553 bool active = false; 00554 if (outputPacketLen > 0) { 00555 bool sent = stream.writeBlock((uint8_t*)(outputPacketBuffer), 00556 (uint16_t)(outputPacketLen)); 00557 if (sent) { 00558 active = true; 00559 outputPacketLen = 0; 00560 } 00561 } 00562 return active; 00563 } 00564 00565 SerialSLCAN::SerialSLCAN(Serial& stream, CAN& can) 00566 : stream(stream), 00567 can(can), 00568 commandQueued(false), 00569 commandOverflow(false), 00570 inputCommandLen(0) { 00571 } 00572 00573 bool SerialSLCAN::setBaudrate(int baudrate) { 00574 return (can.frequency(baudrate) == 1); 00575 } 00576 00577 bool SerialSLCAN::setMode(CAN::Mode mode) { 00578 return (can.mode(mode) == 1); 00579 } 00580 00581 bool SerialSLCAN::transmitMessage(CANMessage& msg) { 00582 return (can.write(msg) == 1); 00583 } 00584 00585 bool SerialSLCAN::getNextCANMessage(CANMessage& msg) { 00586 return (can.read(msg) == 1); 00587 } 00588 00589 /* Parse and execute a single SLCAN command and enqueue the response */ 00590 bool SerialSLCAN::processCommands() { 00591 bool active = false; 00592 00593 // Buffer an entire command 00594 while (!commandQueued && stream.readable()) { 00595 char c = (char)stream.getc(); 00596 if (c == '\r') { 00597 if (commandOverflow) { 00598 // Replace with a dummy invalid command so we return an error 00599 inputCommandBuffer[0] = '!'; 00600 inputCommandBuffer[1] = '\0'; 00601 inputCommandLen = 0; 00602 commandOverflow = false; 00603 active = true; 00604 } else { 00605 // Null-terminate the buffered command 00606 inputCommandBuffer[inputCommandLen] = '\0'; 00607 inputCommandLen = 0; 00608 active = true; 00609 } 00610 commandQueued = true; 00611 } else if (c == '\n' && inputCommandLen == 0) { 00612 // Ignore line feeds immediately after a carriage return 00613 } else if (commandOverflow) { 00614 // Swallow the rest of the command when overflow occurs 00615 } else { 00616 // Append to the end of the command 00617 inputCommandBuffer[inputCommandLen++] = c; 00618 00619 if (inputCommandLen >= sizeof(inputCommandBuffer)) { 00620 commandOverflow = true; 00621 } 00622 } 00623 } 00624 00625 // Process the current command 00626 if (commandQueued) { 00627 char outputResponseBuffer[32]; 00628 outputResponseBuffer[0] = '\0'; 00629 if (execCommand(inputCommandBuffer, outputResponseBuffer)) { 00630 // Success 00631 stream.puts(outputResponseBuffer); 00632 stream.putc('\r'); 00633 } else { 00634 // Failure 00635 stream.putc('\a'); 00636 } 00637 commandQueued = false; 00638 active = true; 00639 } 00640 00641 return active; 00642 } 00643 00644 /* Read and enqueue as many received CAN messages as will fit */ 00645 bool SerialSLCAN::processCANMessages() { 00646 bool active = false; 00647 CANMessage msg; 00648 while (getNextCANMessage(msg)) { 00649 char buffer[32]; 00650 size_t len = formatCANMessage(msg, buffer, sizeof(buffer)); 00651 buffer[len] = '\0'; 00652 stream.puts(buffer); 00653 active = true; 00654 } 00655 00656 return active; 00657 } 00658 00659 /* Attempt to transmit the output queue */ 00660 bool SerialSLCAN::flush() { 00661 return false; 00662 }
Generated on Sun Jul 24 2022 20:02:47 by
1.7.2