master/fsm_coe.c
changeset 1562 5c249f469b81
parent 1550 81a16ba13ae6
child 1563 ddedb71b3a85
equal deleted inserted replaced
1561:89f6cd5b90ff 1562:5c249f469b81
    60 
    60 
    61 void ec_fsm_coe_down_start(ec_fsm_coe_t *);
    61 void ec_fsm_coe_down_start(ec_fsm_coe_t *);
    62 void ec_fsm_coe_down_request(ec_fsm_coe_t *);
    62 void ec_fsm_coe_down_request(ec_fsm_coe_t *);
    63 void ec_fsm_coe_down_check(ec_fsm_coe_t *);
    63 void ec_fsm_coe_down_check(ec_fsm_coe_t *);
    64 void ec_fsm_coe_down_response(ec_fsm_coe_t *);
    64 void ec_fsm_coe_down_response(ec_fsm_coe_t *);
       
    65 void ec_fsm_coe_down_seg_check(ec_fsm_coe_t *);
       
    66 void ec_fsm_coe_down_seg_response(ec_fsm_coe_t *);
    65 
    67 
    66 void ec_fsm_coe_up_start(ec_fsm_coe_t *);
    68 void ec_fsm_coe_up_start(ec_fsm_coe_t *);
    67 void ec_fsm_coe_up_request(ec_fsm_coe_t *);
    69 void ec_fsm_coe_up_request(ec_fsm_coe_t *);
    68 void ec_fsm_coe_up_check(ec_fsm_coe_t *);
    70 void ec_fsm_coe_up_check(ec_fsm_coe_t *);
    69 void ec_fsm_coe_up_response(ec_fsm_coe_t *);
    71 void ec_fsm_coe_up_response(ec_fsm_coe_t *);
  1069 {
  1071 {
  1070     ec_datagram_t *datagram = fsm->datagram;
  1072     ec_datagram_t *datagram = fsm->datagram;
  1071     ec_slave_t *slave = fsm->slave;
  1073     ec_slave_t *slave = fsm->slave;
  1072     ec_sdo_request_t *request = fsm->request;
  1074     ec_sdo_request_t *request = fsm->request;
  1073     uint8_t *data;
  1075     uint8_t *data;
  1074     uint8_t size;
  1076     uint8_t data_set_size;
  1075 
  1077 
  1076     if (fsm->slave->master->debug_level) {
  1078     if (fsm->slave->master->debug_level) {
  1077         char subidxstr[10];
  1079         char subidxstr[10];
  1078         if (request->complete_access) {
  1080         if (request->complete_access) {
  1079             subidxstr[0] = 0x00;
  1081             subidxstr[0] = 0x00;
  1089         EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
  1091         EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
  1090         fsm->state = ec_fsm_coe_error;
  1092         fsm->state = ec_fsm_coe_error;
  1091         return;
  1093         return;
  1092     }
  1094     }
  1093 
  1095 
       
  1096     if (slave->configured_rx_mailbox_size < 16) {
       
  1097         EC_ERR("Mailbox too small!\n");
       
  1098         fsm->state = ec_fsm_coe_error;
       
  1099         return;
       
  1100     }
       
  1101 
  1094     if (request->data_size <= 4) { // use expedited transfer type
  1102     if (request->data_size <= 4) { // use expedited transfer type
  1095         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 10);
  1103         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 10);
  1096         if (IS_ERR(data)) {
  1104         if (IS_ERR(data)) {
  1097             fsm->state = ec_fsm_coe_error;
  1105             fsm->state = ec_fsm_coe_error;
  1098             return;
  1106             return;
  1099         }
  1107         }
  1100 
  1108 
  1101         size = 4 - request->data_size;
  1109         fsm->remaining = 0;
       
  1110 
       
  1111         data_set_size = 4 - request->data_size;
  1102 
  1112 
  1103         EC_WRITE_U16(data, 0x2 << 12); // SDO request
  1113         EC_WRITE_U16(data, 0x2 << 12); // SDO request
  1104         EC_WRITE_U8 (data + 2, (0x3 // size specified, expedited
  1114         EC_WRITE_U8 (data + 2, (0x3 // size specified, expedited
  1105                     | size << 2
  1115                     | data_set_size << 2
  1106                     | ((request->complete_access ? 1 : 0) << 4) 
  1116                     | ((request->complete_access ? 1 : 0) << 4) 
  1107                     | 0x1 << 5)); // Download request
  1117                     | 0x1 << 5)); // Download request
  1108         EC_WRITE_U16(data + 3, request->index);
  1118         EC_WRITE_U16(data + 3, request->index);
  1109         EC_WRITE_U8 (data + 5,
  1119         EC_WRITE_U8 (data + 5,
  1110                 request->complete_access ? 0x00 : request->subindex);
  1120                 request->complete_access ? 0x00 : request->subindex);
  1115             EC_DBG("Expedited download request:\n");
  1125             EC_DBG("Expedited download request:\n");
  1116             ec_print_data(data, 10);
  1126             ec_print_data(data, 10);
  1117         }
  1127         }
  1118     }
  1128     }
  1119     else { // request->data_size > 4, use normal transfer type
  1129     else { // request->data_size > 4, use normal transfer type
  1120         if (slave->configured_rx_mailbox_size < 6 + 10 + request->data_size) {
  1130         size_t data_size;
  1121             EC_ERR("SDO fragmenting not supported yet!\n"); // FIXME
  1131 
  1122             fsm->state = ec_fsm_coe_error;
  1132         if (slave->configured_rx_mailbox_size <
  1123             return;
  1133                 6 + 10 + request->data_size) {
       
  1134             // segmenting needed
       
  1135             data_size = slave->configured_rx_mailbox_size - 6;
       
  1136         } else {
       
  1137             data_size = 10 + request->data_size;
  1124         }
  1138         }
  1125 
  1139 
  1126         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03,
  1140         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03,
  1127                 request->data_size + 10);
  1141                 data_size);
  1128         if (IS_ERR(data)) {
  1142         if (IS_ERR(data)) {
  1129             fsm->state = ec_fsm_coe_error;
  1143             fsm->state = ec_fsm_coe_error;
  1130             return;
  1144             return;
  1131         }
  1145         }
       
  1146 
       
  1147         fsm->offset = 0;
       
  1148         fsm->remaining = request->data_size;
  1132 
  1149 
  1133         EC_WRITE_U16(data, 0x2 << 12); // SDO request
  1150         EC_WRITE_U16(data, 0x2 << 12); // SDO request
  1134         EC_WRITE_U8 (data + 2, (0x1 // size indicator, normal
  1151         EC_WRITE_U8 (data + 2, (0x1 // size indicator, normal
  1135                     | ((request->complete_access ? 1 : 0) << 4) 
  1152                     | ((request->complete_access ? 1 : 0) << 4) 
  1136                     | 0x1 << 5)); // Download request
  1153                     | 0x1 << 5)); // Download request
  1137         EC_WRITE_U16(data + 3, request->index);
  1154         EC_WRITE_U16(data + 3, request->index);
  1138         EC_WRITE_U8 (data + 5,
  1155         EC_WRITE_U8 (data + 5,
  1139                 request->complete_access ? 0x00 : request->subindex);
  1156                 request->complete_access ? 0x00 : request->subindex);
  1140         EC_WRITE_U32(data + 6, request->data_size);
  1157         EC_WRITE_U32(data + 6, request->data_size);
  1141         memcpy(data + 10, request->data, request->data_size);
  1158 
       
  1159         if (data_size > 10) {
       
  1160             size_t segment_size = data_size - 10;
       
  1161             fsm->remaining -= segment_size;
       
  1162             memcpy(data + 10, request->data, segment_size);
       
  1163             fsm->offset += segment_size;
       
  1164         }
  1142 
  1165 
  1143         if (slave->master->debug_level) {
  1166         if (slave->master->debug_level) {
  1144             EC_DBG("Normal download request:\n");
  1167             EC_DBG("Normal download request:\n");
  1145             ec_print_data(data, 10 + request->data_size);
  1168             ec_print_data(data, data_size);
  1146         }
  1169         }
  1147     }
  1170     }
  1148 
  1171 
  1149     fsm->request->jiffies_sent = jiffies;
  1172     fsm->request->jiffies_sent = jiffies;
  1150     fsm->retries = EC_FSM_RETRIES;
  1173     fsm->retries = EC_FSM_RETRIES;
  1355         fsm->retries = EC_FSM_RETRIES;
  1378         fsm->retries = EC_FSM_RETRIES;
  1356         fsm->state = ec_fsm_coe_down_check;
  1379         fsm->state = ec_fsm_coe_down_check;
  1357         return;
  1380         return;
  1358     }
  1381     }
  1359 
  1382 
  1360     fsm->state = ec_fsm_coe_end; // success
  1383     if (fsm->remaining) { // more segments to download
       
  1384         size_t max_segment_size = slave->configured_rx_mailbox_size - 9;
       
  1385         size_t segment_size, data_size;
       
  1386         uint8_t last_segment, seg_data_size;
       
  1387 
       
  1388         if (fsm->remaining > max_segment_size) {
       
  1389             segment_size = max_segment_size;
       
  1390             last_segment = 0;
       
  1391         } else {
       
  1392             segment_size = fsm->remaining;
       
  1393             last_segment = 1;
       
  1394         }
       
  1395 
       
  1396         if (segment_size > 7) {
       
  1397             seg_data_size = 0x00;
       
  1398             data_size = 3 + segment_size;
       
  1399         } else {
       
  1400             seg_data_size = 7 - segment_size;
       
  1401             data_size = 10;
       
  1402         }
       
  1403 
       
  1404         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03,
       
  1405                 data_size);
       
  1406         if (IS_ERR(data)) {
       
  1407             fsm->state = ec_fsm_coe_error;
       
  1408             return;
       
  1409         }
       
  1410 
       
  1411         fsm->toggle = 0;
       
  1412 
       
  1413         EC_WRITE_U16(data, 0x2 << 12); // SDO request
       
  1414         EC_WRITE_U8(data + 2, (last_segment ? 1 : 0)
       
  1415                 | (seg_data_size << 1) 
       
  1416                 | (fsm->toggle << 4)
       
  1417                 | (0x00 << 5)); // Download segment request
       
  1418         memcpy(data + 3, request->data + fsm->offset, segment_size);
       
  1419         if (segment_size < 7) {
       
  1420             memset(data + 3 + segment_size, 0x00, 7 - segment_size);
       
  1421         }
       
  1422 
       
  1423         fsm->offset += segment_size;
       
  1424         fsm->remaining -= segment_size;
       
  1425 
       
  1426         if (slave->master->debug_level) {
       
  1427             EC_DBG("Download segment request:\n");
       
  1428             ec_print_data(data, data_size);
       
  1429         }
       
  1430 
       
  1431         fsm->state = ec_fsm_coe_down_seg_check; // success
       
  1432     } else {
       
  1433         fsm->state = ec_fsm_coe_end; // success
       
  1434     }
       
  1435 }
       
  1436 
       
  1437 /*****************************************************************************/
       
  1438 
       
  1439 /**
       
  1440    CoE state: DOWN SEG CHECK.
       
  1441 */
       
  1442 
       
  1443 void ec_fsm_coe_down_seg_check(ec_fsm_coe_t *fsm /**< finite state machine */)
       
  1444 {
       
  1445     ec_datagram_t *datagram = fsm->datagram;
       
  1446     ec_slave_t *slave = fsm->slave;
       
  1447 
       
  1448     if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
       
  1449         return;
       
  1450 
       
  1451     if (datagram->state != EC_DATAGRAM_RECEIVED) {
       
  1452         fsm->state = ec_fsm_coe_error;
       
  1453         EC_ERR("Failed to receive CoE mailbox check datagram for slave %u"
       
  1454                 " (datagram state %u).\n",
       
  1455                slave->ring_position, datagram->state);
       
  1456         return;
       
  1457     }
       
  1458 
       
  1459     if (datagram->working_counter != 1) {
       
  1460         fsm->state = ec_fsm_coe_error;
       
  1461         EC_ERR("Reception of CoE mailbox segment check"
       
  1462                 " datagram failed on slave %u: ", slave->ring_position);
       
  1463         ec_datagram_print_wc_error(datagram);
       
  1464         return;
       
  1465     }
       
  1466 
       
  1467     if (!ec_slave_mbox_check(datagram)) {
       
  1468         unsigned long diff_ms =
       
  1469             (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
       
  1470         if (diff_ms >= fsm->request->response_timeout) {
       
  1471             fsm->state = ec_fsm_coe_error;
       
  1472             EC_ERR("Timeout while waiting for SDO download segment response "
       
  1473                     "on slave %u.\n", slave->ring_position);
       
  1474             return;
       
  1475         }
       
  1476 
       
  1477         ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
  1478         fsm->retries = EC_FSM_RETRIES;
       
  1479         return;
       
  1480     }
       
  1481 
       
  1482     // Fetch response
       
  1483     ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
       
  1484     fsm->retries = EC_FSM_RETRIES;
       
  1485     fsm->state = ec_fsm_coe_down_seg_response;
       
  1486 }
       
  1487 
       
  1488 /*****************************************************************************/
       
  1489 
       
  1490 /**
       
  1491    CoE state: DOWN SEG RESPONSE.
       
  1492    \todo Timeout behavior
       
  1493 */
       
  1494 
       
  1495 void ec_fsm_coe_down_seg_response(
       
  1496         ec_fsm_coe_t *fsm /**< finite state machine */
       
  1497         )
       
  1498 {
       
  1499     ec_datagram_t *datagram = fsm->datagram;
       
  1500     ec_slave_t *slave = fsm->slave;
       
  1501     uint8_t *data, mbox_prot;
       
  1502     size_t rec_size;
       
  1503     ec_sdo_request_t *request = fsm->request;
       
  1504 
       
  1505     if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
       
  1506         return; // FIXME: request again?
       
  1507 
       
  1508     if (datagram->state != EC_DATAGRAM_RECEIVED) {
       
  1509         fsm->state = ec_fsm_coe_error;
       
  1510         EC_ERR("Failed to receive CoE download response datagram from"
       
  1511                " slave %u (datagram state %u).\n",
       
  1512                slave->ring_position, datagram->state);
       
  1513         return;
       
  1514     }
       
  1515 
       
  1516     if (datagram->working_counter != 1) {
       
  1517         fsm->state = ec_fsm_coe_error;
       
  1518         EC_ERR("Reception of CoE download response failed on slave %u: ",
       
  1519                 slave->ring_position);
       
  1520         ec_datagram_print_wc_error(datagram);
       
  1521         return;
       
  1522     }
       
  1523 
       
  1524     data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
       
  1525     if (IS_ERR(data)) {
       
  1526         fsm->state = ec_fsm_coe_error;
       
  1527         return;
       
  1528     }
       
  1529 
       
  1530     if (mbox_prot != 0x03) { // CoE
       
  1531         fsm->state = ec_fsm_coe_error;
       
  1532         EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
       
  1533         return;
       
  1534     }
       
  1535 
       
  1536     if (ec_fsm_coe_check_emergency(fsm, data, rec_size)) {
       
  1537         // check for CoE response again
       
  1538         ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
  1539         fsm->retries = EC_FSM_RETRIES;
       
  1540         fsm->state = ec_fsm_coe_down_check;
       
  1541         return;
       
  1542     }
       
  1543 
       
  1544     if (slave->master->debug_level) {
       
  1545         EC_DBG("Download response:\n");
       
  1546         ec_print_data(data, rec_size);
       
  1547     }
       
  1548 
       
  1549     if (rec_size < 6) {
       
  1550         fsm->state = ec_fsm_coe_error;
       
  1551         EC_ERR("Received data are too small (%zu bytes):\n", rec_size);
       
  1552         ec_print_data(data, rec_size);
       
  1553         return;
       
  1554     }
       
  1555 
       
  1556     if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
       
  1557         EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
       
  1558         char subidxstr[10];
       
  1559         fsm->state = ec_fsm_coe_error;
       
  1560         if (request->complete_access) {
       
  1561             subidxstr[0] = 0x00;
       
  1562         } else {
       
  1563             sprintf(subidxstr, ":%02X", request->subindex);
       
  1564         }
       
  1565         EC_ERR("SDO download 0x%04X%s (%zu bytes) aborted on slave %u.\n",
       
  1566                 request->index, subidxstr, request->data_size,
       
  1567                 slave->ring_position);
       
  1568         if (rec_size < 10) {
       
  1569             EC_ERR("Incomplete abort command:\n");
       
  1570             ec_print_data(data, rec_size);
       
  1571         } else {
       
  1572             fsm->request->abort_code = EC_READ_U32(data + 6);
       
  1573             ec_canopen_abort_msg(fsm->request->abort_code);
       
  1574         }
       
  1575         return;
       
  1576     }
       
  1577 
       
  1578     if (EC_READ_U16(data) >> 12 != 0x3 ||
       
  1579             ((EC_READ_U8(data + 2) >> 5) != 0x01)) { // segment response
       
  1580         if (slave->master->debug_level) {
       
  1581             EC_DBG("Invalid SDO download response at slave %u! Retrying...\n",
       
  1582                     slave->ring_position);
       
  1583             ec_print_data(data, rec_size);
       
  1584         }
       
  1585         // check for CoE response again
       
  1586         ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
  1587         fsm->retries = EC_FSM_RETRIES;
       
  1588         fsm->state = ec_fsm_coe_down_seg_check;
       
  1589         return;
       
  1590     }
       
  1591 
       
  1592     if (((EC_READ_U8(data + 2) >> 4) & 0x01) != fsm->toggle) {
       
  1593         EC_ERR("Invalid toggle received during segmented download:\n");
       
  1594         ec_print_data(data, rec_size);
       
  1595         fsm->state = ec_fsm_coe_error;
       
  1596         return;
       
  1597     }
       
  1598 
       
  1599     if (fsm->remaining) { // more segments to download
       
  1600         size_t max_segment_size = slave->configured_rx_mailbox_size - 9;
       
  1601         size_t segment_size, data_size;
       
  1602         uint8_t last_segment, seg_data_size;
       
  1603 
       
  1604         if (fsm->remaining > max_segment_size) {
       
  1605             segment_size = max_segment_size;
       
  1606             last_segment = 0;
       
  1607         } else {
       
  1608             segment_size = fsm->remaining;
       
  1609             last_segment = 1;
       
  1610         }
       
  1611 
       
  1612         if (segment_size > 7) {
       
  1613             seg_data_size = 0x00;
       
  1614             data_size = 3 + segment_size;
       
  1615         } else {
       
  1616             seg_data_size = 7 - segment_size;
       
  1617             data_size = 10;
       
  1618         }
       
  1619 
       
  1620         data = ec_slave_mbox_prepare_send(slave, datagram, 0x03,
       
  1621                 data_size);
       
  1622         if (IS_ERR(data)) {
       
  1623             fsm->state = ec_fsm_coe_error;
       
  1624             return;
       
  1625         }
       
  1626 
       
  1627         fsm->toggle = !fsm->toggle;
       
  1628 
       
  1629         EC_WRITE_U16(data, 0x2 << 12); // SDO request
       
  1630         EC_WRITE_U8(data + 2, (last_segment ? 1 : 0)
       
  1631                 | (seg_data_size << 1) 
       
  1632                 | (fsm->toggle << 4)
       
  1633                 | (0x00 << 5)); // Download segment request
       
  1634         memcpy(data + 3, request->data + fsm->offset, segment_size);
       
  1635         if (segment_size < 7) {
       
  1636             memset(data + 3 + segment_size, 0x00, 7 - segment_size);
       
  1637         }
       
  1638 
       
  1639         fsm->offset += segment_size;
       
  1640         fsm->remaining -= segment_size;
       
  1641 
       
  1642         if (slave->master->debug_level) {
       
  1643             EC_DBG("Download segment request:\n");
       
  1644             ec_print_data(data, data_size);
       
  1645         }
       
  1646 
       
  1647         fsm->state = ec_fsm_coe_down_seg_check; // success
       
  1648     } else {
       
  1649         fsm->state = ec_fsm_coe_end; // success
       
  1650     }
  1361 }
  1651 }
  1362 
  1652 
  1363 /*****************************************************************************/
  1653 /*****************************************************************************/
  1364 
  1654 
  1365 /**
  1655 /**