All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tuwien.auto.calimero.cemi.CEMIFactory Maven / Gradle / Ivy

There is a newer version: 2.6-rc1
Show newest version
/*
    Calimero 2 - A library for KNX network access
    Copyright (c) 2006, 2011 B. Malinowsky

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Linking this library statically or dynamically with other modules is
    making a combined work based on this library. Thus, the terms and
    conditions of the GNU General Public License cover the whole
    combination.

    As a special exception, the copyright holders of this library give you
    permission to link this library with independent modules to produce an
    executable, regardless of the license terms of these independent
    modules, and to copy and distribute the resulting executable under terms
    of your choice, provided that you also meet, for each linked independent
    module, the terms and conditions of the license of that module. An
    independent module is a module which is not derived from or based on
    this library. If you modify this library, you may extend this exception
    to your version of the library, but you are not obligated to do so. If
    you do not wish to do so, delete this exception statement from your
    version.
*/

package tuwien.auto.calimero.cemi;

import java.util.Iterator;
import java.util.List;

import tuwien.auto.calimero.DataUnitBuilder;
import tuwien.auto.calimero.GroupAddress;
import tuwien.auto.calimero.IndividualAddress;
import tuwien.auto.calimero.KNXAddress;
import tuwien.auto.calimero.Priority;
import tuwien.auto.calimero.exception.KNXFormatException;

/**
 * Factory helper for creating and copying cEMI messages.
 * 

* * @author B. Malinowsky */ public final class CEMIFactory { private CEMIFactory() {} /** * Creates a new cEMI message out of the given data byte stream. *

* * @param data byte stream containing a cEMI message frame structure * @param offset start offset of cEMI message in data * @param length length in bytes of the whole cEMI message in data * @return the new created cEMI message * @throws KNXFormatException if no (valid) cEMI structure was found or unsupported * cEMI message code */ public static CEMI create(final byte[] data, final int offset, final int length) throws KNXFormatException { if (length < 1) throw new KNXFormatException("buffer too short for cEMI frame", length); final int mc = data[offset] & 0xff; switch (mc) { case CEMILData.MC_LDATA_REQ: case CEMILData.MC_LDATA_CON: case CEMILData.MC_LDATA_IND: if (length < 26) { try { return new CEMILData(data, offset); } catch (final KNXFormatException e) { // fall-through and try if the extended cEMI works } } return new CEMILDataEx(data, offset); case CEMIDevMgmt.MC_PROPREAD_REQ: case CEMIDevMgmt.MC_PROPREAD_CON: case CEMIDevMgmt.MC_PROPWRITE_REQ: case CEMIDevMgmt.MC_PROPWRITE_CON: case CEMIDevMgmt.MC_PROPINFO_IND: case CEMIDevMgmt.MC_RESET_REQ: case CEMIDevMgmt.MC_RESET_IND: return new CEMIDevMgmt(data, offset, length); case CEMIBusMon.MC_BUSMON_IND: return new CEMIBusMon(data, offset, length); default: throw new KNXFormatException("cEMI msg code not supported", mc); } } /** * Creates a new cEMI message with information provided by original, * and adjusts it to match the supplied msgCode and data. *

* The message code has to correspond to the type of cEMI frame supplied with * original. The byte length of data has to fit the cEMI frame type * supplied with original.
* The data argument varies according to the supplied message code. For * L-Data frames, this is the tpdu, for busmonitor frames, this is the raw frame, for * device management frames, this is the data part or error information. * * @param msgCode the message code for the new cEMI frame * @param data the data for the frame * @param original the original frame providing all necessary information for the new * frame * @return the new cEMI frame adjusted with message code and data * @throws KNXFormatException if cEMI message code is unsupported or frame creation * failed */ public static CEMI create(final int msgCode, final byte[] data, final CEMI original) throws KNXFormatException { switch (msgCode) { case CEMILData.MC_LDATA_REQ: case CEMILData.MC_LDATA_CON: case CEMILData.MC_LDATA_IND: return create(msgCode, null, null, data, (CEMILData) original, false, ((CEMILData) original).isRepetition()); case CEMIDevMgmt.MC_PROPREAD_REQ: case CEMIDevMgmt.MC_PROPREAD_CON: case CEMIDevMgmt.MC_PROPWRITE_REQ: case CEMIDevMgmt.MC_PROPWRITE_CON: case CEMIDevMgmt.MC_PROPINFO_IND: case CEMIDevMgmt.MC_RESET_REQ: case CEMIDevMgmt.MC_RESET_IND: { final CEMIDevMgmt f = (CEMIDevMgmt) original; return new CEMIDevMgmt(msgCode, f.getObjectType(), f.getObjectInstance(), f .getPID(), f.getStartIndex(), f.getElementCount(), data); } case CEMIBusMon.MC_BUSMON_IND: final CEMIBusMon f = (CEMIBusMon) original; return CEMIBusMon.newWithStatus(f.getStatus(), f.getTimestamp(), f.getTimestampType() == CEMIBusMon.TYPEID_TIMESTAMP_EXT, data); default: throw new KNXFormatException("not supported cEMI msg code", msgCode); } } /** * Creates a new cEMI L-Data message with information provided by * original, and adjusts source and destination address to match the * supplied addresses. *

* * @param src the new KNX source address for the message, use null to * use original address * @param dst the new KNX destination address for the message, use null * to use original address * @param original the original frame providing all missing information for the * adjusted message * @param extended true to always created an extended frame, * false to create type according to original * @return the new cEMI L-Data message adjusted with KNX addresses */ public static CEMILData create(final IndividualAddress src, final KNXAddress dst, final CEMILData original, final boolean extended) { return (CEMILData) create(0, src, dst, null, original, extended, original.isRepetition()); } /** * Creates a new cEMI L-Data message with information provided by * original, and adjusts source and destination address to match the * supplied addresses, and sets the repeat/is repeated frame indication. *

* * @param src the new KNX source address for the message, use null to * use original address * @param dst the new KNX destination address for the message, use null * to use original address * @param original the original frame providing all missing information for the * adjusted message * @param extended true to always created an extended frame, * false to create type according to original * @param repeat @see {@link CEMILData#isRepetition()} * @return the new cEMI L-Data message adjusted with KNX addresses */ public static CEMILData create(final IndividualAddress src, final KNXAddress dst, final CEMILData original, final boolean extended, final boolean repeat) { return (CEMILData) create(0, src, dst, null, original, extended, repeat); } /** * Creates a new cEMI message out of the supplied EMI frame. *

* * @param frame EMI frame * @return the new cEMI message * @throws KNXFormatException if no (valid) EMI structure was found or unsupported EMI * message code */ public static CEMI createFromEMI(final byte[] frame) throws KNXFormatException { // check for minimum frame length (i.e., a busmonitor frame) if (frame.length < 4) throw new KNXFormatException("EMI frame too short"); final int mc = frame[0] & 0xff; if (mc == CEMIBusMon.MC_BUSMON_IND) { return CEMIBusMon.newWithStatus(frame[1] & 0xff, (frame[2] & 0xff) << 8 | frame[3] & 0xff, false, DataUnitBuilder.copyOfRange(frame, 4, frame.length)); } final Priority p = Priority.get(frame[1] >> 2 & 0x3); final boolean ack = (frame[1] & 0x02) != 0; final boolean c = (frame[1] & 0x01) != 0; final int dst = (frame[4] & 0xff) << 8 | frame[5] & 0xff; final KNXAddress a = (frame[6] & 0x80) != 0 ? (KNXAddress) new GroupAddress(dst) : new IndividualAddress(dst); final int hops = frame[6] >> 4 & 0x07; final int len = (frame[6] & 0x0f) + 1; final byte[] tpdu = DataUnitBuilder.copyOfRange(frame, 7, len + 7); // no long frames in EMI2 return c ? new CEMILData(mc, new IndividualAddress(0), a, tpdu, p, c) : new CEMILData(mc, new IndividualAddress(0), a, tpdu, p, true, true, ack, hops); } /** * Does a lazy copy of the supplied cEMI frame. *

* Only for cEMI frames which are not immutable a copy is created, for all * other frames original is returned. * * @param original the frame to copy * @return the original frame if immutable, a copy of it otherwise */ public static CEMI copy(final CEMI original) { // on original == null we just return null, too if (original instanceof CEMILDataEx) return (CEMI) ((CEMILDataEx) original).clone(); // all other are immutable return original; } // leave msgcode/src/dst/data null/0 to use from original private static CEMI create(final int msgCode, final IndividualAddress src, final KNXAddress dst, final byte[] data, final CEMILData original, final boolean ext, final boolean repeat) { final int mc = msgCode != 0 ? msgCode : original.getMessageCode(); final IndividualAddress s = src != null ? src : original.getSource(); final KNXAddress d = dst != null ? dst : original.getDestination(); final byte[] content = data != null ? data : original.getPayload(); if (original instanceof CEMILDataEx) { final CEMILDataEx f = (CEMILDataEx) original; final CEMILDataEx copy = new CEMILDataEx(mc, s, d, content, f.getPriority(), repeat, f .isDomainBroadcast(), f.isAckRequested(), f.getHopCount()); // copy additional info final List l = f.getAdditionalInfo(); for (final Iterator i = l.iterator(); i.hasNext();) { final CEMILDataEx.AddInfo info = (CEMILDataEx.AddInfo) i.next(); copy.addAdditionalInfo(info.getType(), info.getInfo()); } return copy; } if (ext) return new CEMILDataEx(mc, s, d, content, original.getPriority(), repeat, original.getHopCount()); return new CEMILData(mc, s, d, content, original.getPriority(), repeat, original.getHopCount()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy