@Override public void frameReceived(final FrameEvent e) { try { // with EMI1 frames, there is the possibility we receive some left-over Get-Value responses // from BCU switching during link setup, silently discard them final byte[] emi1 = e.getFrameBytes(); if (emi1 != null && BcuSwitcher.isEmi1GetValue(emi1[0] & 0xff)) return; final CEMI cemi = onReceive(e); if (cemi instanceof CEMIDevMgmt) { // XXX check .con correctly (required for setting cEMI link layer mode) final int mc = cemi.getMessageCode(); if (mc == CEMIDevMgmt.MC_PROPWRITE_CON) { final CEMIDevMgmt f = (CEMIDevMgmt) cemi; if (f.isNegativeResponse()) logger.error("L-DM negative response, " + f.getErrorMessage()); } } // from this point on, we are only dealing with L_Data if (!(cemi instanceof CEMILData)) return; final CEMILData f = (CEMILData) cemi; final int mc = f.getMessageCode(); if (mc == CEMILData.MC_LDATA_IND) { addEvent(l -> l.indication(new FrameEvent(source, f))); logger.debug("indication {}", f.toString()); } else if (mc == CEMILData.MC_LDATA_CON) { addEvent(l -> l.confirmation(new FrameEvent(source, f))); logger.debug("confirmation of {}", f.getDestination()); } else logger.warn("unspecified frame event - ignored, msg code = 0x" + Integer.toHexString(mc)); } catch (final KNXFormatException | RuntimeException ex) { logger.warn( "received unspecified frame {}", DataUnitBuilder.toHex(e.getFrameBytes(), ""), ex); } }
// Creates the target EMI format using a cEMI L-Data message private byte[] createEmi(final CEMILData f) { if (cEMI) { final CEMILData adjusted = adjustMsgType(f); addMediumInfo(adjusted); return adjusted.toByteArray(); } return CEMIFactory.toEmi(f); }
@Override public void confirmation(final FrameEvent e) { assertNotNull(e); assertEquals(lnk, e.getSource()); final CEMILData f = (CEMILData) e.getFrame(); con = f; assertEquals(CEMILData.MC_LDATA_CON, f.getMessageCode()); assertTrue(f.isPositiveConfirmation()); System.out.println("confirmation"); Debug.printLData(f); }
private CEMILData adjustMsgType(final CEMILData msg) { final boolean srcOk = msg.getSource().getRawAddress() != 0; // just return if we don't need to adjust source address and don't need LDataEx if ((srcOk || medium.getDeviceAddress().getRawAddress() == 0) && (medium instanceof TPSettings || msg instanceof CEMILDataEx)) return msg; return CEMIFactory.create(srcOk ? null : medium.getDeviceAddress(), null, msg, true); }
@Override public void indication(final FrameEvent e) { assertNotNull(e); assertEquals(lnk, e.getSource()); final CEMILData f = (CEMILData) e.getFrame(); ind = f; assertEquals(CEMILData.MC_LDATA_IND, ind.getMessageCode()); System.out.println("indication"); Debug.printLData(ind); }
@Override public void send(final CEMILData msg, final boolean waitForCon) throws KNXTimeoutException, KNXLinkClosedException { if (closed) throw new KNXLinkClosedException("link closed"); if (cEMI && !sendCEmiAsByteArray) { final CEMILData adjusted = adjustMsgType(msg); addMediumInfo(adjusted); onSend(adjusted, waitForCon); return; } onSend(msg.getDestination(), createEmi(msg), waitForCon); }
/** * {@inheritDoc}<br> * If a maximum size is set and the queue already reached maximum size, if {@link #isOverwrite()} * evaluates to<br> * - <code>true</code>, <code>frame</code> will replace the oldest inserted frame<br> * - <code>false</code>, <code>frame</code> is ignored and not queued. */ public synchronized void setFrame(final CEMILData frame) { if (!frame.getDestination().equals(getKey())) throw new KNXIllegalArgumentException("frame key differs from this key"); if (!max) ensureCapacity(); else if (!overwrite && size == timestamps.length) return; final CEMILData[] c = (CEMILData[]) value; // notify on first time queue fills up final boolean notifyListener = max && size == c.length - 1; resetTimestamp(); c[next] = frame; timestamps[next] = getTimestamp(); ++next; next %= c.length; if (size < c.length) ++size; if (notifyListener) fireQueueFilled(); }