master/slave.c
changeset 980 c07dd38243ba
parent 979 405cc2d033e0
child 992 50a44cbd30af
equal deleted inserted replaced
979:405cc2d033e0 980:c07dd38243ba
    55 /*****************************************************************************/
    55 /*****************************************************************************/
    56 
    56 
    57 void ec_slave_clear(struct kobject *);
    57 void ec_slave_clear(struct kobject *);
    58 void ec_slave_sdos_clear(struct kobject *);
    58 void ec_slave_sdos_clear(struct kobject *);
    59 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
    59 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
    60 ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *,
       
    61                                  const char *, size_t);
       
    62 char *ec_slave_sii_string(ec_slave_t *, unsigned int);
    60 char *ec_slave_sii_string(ec_slave_t *, unsigned int);
    63 
    61 
    64 /*****************************************************************************/
    62 /*****************************************************************************/
    65 
    63 
    66 /** \cond */
    64 /** \cond */
    67 
    65 
    68 EC_SYSFS_READ_ATTR(info);
    66 EC_SYSFS_READ_ATTR(info);
    69 EC_SYSFS_READ_WRITE_ATTR(sii);
       
    70 EC_SYSFS_READ_WRITE_ATTR(alias);
       
    71 
    67 
    72 static struct attribute *def_attrs[] = {
    68 static struct attribute *def_attrs[] = {
    73     &attr_info,
    69     &attr_info,
    74     &attr_sii,
       
    75     &attr_alias,
       
    76     NULL,
    70     NULL,
    77 };
    71 };
    78 
    72 
    79 static struct sysfs_ops sysfs_ops = {
    73 static struct sysfs_ops sysfs_ops = {
    80     .show = ec_show_slave_attribute,
    74     .show = ec_show_slave_attribute,
    81     .store = ec_store_slave_attribute
       
    82 };
    75 };
    83 
    76 
    84 static struct kobj_type ktype_ec_slave = {
    77 static struct kobj_type ktype_ec_slave = {
    85     .release = ec_slave_clear,
    78     .release = ec_slave_clear,
    86     .sysfs_ops = &sysfs_ops,
    79     .sysfs_ops = &sysfs_ops,
   846 }
   839 }
   847 
   840 
   848 /*****************************************************************************/
   841 /*****************************************************************************/
   849 
   842 
   850 /**
   843 /**
   851  * Schedules an SII write request.
   844  * Writes SII contents to a slave.
   852  * \return 0 case of success, otherwise error code.
   845  * \return Zero on success, otherwise error code.
   853  */
   846  */
   854 
   847 
   855 int ec_slave_schedule_sii_writing(
   848 int ec_slave_write_sii(
   856         ec_sii_write_request_t *request /**< SII write request */
   849         ec_slave_t *slave, /**< EtherCAT slave */
   857         )
   850         uint16_t offset, /**< SII word offset. */
   858 {
   851         unsigned int nwords, /**< Number of words. */
   859     ec_master_t *master = request->slave->master;
   852         const uint16_t *words /**< New SII data. */
   860 
   853         )
   861     request->state = EC_REQUEST_QUEUED;
   854 {
   862 
   855     ec_master_t *master = slave->master;
   863     // schedule SII write request.
       
   864     down(&master->sii_sem);
       
   865     list_add_tail(&request->list, &master->sii_requests);
       
   866     up(&master->sii_sem);
       
   867 
       
   868     // wait for processing through FSM
       
   869     if (wait_event_interruptible(master->sii_queue,
       
   870                 request->state != EC_REQUEST_QUEUED)) {
       
   871         // interrupted by signal
       
   872         down(&master->sii_sem);
       
   873         if (request->state == EC_REQUEST_QUEUED) {
       
   874             list_del(&request->list);
       
   875             up(&master->sii_sem);
       
   876             return -EINTR;
       
   877         }
       
   878         // request already processing: interrupt not possible.
       
   879         up(&master->sii_sem);
       
   880     }
       
   881 
       
   882     // wait until master FSM has finished processing
       
   883     wait_event(master->sii_queue,
       
   884             request->state != EC_REQUEST_BUSY);
       
   885 
       
   886     return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
       
   887 }
       
   888 
       
   889 /*****************************************************************************/
       
   890 
       
   891 /**
       
   892  * Calculates the SII checksum field.
       
   893  *
       
   894  * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
       
   895  * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
       
   896  *
       
   897  * The below code was originally generated with PYCRC
       
   898  * http://www.tty1.net/pycrc
       
   899  *
       
   900  * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
       
   901  *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
       
   902  *
       
   903  * \return CRC8
       
   904  */
       
   905 
       
   906 uint8_t ec_slave_sii_crc(
       
   907         const uint8_t *data, /**< pointer to data */
       
   908         size_t length /**< number of bytes in \a data */
       
   909         )
       
   910 {
       
   911     unsigned int i;
       
   912     uint8_t bit, byte, crc = 0x48;
       
   913 
       
   914     while (length--) {
       
   915         byte = *data++;
       
   916         for (i = 0; i < 8; i++) {
       
   917             bit = crc & 0x80;
       
   918             crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
       
   919             if (bit) crc ^= 0x07;
       
   920         }
       
   921     }
       
   922 
       
   923     for (i = 0; i < 8; i++) {
       
   924         bit = crc & 0x80;
       
   925         crc <<= 1;
       
   926         if (bit) crc ^= 0x07;
       
   927     }
       
   928 
       
   929     return crc;
       
   930 }
       
   931 
       
   932 /*****************************************************************************/
       
   933 
       
   934 /**
       
   935  * Writes complete SII contents to a slave.
       
   936  * \return data size written in case of success, otherwise error code.
       
   937  */
       
   938 
       
   939 ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */
       
   940         const uint8_t *data, /**< new SII data */
       
   941         size_t size /**< size of data in bytes */
       
   942         )
       
   943 {
       
   944     ec_sii_write_request_t request;
   856     ec_sii_write_request_t request;
   945     const uint16_t *cat_header;
       
   946     uint16_t cat_type, cat_size;
       
   947     int ret;
       
   948     uint8_t crc;
       
   949 
       
   950     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
       
   951         EC_ERR("Writing SIIs only allowed in idle mode!\n");
       
   952         return -EBUSY;
       
   953     }
       
   954 
       
   955     if (size % 2) {
       
   956         EC_ERR("SII data size is odd (%u bytes)! SII data must be"
       
   957                 " word-aligned. Dropping.\n", size);
       
   958         return -EINVAL;
       
   959     }
       
   960 
   857 
   961     // init SII write request
   858     // init SII write request
   962     INIT_LIST_HEAD(&request.list);
   859     INIT_LIST_HEAD(&request.list);
   963     request.slave = slave;
   860     request.slave = slave;
   964     request.words = (const uint16_t *) data;
   861     request.words = words;
   965     request.offset = 0;
   862     request.offset = offset;
   966     request.nwords = size / 2;
   863     request.nwords = nwords;
   967 
   864     request.state = EC_REQUEST_QUEUED;
   968     if (request.nwords < 0x0041) {
   865 
   969         EC_ERR("SII data too short (%u words)! Mimimum is"
   866     // schedule SII write request.
   970                 " 40 fixed words + 1 delimiter. Dropping.\n",
   867     down(&master->sii_sem);
   971                 request.nwords);
   868     list_add_tail(&request.list, &master->sii_requests);
   972         return -EINVAL;
   869     up(&master->sii_sem);
   973     }
   870 
   974 
   871     // wait for processing through FSM
   975     // calculate checksum
   872     if (wait_event_interruptible(master->sii_queue,
   976     crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6
   873                 request.state != EC_REQUEST_QUEUED)) {
   977     if (crc != data[14]) {
   874         // interrupted by signal
   978         EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc);
   875         down(&master->sii_sem);
   979     }
   876         if (request.state == EC_REQUEST_QUEUED) {
   980 
   877             list_del(&request.list);
   981     cat_header = request.words + EC_FIRST_SII_CATEGORY_OFFSET;
   878             up(&master->sii_sem);
   982     cat_type = EC_READ_U16(cat_header);
   879             return -EINTR;
   983     while (cat_type != 0xFFFF) { // cycle through categories
   880         }
   984         if (cat_header + 1 > request.words + request.nwords) {
   881         // request already processing: interrupt not possible.
   985             EC_ERR("SII data corrupted! Dropping.\n");
   882         up(&master->sii_sem);
   986             return -EINVAL;
   883     }
   987         }
   884 
   988         cat_size = EC_READ_U16(cat_header + 1);
   885     // wait until master FSM has finished processing
   989         if (cat_header + cat_size + 2 > request.words + request.nwords) {
   886     wait_event(master->sii_queue,
   990             EC_ERR("SII data corrupted! Dropping.\n");
   887             request.state != EC_REQUEST_BUSY);
   991             return -EINVAL;
   888 
   992         }
   889     if (request.state == EC_REQUEST_SUCCESS) {
   993         cat_header += cat_size + 2;
   890         if (offset <= 4 && offset + nwords > 4) { // alias was written
   994         cat_type = EC_READ_U16(cat_header);
   891             slave->sii.alias = EC_READ_U16(words + 4);
   995     }
   892         }
   996 
   893         return 0;
   997     // SII data ok. schedule writing.
   894     } else {
   998     if ((ret = ec_slave_schedule_sii_writing(&request)))
   895         return -EIO;
   999         return ret; // error code
   896     }
  1000 
       
  1001     return size; // success
       
  1002 }
       
  1003 
       
  1004 /*****************************************************************************/
       
  1005 
       
  1006 /**
       
  1007  * Writes the Secondary slave address (alias) to the slave's SII.
       
  1008  * \return data size written in case of success, otherwise error code.
       
  1009  */
       
  1010 
       
  1011 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
       
  1012         const uint8_t *data, /**< alias string */
       
  1013         size_t size /**< size of data in bytes */
       
  1014         )
       
  1015 {
       
  1016     ec_sii_write_request_t request;
       
  1017     char *remainder;
       
  1018     uint16_t alias;
       
  1019     int ret;
       
  1020     uint8_t sii_data[16], crc;
       
  1021 
       
  1022     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
       
  1023         EC_ERR("Writing to SII is only allowed in idle mode!\n");
       
  1024         return -EBUSY;
       
  1025     }
       
  1026 
       
  1027     alias = simple_strtoul(data, &remainder, 0);
       
  1028     if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
       
  1029         EC_ERR("Invalid alias value! Dropping.\n");
       
  1030         return -EINVAL;
       
  1031     }
       
  1032 
       
  1033     if (!slave->sii_words || slave->sii_nwords < 8) {
       
  1034         EC_ERR("Failed to read SII contents from slave %u.\n",
       
  1035                 slave->ring_position);
       
  1036         return -EINVAL;
       
  1037     }
       
  1038 
       
  1039     // copy first 7 words of recent SII contents
       
  1040     memcpy(sii_data, (uint8_t *) slave->sii_words, 14);
       
  1041     
       
  1042     // write new alias address in word 4
       
  1043     EC_WRITE_U16(sii_data + 8, alias);
       
  1044 
       
  1045     // calculate new checksum over words 0 to 6
       
  1046     crc = ec_slave_sii_crc(sii_data, 14);
       
  1047     EC_WRITE_U16(sii_data + 14, crc);
       
  1048 
       
  1049     // init SII write request
       
  1050     INIT_LIST_HEAD(&request.list);
       
  1051     request.slave = slave;
       
  1052     request.words = (const uint16_t *) sii_data;
       
  1053     request.offset = 0x0000;
       
  1054     request.nwords = 8;
       
  1055 
       
  1056     if ((ret = ec_slave_schedule_sii_writing(&request)))
       
  1057         return ret; // error code
       
  1058 
       
  1059     slave->sii.alias = alias; // FIXME: do this in state machine
       
  1060 
       
  1061     return size; // success
       
  1062 }
   897 }
  1063 
   898 
  1064 /*****************************************************************************/
   899 /*****************************************************************************/
  1065 
   900 
  1066 /**
   901 /**
  1072                                 struct attribute *attr, /**< attribute */
   907                                 struct attribute *attr, /**< attribute */
  1073                                 char *buffer /**< memory to store data */
   908                                 char *buffer /**< memory to store data */
  1074                                 )
   909                                 )
  1075 {
   910 {
  1076     ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
   911     ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
  1077     unsigned int sii_size;
       
  1078 
   912 
  1079     if (attr == &attr_info) {
   913     if (attr == &attr_info) {
  1080         return ec_slave_info(slave, buffer);
   914         return ec_slave_info(slave, buffer);
  1081     } else if (attr == &attr_sii) {
       
  1082         if (slave->sii_words) {
       
  1083             sii_size = slave->sii_nwords * 2;
       
  1084             if (sii_size > PAGE_SIZE) {
       
  1085                 EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
       
  1086                        slave->ring_position, sii_size,
       
  1087                        (int) PAGE_SIZE);
       
  1088             }
       
  1089             else {
       
  1090                 memcpy(buffer, (uint8_t *) slave->sii_words, sii_size);
       
  1091                 return sii_size;
       
  1092             }
       
  1093         }
       
  1094     } else if (attr == &attr_alias) {
       
  1095         return sprintf(buffer, "%u\n", slave->sii.alias);
       
  1096     }
   915     }
  1097 
   916 
  1098     return 0;
   917     return 0;
  1099 }
       
  1100 
       
  1101 /*****************************************************************************/
       
  1102 
       
  1103 /**
       
  1104    Formats attribute data for SysFS write access.
       
  1105    \return number of bytes processed, or negative error code
       
  1106 */
       
  1107 
       
  1108 ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
       
  1109                                  struct attribute *attr, /**< attribute */
       
  1110                                  const char *buffer, /**< memory with data */
       
  1111                                  size_t size /**< size of data to store */
       
  1112                                  )
       
  1113 {
       
  1114     ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
       
  1115 
       
  1116     if (attr == &attr_sii) {
       
  1117         return ec_slave_write_sii(slave, buffer, size);
       
  1118     } else if (attr == &attr_alias) {
       
  1119         return ec_slave_write_alias(slave, buffer, size);
       
  1120     }
       
  1121 
       
  1122     return -EIO;
       
  1123 }
   918 }
  1124 
   919 
  1125 /*****************************************************************************/
   920 /*****************************************************************************/
  1126 
   921 
  1127 /** Get the sync manager for either Rx- or Tx-Pdos.
   922 /** Get the sync manager for either Rx- or Tx-Pdos.