2 This file is part of CanFestival, a library implementing CanOpen Stack.
4 Author: CANopen Canada (canfestival@canopencanada.ca)
6 See COPYING file for copyrights details.
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <objdictdef.h>
30 #include "can_driver.h"
35 #define led_set_state(a,b)
45 1. since in the LSS protocol all LSS Slave use the same COB, only 1 Slave
46 must be allowed to communicate with the Master
48 2. the Master always take the iniative. the Slave is only allowed to transmit
49 within a confirmed service
51 3. requesting message (from the Master) using COB-ID 2021 and response messages
52 (from the Slave) using COB-ID 2020
56 0 = this slave is not talking to the master
57 1 = this slave is talking to the master (this slave has been selected via )
63 int lss_table_selector, lss_table_index;
66 /* slave storing the information sent by the master */
69 how this buffer is used
72 [0..3] used to store the LSS Address
73 [4..9] use by LSS Identify Remort Slave
76 [0..3] hold the answer from the slave regarding its ID
80 void lss_copy(UNS8 *data, UNS32 value)
81 /* transfert 32 bits value into uns8 data vector */
83 data[0] = value & 0xff;
84 data[1] = (value>>8) & 0xff;
85 data[2] = (value>>16) & 0xff;
86 data[3] = (value>>24) & 0xff;
90 UNS32 lss_get_value(UNS8 *data)
91 /* build a 'UNS32' value from a 'unsigned char' vector */
93 return data[0] + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
97 void lss_init_msg(Message *msg)
113 void lss_SwitchModeGlobal(CO_Data *d, UNS32 mode)
115 this service is used to switch all LSS slaves in the network between operation
116 mode and configuration mode.
123 sending a COB-ID 2021
124 [0] = 4 (for switch mode global)
125 [1] = 0 for operation mode, = 1 for configuration mode
129 if (!(d->iam_a_slave))
131 msg.cob_id.w = 0x07E5 /* 2021 */;
135 msg.data[1] = (UNS8)mode;
142 /* set mode global */
148 void lss_SwitchModeSelective_master(CO_Data *d, UNS32 *LSSaddr)
150 LSS address : <vendor-id> <product-code> <revision-number> <serial-number>
151 vendor-id : provided by CiA
152 identical to the CANopen identity object
154 select the slave corresponding to this ADDRESS
160 if (d->iam_a_slave) /* not the master */
163 msg.cob_id.w = 0x07E5 /* 2021 */;
167 lss_copy(msg.data+1, LSSaddr[0]);
172 lss_copy(msg.data+1, LSSaddr[1]);
177 lss_copy(msg.data+1, LSSaddr[2]);
182 lss_copy(msg.data+1, LSSaddr[3]);
188 UNS32 lss_validate_address(CO_Data* d)
191 extern s_identity obj1018;
193 /* maybe we should go throught getODentry but those
194 data are 1) RO and 2) the proper ID of this device */
196 UNS32 r, vendor_id, product_code, revision_number, serial_number;
197 UNS8 sz = sizeof(UNS32), dt = int32;
199 r = getODentry(d, 0x1018, 1, (void *)&vendor_id, &sz, &dt, 0);
200 r = getODentry(d, 0x1018, 2, (void *)&product_code, &sz, &dt, 0);
201 r = getODentry(d, 0x1018, 3, (void *)&revision_number, &sz, &dt, 0);
202 r = getODentry(d, 0x1018, 4, (void *)&serial_number, &sz, &dt, 0);
207 lss_buffer[0] == vendor-id
208 lss_buffer[1] == product code
209 lss_buffer[2] == revision
210 lss_buffer[3] == serial
216 if (lss_buffer[0] == vendor_id &&
217 lss_buffer[1] == product_code &&
218 lss_buffer[2] == revision_number &&
219 lss_buffer[3] == serial_number)
228 void lss_SwitchModeSelective_slave(CO_Data *d)
230 SwitchModeSelective for the SLAVE
231 received the frames from the master and start building
239 the master broadcast the address of a particular slave
240 for 64,65 and 66 store the partial address
241 when 67 arrive process the call and asknowledge if necessary
244 if (lss_validate_address(d))
246 /* slave should transmit cob_id 2020 */
247 msg.cob_id.w = 0x07E4 /* 2020 */;
251 msg.data[1] = (UNS8)current_mode;
257 /* reset the address */
265 void lss_ConfigureNode_ID(CO_Data *d, UNS32 node_id)
267 through this service the LSS Master configures the NMT-address
268 parameter of a LSS slave.
274 if (!(d->iam_a_slave))
276 msg.cob_id.w = 0x07E5 /* 2021 */;
280 msg.data[1] = (UNS8)node_id;
288 receiving NODE ID from the master
294 1 = node id out of range
296 255 = implementation specific error occured
297 spec error = mode detailed error
299 msg.cob_id.w = 0x07E4 /* 2020 */;
303 /* msg.data[1] = error code */
304 /* msg.data[2] = spec error */
312 void lss_ConfigureBitTimingParameters(CO_Data *d,
313 UNS32 table_selector,
316 this service allows all LSS slaves in configuration mode.
317 must be followed by an Activate Bit Timing Parameters
323 if (!(d->iam_a_slave))
325 msg.cob_id.w = 0x07E5 /* 2021 */;
329 msg.data[1] = (UNS8)table_selector;
330 msg.data[2] = (UNS8)table_index;
339 /* validate if this baudrate is possible */
340 if (table_selector == 0 && baudrate_valid(table_index) == 1)
342 lss_table_selector = table_selector;
343 lss_table_index = table_index;
346 error_code = 1; /* bit timing not supported */
348 msg.cob_id.w = 0x07E4 /* 2020 */;
352 msg.data[1] = error_code;
359 led_set_state(d, LED_AUTOBITRATE);
363 void lss_ActivateBitTimingParameters_master(CO_Data *d, unsigned short switch_delay)
367 switch_delay has to be longer than the longest timeof any node
368 in the network to avoid that a node already switches while another
369 stills transmist the old bit timing parameters
378 msg.cob_id.w = 0x07E5 /* 2021 */;
382 msg.data[1] = (UNS8)(switch_delay & 0xff);
383 msg.data[2] = (UNS8)((switch_delay >> 8) & 0xff);
386 led_set_state(LED_AUTOBITRATE);
393 void lss_ActivateBitTimingParameters_slave(UNS8 byte_low, UNS8 byte_high)
395 /* rebuild the delay value (short) from the 2 (UNS8) data */
396 unsigned short switch_delay = byte_low + (((UNS16)byte_high)<<8);
398 /* set the baudrate to the value proposed by the master */
399 if (lss_table_selector == 0)
400 baudrate_set(lss_table_index);
402 /* wait for switch_delay ms before continuing */
406 void lss_StoreConfiguredParameters(CO_Data *d)
408 store configured parameters into non-volatile storage
414 if (!(d->iam_a_slave))
416 msg.cob_id.w = 0x07E5 /* 2021 */;
426 msg.cob_id.w = 0x07E4 /* 2020 */;
429 /* msg.data[1] = error code; */
430 /* msg.data[2] = spec err */
438 void lss_InquireLSSAddress_master(CO_Data *d, int flag)
440 this service allows to determine the LSS-address parameters of a LSS-slave in
443 request 1 single item of the LSS address
444 0 = request vendor-id
445 1 = request product-id
453 if (!(d->iam_a_slave))
455 msg.cob_id.w = 0x07E5 /* 2021 */;
458 msg.data[0] = 90 + flag;
466 int lss_InquireLSSAddress_slave(CO_Data *d, int cs)
471 if (!(d->iam_a_slave)) /* not a slave */
479 value = 0; /* = vendor id */
482 value = 0; /* = product code */
485 value = 0; /* = revision */
488 value = 0; /* = serial */
494 msg.cob_id.w = 0x07E4 /* 2020 */;
498 lss_copy(msg.data+1, value);
510 void lss_IdentifyRemoteSlaves(CO_Data *d,
518 throught this service, the LSS Master requests all LSS slave whose LSS address
519 meets the LSSaddr_sel to idenfity themselves through LSS Identify Slave
525 if (!(d->iam_a_slave))
528 request answers from all slaves corresponding
529 to the revision and serial range of values
532 msg.cob_id.w = 0x07E5 /* 2021 */;
536 lss_copy(msg.data+1, vendor_id);
541 lss_copy(msg.data+1, product_code);
545 msg.data[0] = 72; /* revision number low */
546 lss_copy(msg.data+1, rev_low);
550 msg.data[0] = 73; /* revision number high */
551 lss_copy(msg.data+1, rev_high);
555 msg.data[0] = 74; /* serial number low */
556 lss_copy(msg.data+1, serial_low);
560 msg.data[0] = 75; /* serial number high */
561 lss_copy(msg.data+1, serial_high);
568 int lss_validate_range_addr(CO_Data *d)
573 lss_buffer[4] == vendor_id
574 lss_buffer[5] == product code
575 lss_buffer[6] <= revision <= lss_buffer[7]
576 lss_buffer[8] <= serial <= lss_buffer[9]
582 UNS32 r, vendor_id, product_code, revision_number, serial_number;
583 UNS8 sz = sizeof(UNS32), dt = int32;
585 r = getODentry(d, 0x1018, 1, (void *)&vendor_id, &sz, &dt, 0);
586 r = getODentry(d, 0x1018, 2, (void *)&product_code, &sz, &dt, 0);
587 r = getODentry(d, 0x1018, 3, (void *)&revision_number, &sz, &dt, 0);
588 r = getODentry(d, 0x1018, 4, (void *)&serial_number, &sz, &dt, 0);
590 if (lss_buffer[4] == vendor_id &&
591 lss_buffer[5] == product_code &&
592 lss_buffer[6] <= revision_number &&
593 revision_number <= lss_buffer[7] &&
594 lss_buffer[8] <= serial_number &&
595 serial_number <= lss_buffer[9])
604 void lss_IdentifySlave(CO_Data *d)
606 through this service, an LSS slave indicates that it is a slave
607 with LSS address within the LSSaddr_sel
613 if (lss_validate_range_addr(d))
615 msg.cob_id.w = 0x07E4 /* 2020 */;
634 int lss_process_msg(CO_Data *d, Message *msg)
636 /* process the incoming message */
637 if (msg->cob_id.w == 0x07E4 /* 2020 */)
639 // should be the master
640 // a slave just answered
643 /* slave acknowledging the SwitchModeSelective call */
645 /* msg->data[1] contains the 'mode global' value from the slave*/
648 /* a slave had acknowledged the call from LSS Identify Remote Slave */
652 /* the slave acknowledged and sent the requested data */
654 lss_buffer[0] = lss_get_value(msg->data+1);
658 lss_buffer[1] = lss_get_value(msg->data+1);
662 lss_buffer[2] = lss_get_value(msg->data+1);
666 lss_buffer[3] = lss_get_value(msg->data+1);
672 else if (msg->cob_id.w == 0x07E5 /* 2021 */)
675 // the master sent a request
679 lss_SwitchModeGlobal(d, msg->data[1]);
683 lss_ConfigureNode_ID(d, msg->data[1]);
687 lss_ConfigureBitTimingParameters(d, msg->data[1], msg->data[2]);
690 lss_ActivateBitTimingParameters_slave(msg->data[1], msg->data[2]);
693 /* Switch Mode Selective */
695 lss_buffer[0] = lss_get_value(msg->data+1);
698 lss_buffer[1] = lss_get_value(msg->data+1);
701 lss_buffer[2] = lss_get_value(msg->data+1);
704 lss_buffer[3] = lss_get_value(msg->data+1);
705 lss_SwitchModeSelective_slave(d);
708 /* Identify Remote Slave */
710 lss_buffer[4] = lss_get_value(msg->data+1);
713 lss_buffer[5] = lss_get_value(msg->data+1);
716 lss_buffer[6] = lss_get_value(msg->data+1);
719 lss_buffer[7] = lss_get_value(msg->data+1);
722 lss_buffer[8] = lss_get_value(msg->data+1);
725 lss_buffer[9] = lss_get_value(msg->data+1);
726 lss_IdentifySlave(d);
729 /* Inquire Identify of Slave */
734 lss_InquireLSSAddress_slave(d, msg->data[0]);