| /* Copyright (c) 2000-2019 Ericsson Telecom AB AB |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Michael Josenhans |
| ******************************************************************************/ |
| // |
| // File: Isobus.ttcn |
| // Description: Encoder / Decoder for Isobus message frames |
| // |
| // Revision R1A |
| |
| module Isobus { |
| import from General_Types all |
| import from Can all |
| import from IsobusCMMessageTypes all |
| import from IsobusNMMessageTypes all |
| import from IsobusVTMessageTypes all |
| import from J1939 all |
| |
| // Note: |
| // SocketCAN Error frames are not considered here |
| // SocketCAN RTR frames are not considered here |
| // SocketCAN Basic frames are not considered here |
| |
| external function encode_CAN_frame_j1939mod(in CAN_frame_j1939mod pdu) return octetstring |
| with { extension "prototype(convert) encode(RAW)" } |
| external function decode_CAN_frame_j1939mod(in octetstring data) return CAN_frame_j1939mod |
| with { extension "prototype(convert) decode(RAW)" } |
| |
| const octetstring ISOBUS_PRIORITY_MASK := '1C000000'O; |
| const octetstring ISOBUS_RESERVED_MASK := '02000000'O; |
| const octetstring ISOBUS_DATAPAGE_MASK := '01000000'O; |
| const octetstring ISOBUS_PDUFORMAT_MASK := '00FF0000'O; |
| const octetstring ISOBUS_PDUSPECIFIC_MASK := '0000FF00'O; |
| const octetstring ISOBUS_SOURCEADDRESS_MASK := '000000FF'O; |
| |
| type J1939_Priority Priority |
| |
| type record J1939_header { // Error & RTR Frames are not considered here |
| //PGN pgn optional, |
| //BIT3 ignore, |
| Priority prio, |
| BIT1 res, |
| BIT1 dp, |
| OCT1 pf, |
| OCT1 ps, |
| SourceAddress sa |
| } with { variant "FIELDORDER(msb)" } |
| |
| |
| |
| type record J1939mod { // Error & RTR Frames are not considered here |
| //PGN pgn optional, |
| //BIT3 ignore, |
| Priority prio, |
| BIT1 res, |
| BIT1 dp, |
| OCT1 pf, |
| OCT1 ps, |
| SourceAddress sa, |
| OCT3 comp |
| } with { variant "FIELDORDER(msb)" } |
| |
| |
| type union AnyIsoBusPdu { |
| ETP_DT etp_dt, // extended TP data transfer |
| ETP_CM etp_cm, // extended TP connection management |
| VT2ECU vt2ecu, // Message Virtual Terminal (VT) to ECU |
| ECU2VT ecu2vt, // Message ECU to Virtual Terminal (VT) |
| RequestForAddressClaimed requestForAddressClaimed, |
| TP_DT tp_dt, // TP data transfer |
| TP_CM tp_cm, // TP connection management |
| NetworkMessage networkMessage, // Network Message according ISO 11873-4 |
| CannotClaimSourceAddress cannotClaimSourceAddress, |
| AddressClaimed addressClaimed, |
| CommandedAddress commandedAddress |
| // other upper layer isobus protocols like Task Comtroller are added here ... |
| } |
| with { variant "" } |
| |
| type record CAN_frame_j1939 { |
| J1939_header can_j1939, |
| AnyIsoBusPdu can_pdu |
| }with { variant "" } |
| |
| |
| type record CAN_frame_j1939mod { |
| J1939mod can_j1939, |
| AnyIsoBusPdu can_pdu |
| }with { |
| variant (can_pdu) "CROSSTAG( |
| etp_dt, can_j1939.comp = 'C70000'O; //199 |
| etp_cm, can_j1939.comp = 'C80000'O; //200 |
| vt2ecu, can_j1939.comp = 'E60000'O; //230 |
| ecu2vt, can_j1939.comp = 'E70000'O; //231 |
| requestForAddressClaimed, can_j1939.comp = 'EA0000'O; //234 |
| tp_dt, can_j1939.comp = 'EB0000'O; //235 |
| tp_cm, can_j1939.comp = 'EC0000'O; //236 |
| networkMessage, can_j1939.comp = 'ED0000'O; //237 |
| cannotClaimSourceAddress, can_j1939.comp = 'EEFFFE'O; //238 all and conjuction needed!!!!!! |
| addressClaimed, can_j1939.comp = 'EEFF00'O; //238 all and conjuction needed!!!!!! |
| commandedAddress, can_j1939.comp = 'FED800'O)" //254 all and conjuction needed!!!!!! |
| } |
| |
| function j1939frame2can(in CAN_frame_j1939 p_can_frame_j1939, in Priority p_priority, in DestinationAddress p_da, in SourceAddress p_sa) return CAN_frame { |
| var CAN_frame v_can_frame |
| v_can_frame.can_id := pdu1_j1939id2canid(p_can_frame_j1939.can_j1939, p_priority, p_da, p_sa) |
| // v_can_frame.can_pdu := encode_AnyIsoBusPdu(p_can_frame_j1939.can_pdu) |
| v_can_frame.can_pdu := substr(f_encode_CAN_frame_j1939(p_can_frame_j1939),0,3)//strip 3 byte header |
| return v_can_frame |
| } |
| |
| function pdu1_j1939id2canid(in J1939_header p_j1939, in Priority p_priority, in DestinationAddress p_da, in SourceAddress p_sa) return CAN_id{ |
| var CAN_id v_can_id |
| v_can_id := bit2oct(oct2bit(p_sa) or4b (oct2bit(p_da) << 8) or4b (oct2bit(p_j1939.pf) << 16) or4b ((p_j1939.dp) << 24) or4b |
| ((p_j1939.res) << 25) or4b (int2bit(p_priority, 32) << 26)) |
| return v_can_id |
| } |
| |
| /* |
| function j1939id2canid(in J1939 p_j1939) return CAN_id{ |
| var CAN_id v_can_id |
| v_can_id := (p_j1939.sa << 0) or4b (p_j1939.ps << 8) or4b (p_j1939.pf << 16) or4b bit2oct(p_j1939.dp << 24) or4b |
| bit2oct(p_j1939.res << 25) or4b bit2oct(p_j1939.prio << 26) |
| return v_can_id |
| } |
| */ |
| |
| function j1939id2canid(in J1939_header p_j1939) return CAN_id{ |
| var CAN_id v_can_id |
| v_can_id := int2oct( |
| oct2int(p_j1939.sa) + oct2int(p_j1939.ps)*256 + oct2int(p_j1939.pf) * 256 * 256 + |
| bit2int(p_j1939.dp) * 256 * 256 * 256 + bit2int(p_j1939.res) * 256 * 256 * 256 * 2 + |
| p_j1939.prio * 256 * 256 * 256 * 2 * 2, |
| 4 ) |
| return v_can_id |
| } |
| |
| //--------------------------------------------------------------------------------------- |
| function can2j1939frame(CAN_frame p_can_frame) return CAN_frame_j1939 { |
| //--------------------------------------------------------------------------------------- |
| var CAN_frame_j1939 v_can_frame_j1939 |
| |
| //log("can_id", p_can_frame.can_id) |
| //log("can_pdu", p_can_frame.can_pdu) |
| |
| v_can_frame_j1939:=f_decode_CAN_frame_j1939(p_can_frame.can_id& p_can_frame.can_pdu) |
| |
| //log("Higher layer octet pdustring: ", v_can_frame_j1939) |
| return v_can_frame_j1939 |
| } |
| |
| function canid2j1939(in CAN_id p_can_id) return J1939_header { |
| //--------------------------------------------------------------------------------------- |
| |
| var bitstring v_can_id_bitstring:= oct2bit(p_can_id) |
| var J1939_header v_j1939 |
| |
| v_j1939.prio :=bit2int(substr(v_can_id_bitstring, 0, 6)); //3 ,3 |
| v_j1939.res :=v_can_id_bitstring[6]; |
| v_j1939.dp :=v_can_id_bitstring[7]; |
| v_j1939.pf :=p_can_id[1];//(p_can_id and4b ISOBUS_PDUFORMAT_MASK) >> 2 // shift 16 bits = 2 octets |
| v_j1939.ps :=p_can_id[2];// (p_can_id and4b ISOBUS_PDUSPECIFIC_MASK) >> 1 // shift 8 bits = 1 octet |
| v_j1939.sa :=p_can_id[3];//(p_can_id and4b ISOBUS_SOURCEADDRESS_MASK) |
| |
| return v_j1939 |
| } |
| |
| //********************************************************************************- |
| |
| |
| |
| //--------------------------------------------------------------------------- |
| function f_insert_aux_hdr(in octetstring p_os) return octetstring |
| //--------------------------------------------------------------------------- |
| { |
| var OCT3 v_os |
| |
| |
| v_os[0]:=p_os[1];//pf |
| if(p_os[1] == 'FE'O) |
| { |
| if (p_os[2]=='D8'O) {v_os[1]:='D8'O;v_os[2]:='00'O;} |
| } |
| |
| else if(p_os[1] == 'EE'O) |
| { |
| if (p_os[2] == 'FF'O) |
| { if (p_os[3]=='FE'O) {v_os[1]:='FF'O;v_os[2]:='FE'O;} |
| else {v_os[1]:='FF'O;v_os[2]:='00'O;} |
| } |
| |
| } |
| |
| |
| else { v_os[1]:='00'O;v_os[2]:='00'O;} |
| |
| |
| //log("replace(p_os,4,0,v_os) :",replace(p_os,4,0,v_os)) |
| |
| return replace(p_os,4,0,v_os)//insert aux header |
| } |
| |
| //--------------------------------------------------------------------------- |
| function f_remove_aux_hdr(in octetstring p_os) return octetstring |
| //--------------------------------------------------------------------------- |
| { |
| //log("p_os :",p_os) |
| |
| |
| p_os[1]:=p_os[4]; //pf := aux[0]; |
| if (p_os[4] == 'EE'O) |
| { |
| if (p_os[6] == 'FE'O ) { //'EEFFFE' O |
| p_os[2]:=p_os[5]; //ps := aux[1]; |
| p_os[3]:=p_os[6]; //sa := aux[2]; |
| } |
| else { //'EEFFXX'O |
| p_os[2]:=p_os[5]; //ps := aux[1]; |
| } |
| } |
| else if (p_os[4] == 'FE'O) //'FED8XX'O |
| { |
| p_os[2]:=p_os[5]; //ps := aux[1]; |
| } |
| |
| |
| //log("p_os :",p_os) |
| |
| //log("replace(p_os,4,3,''O) :",replace(p_os,4,3,''O)) |
| return replace(p_os,4,3,''O); //remove aux header |
| } |
| |
| //--------------------------------------------------------------------------- |
| function f_map_mod2frame(in CAN_frame_j1939mod p_frame) return CAN_frame_j1939 |
| //--------------------------------------------------------------------------- |
| { |
| var CAN_frame_j1939 v_CAN_frame_j1939 |
| |
| v_CAN_frame_j1939.can_pdu:=p_frame.can_pdu; |
| v_CAN_frame_j1939.can_j1939.prio:=p_frame.can_j1939.prio; |
| v_CAN_frame_j1939.can_j1939.res:=p_frame.can_j1939.res; |
| v_CAN_frame_j1939.can_j1939.dp:=p_frame.can_j1939.dp; |
| v_CAN_frame_j1939.can_j1939.pf:=p_frame.can_j1939.pf; |
| v_CAN_frame_j1939.can_j1939.ps:=p_frame.can_j1939.ps; |
| v_CAN_frame_j1939.can_j1939.sa:=p_frame.can_j1939.sa; |
| |
| |
| //log("v_CAN_frame_j1939 :",v_CAN_frame_j1939) |
| return v_CAN_frame_j1939 |
| |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| function f_map_frame2mod(in CAN_frame_j1939 p_frame) return CAN_frame_j1939mod |
| //--------------------------------------------------------------------------- |
| { |
| var CAN_frame_j1939mod v_CAN_frame_j1939mod |
| |
| |
| v_CAN_frame_j1939mod.can_pdu:=p_frame.can_pdu; |
| v_CAN_frame_j1939mod.can_j1939.prio:=p_frame.can_j1939.prio; |
| v_CAN_frame_j1939mod.can_j1939.res:=p_frame.can_j1939.res; |
| v_CAN_frame_j1939mod.can_j1939.dp:=p_frame.can_j1939.dp; |
| v_CAN_frame_j1939mod.can_j1939.pf:=p_frame.can_j1939.pf; |
| v_CAN_frame_j1939mod.can_j1939.ps:=p_frame.can_j1939.ps; |
| v_CAN_frame_j1939mod.can_j1939.sa:=p_frame.can_j1939.sa; |
| if (p_frame.can_j1939.pf == 'EE'O) |
| { |
| if (p_frame.can_j1939.ps == 'D8'O) { |
| v_CAN_frame_j1939mod.can_j1939.comp := p_frame.can_j1939.pf&p_frame.can_j1939.ps&'00'O; |
| } else if (p_frame.can_j1939.ps == 'FF'O) { |
| if (p_frame.can_j1939.sa == 'FE'O) { |
| v_CAN_frame_j1939mod.can_j1939.comp := p_frame.can_j1939.pf&p_frame.can_j1939.ps&p_frame.can_j1939.sa |
| } else {//?? |
| v_CAN_frame_j1939mod.can_j1939.comp:=p_frame.can_j1939.pf&'0000'O; |
| } |
| } else {//?? |
| v_CAN_frame_j1939mod.can_j1939.comp:=p_frame.can_j1939.pf&'0000'O; |
| } |
| } else { |
| v_CAN_frame_j1939mod.can_j1939.comp := p_frame.can_j1939.pf&'0000'O; |
| } |
| //log("v_CAN_frame_j1939mod :",v_CAN_frame_j1939mod) |
| return v_CAN_frame_j1939mod; |
| } |
| |
| |
| |
| //--------------------------------------------------------------------------- |
| function f_encode_CAN_frame_j1939(in CAN_frame_j1939 pdu) return octetstring |
| //--------------------------------------------------------------------------- |
| { |
| |
| return f_remove_aux_hdr(encode_CAN_frame_j1939mod(f_map_frame2mod(pdu))) |
| |
| |
| } |
| //--------------------------------------------------------------------------- |
| function f_decode_CAN_frame_j1939(in octetstring data) return CAN_frame_j1939 |
| //--------------------------------------------------------------------------- |
| { |
| log("f_insert_aux_hdr(data)", f_insert_aux_hdr(data)); |
| return f_map_mod2frame(decode_CAN_frame_j1939mod(f_insert_aux_hdr(data))) |
| |
| |
| } |
| |
| |
| } with { encode "RAW" } |
| |