36 CANopen-over-EtherCAT Sdo entry functions. |
36 CANopen-over-EtherCAT Sdo entry functions. |
37 */ |
37 */ |
38 |
38 |
39 /*****************************************************************************/ |
39 /*****************************************************************************/ |
40 |
40 |
41 #include <linux/module.h> |
41 #include <linux/slab.h> |
42 |
|
43 #include "sdo.h" |
|
44 #include "sdo_request.h" |
|
45 #include "master.h" |
|
46 |
42 |
47 #include "sdo_entry.h" |
43 #include "sdo_entry.h" |
48 |
44 |
49 /*****************************************************************************/ |
45 /*****************************************************************************/ |
50 |
46 |
51 ssize_t ec_show_sdo_entry_attribute(struct kobject *, struct attribute *, |
47 /** Constructor. |
52 char *); |
|
53 void ec_sdo_entry_clear(struct kobject *); |
|
54 |
|
55 /*****************************************************************************/ |
|
56 |
|
57 /** \cond */ |
|
58 |
|
59 EC_SYSFS_READ_ATTR(info); |
|
60 EC_SYSFS_READ_ATTR(value); |
|
61 |
|
62 static struct attribute *sdo_entry_def_attrs[] = { |
|
63 &attr_info, |
|
64 &attr_value, |
|
65 NULL, |
|
66 }; |
|
67 |
|
68 static struct sysfs_ops sdo_entry_sysfs_ops = { |
|
69 .show = &ec_show_sdo_entry_attribute, |
|
70 .store = NULL |
|
71 }; |
|
72 |
|
73 static struct kobj_type ktype_ec_sdo_entry = { |
|
74 .release = ec_sdo_entry_clear, |
|
75 .sysfs_ops = &sdo_entry_sysfs_ops, |
|
76 .default_attrs = sdo_entry_def_attrs |
|
77 }; |
|
78 |
|
79 /** \endcond */ |
|
80 |
|
81 /*****************************************************************************/ |
|
82 |
|
83 /** Sdo entry constructor. |
|
84 * |
|
85 * \todo Turn parameters. |
|
86 */ |
48 */ |
87 int ec_sdo_entry_init( |
49 void ec_sdo_entry_init( |
88 ec_sdo_entry_t *entry, /**< Sdo entry. */ |
50 ec_sdo_entry_t *entry, /**< Sdo entry. */ |
89 uint8_t subindex, /**< Subindex. */ |
51 ec_sdo_t *sdo, /**< Parent Sdo. */ |
90 ec_sdo_t *sdo /**< Parent Sdo. */ |
52 uint8_t subindex /**< Subindex. */ |
91 ) |
53 ) |
92 { |
54 { |
93 entry->sdo = sdo; |
55 entry->sdo = sdo; |
94 entry->subindex = subindex; |
56 entry->subindex = subindex; |
95 entry->data_type = 0x0000; |
57 entry->data_type = 0x0000; |
96 entry->bit_length = 0; |
58 entry->bit_length = 0; |
97 entry->description = NULL; |
59 entry->description = NULL; |
98 |
|
99 // Init kobject and add it to the hierarchy |
|
100 memset(&entry->kobj, 0x00, sizeof(struct kobject)); |
|
101 kobject_init(&entry->kobj); |
|
102 entry->kobj.ktype = &ktype_ec_sdo_entry; |
|
103 entry->kobj.parent = &sdo->kobj; |
|
104 if (kobject_set_name(&entry->kobj, "%02X", entry->subindex)) { |
|
105 EC_ERR("Failed to set kobj name.\n"); |
|
106 kobject_put(&entry->kobj); |
|
107 return -1; |
|
108 } |
|
109 if (kobject_add(&entry->kobj)) { |
|
110 EC_ERR("Failed to add entry kobject.\n"); |
|
111 kobject_put(&entry->kobj); |
|
112 return -1; |
|
113 } |
|
114 |
|
115 return 0; |
|
116 } |
60 } |
117 |
61 |
118 /*****************************************************************************/ |
62 /*****************************************************************************/ |
119 |
63 |
120 /** Sdo entry destructor. |
64 /** Destructor. |
121 * |
|
122 * Clears and frees an Sdo entry object. |
|
123 */ |
65 */ |
124 void ec_sdo_entry_destroy( |
66 void ec_sdo_entry_clear( |
125 ec_sdo_entry_t *entry /**< Sdo entry. */ |
67 ec_sdo_entry_t *entry /**< Sdo entry. */ |
126 ) |
68 ) |
127 { |
69 { |
128 // destroy self |
70 |
129 kobject_del(&entry->kobj); |
71 if (entry->description) |
130 kobject_put(&entry->kobj); |
72 kfree(entry->description); |
131 } |
73 } |
132 |
74 |
133 /*****************************************************************************/ |
75 /*****************************************************************************/ |
134 |
|
135 /** Clear and free the Sdo entry. |
|
136 * |
|
137 * This method is called by the kobject, |
|
138 * once there are no more references to it. |
|
139 */ |
|
140 void ec_sdo_entry_clear( |
|
141 struct kobject *kobj /**< Sdo entry's kobject. */ |
|
142 ) |
|
143 { |
|
144 ec_sdo_entry_t *entry = container_of(kobj, ec_sdo_entry_t, kobj); |
|
145 |
|
146 if (entry->description) kfree(entry->description); |
|
147 |
|
148 kfree(entry); |
|
149 } |
|
150 |
|
151 /*****************************************************************************/ |
|
152 |
|
153 /** Print Sdo entry information to a buffer. |
|
154 * |
|
155 * \return Number of bytes written. |
|
156 */ |
|
157 ssize_t ec_sdo_entry_info( |
|
158 ec_sdo_entry_t *entry, /**< Sdo entry. */ |
|
159 char *buffer /**< Target buffer. */ |
|
160 ) |
|
161 { |
|
162 off_t off = 0; |
|
163 |
|
164 off += sprintf(buffer + off, "Subindex: 0x%02X\n", entry->subindex); |
|
165 off += sprintf(buffer + off, "Description: %s\n", |
|
166 entry->description ? entry->description : ""); |
|
167 off += sprintf(buffer + off, "Data type: 0x%04X\n", entry->data_type); |
|
168 off += sprintf(buffer + off, "Bit length: %u\n", entry->bit_length); |
|
169 |
|
170 return off; |
|
171 } |
|
172 |
|
173 /*****************************************************************************/ |
|
174 |
|
175 /** Format entry data based on the CANopen data type and print it to a buffer. |
|
176 * |
|
177 * \return number of bytes written. |
|
178 */ |
|
179 ssize_t ec_sdo_entry_format_data( |
|
180 ec_sdo_entry_t *entry, /**< Sdo entry. */ |
|
181 ec_sdo_request_t *request, /**< Sdo request. */ |
|
182 char *buffer /**< Target buffer. */ |
|
183 ) |
|
184 { |
|
185 off_t off = 0; |
|
186 unsigned int i; |
|
187 |
|
188 if (request->data_size * 8 != entry->bit_length) { |
|
189 EC_ERR("Dictionary size of Sdo entry 0x%04X:%02X (%u bit) does not " |
|
190 "match size of uploaded data (%u byte)!\n", entry->sdo->index, |
|
191 entry->subindex, entry->bit_length, request->data_size); |
|
192 EC_DBG("Uploaded data:\n"); |
|
193 ec_print_data(request->data, request->data_size); |
|
194 return -EIO; |
|
195 } |
|
196 |
|
197 if (entry->data_type == 0x0002) { // int8 |
|
198 int8_t value; |
|
199 if (entry->bit_length != 8) |
|
200 goto not_fit; |
|
201 value = EC_READ_S8(request->data); |
|
202 off += sprintf(buffer + off, "%i (0x%02X)\n", value, value); |
|
203 } |
|
204 else if (entry->data_type == 0x0003) { // int16 |
|
205 int16_t value; |
|
206 if (entry->bit_length != 16) |
|
207 goto not_fit; |
|
208 value = EC_READ_S16(request->data); |
|
209 off += sprintf(buffer + off, "%i (0x%04X)\n", value, value); |
|
210 } |
|
211 else if (entry->data_type == 0x0004) { // int32 |
|
212 int32_t value; |
|
213 if (entry->bit_length != 32) |
|
214 goto not_fit; |
|
215 value = EC_READ_S16(request->data); |
|
216 off += sprintf(buffer + off, "%i (0x%08X)\n", value, value); |
|
217 } |
|
218 else if (entry->data_type == 0x0005) { // uint8 |
|
219 uint8_t value; |
|
220 if (entry->bit_length != 8) |
|
221 goto not_fit; |
|
222 value = EC_READ_U8(request->data); |
|
223 off += sprintf(buffer + off, "%u (0x%02X)\n", value, value); |
|
224 } |
|
225 else if (entry->data_type == 0x0006) { // uint16 |
|
226 uint16_t value; |
|
227 if (entry->bit_length != 16) |
|
228 goto not_fit; |
|
229 value = EC_READ_U16(request->data); |
|
230 off += sprintf(buffer + off, "%u (0x%04X)\n", value, value); |
|
231 } |
|
232 else if (entry->data_type == 0x0007) { // uint32 |
|
233 uint32_t value; |
|
234 if (entry->bit_length != 32) |
|
235 goto not_fit; |
|
236 value = EC_READ_U32(request->data); |
|
237 off += sprintf(buffer + off, "%u (0x%08X)\n", value, value); |
|
238 } |
|
239 else if (entry->data_type == 0x0009) { // string |
|
240 off += sprintf(buffer + off, "%s\n", request->data); |
|
241 } |
|
242 else { |
|
243 off += sprintf(buffer + off, "Unknown data type %04X. Data:\n", |
|
244 entry->data_type); |
|
245 goto raw_data; |
|
246 } |
|
247 return off; |
|
248 |
|
249 not_fit: |
|
250 off += sprintf(buffer + off, |
|
251 "Invalid bit length %u for data type 0x%04X. Data:\n", |
|
252 entry->bit_length, entry->data_type); |
|
253 raw_data: |
|
254 for (i = 0; i < request->data_size; i++) |
|
255 off += sprintf(buffer + off, "%02X (%c)\n", |
|
256 request->data[i], request->data[i]); |
|
257 return off; |
|
258 } |
|
259 |
|
260 /*****************************************************************************/ |
|
261 |
|
262 /** Start blocking Sdo entry reading. |
|
263 * |
|
264 * This function blocks, until reading is finished, and is interruptible as |
|
265 * long as the master state machine has not begun with reading. |
|
266 * |
|
267 * \return number of bytes written to buffer, or error code. |
|
268 */ |
|
269 ssize_t ec_sdo_entry_read_value( |
|
270 ec_sdo_entry_t *entry, /**< Sdo entry. */ |
|
271 char *buffer /**< Target buffer. */ |
|
272 ) |
|
273 { |
|
274 ec_master_t *master = entry->sdo->slave->master; |
|
275 off_t off = 0; |
|
276 ec_master_sdo_request_t request; |
|
277 |
|
278 request.slave = entry->sdo->slave; |
|
279 ec_sdo_request_init(&request.req); |
|
280 ec_sdo_request_address(&request.req, entry->sdo->index, entry->subindex); |
|
281 ecrt_sdo_request_read(&request.req); |
|
282 |
|
283 // schedule request. |
|
284 down(&master->sdo_sem); |
|
285 list_add_tail(&request.list, &master->slave_sdo_requests); |
|
286 up(&master->sdo_sem); |
|
287 |
|
288 // wait for processing through FSM |
|
289 if (wait_event_interruptible(master->sdo_queue, |
|
290 request.req.state != EC_REQUEST_QUEUED)) { |
|
291 // interrupted by signal |
|
292 down(&master->sdo_sem); |
|
293 if (request.req.state == EC_REQUEST_QUEUED) { |
|
294 list_del(&request.req.list); |
|
295 up(&master->sdo_sem); |
|
296 return -EINTR; |
|
297 } |
|
298 // request already processing: interrupt not possible. |
|
299 up(&master->sdo_sem); |
|
300 } |
|
301 |
|
302 // wait until master FSM has finished processing |
|
303 wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY); |
|
304 |
|
305 if (request.req.state != EC_REQUEST_SUCCESS) |
|
306 return -EIO; |
|
307 |
|
308 off += ec_sdo_entry_format_data(entry, &request.req, buffer); |
|
309 |
|
310 ec_sdo_request_clear(&request.req); |
|
311 return off; |
|
312 } |
|
313 |
|
314 /*****************************************************************************/ |
|
315 |
|
316 /** Show the Sysfs attribute of an Sdo entry. |
|
317 * |
|
318 * /return Number of bytes written to buffer. |
|
319 */ |
|
320 ssize_t ec_show_sdo_entry_attribute( |
|
321 struct kobject *kobj, /**< kobject. */ |
|
322 struct attribute *attr, /**< Sysfs attribute. */ |
|
323 char *buffer /**< Target buffer. */ |
|
324 ) |
|
325 { |
|
326 ec_sdo_entry_t *entry = container_of(kobj, ec_sdo_entry_t, kobj); |
|
327 |
|
328 if (attr == &attr_info) { |
|
329 return ec_sdo_entry_info(entry, buffer); |
|
330 } |
|
331 else if (attr == &attr_value) { |
|
332 return ec_sdo_entry_read_value(entry, buffer); |
|
333 } |
|
334 |
|
335 return 0; |
|
336 } |
|
337 |
|
338 /*****************************************************************************/ |
|