/** * Called if a SYN packet was received * * @throws IOException */ protected void onEBusSyncReceived() throws IOException { if (inputBuffer.position() == 1 && inputBuffer.get(0) == EBusTelegram.SYN) { if (lockCounter > 0) lockCounter--; logger.trace("Auto-SYN byte received"); // send a telegram from queue if available send(false); } else if (inputBuffer.position() == 2 && inputBuffer.get(0) == EBusTelegram.SYN) { logger.warn("Collision on eBus detected (SYN DATA SYNC Sequence) ..."); blockNextSend = true; // send a telegram from queue if available send(false); } else if (inputBuffer.position() < 5) { if (lockCounter > 0) lockCounter--; logger.trace("Telegram to small, skip!"); // send a telegram from queue if available send(false); } else { if (lockCounter > 0) lockCounter--; byte[] receivedTelegram = Arrays.copyOf(inputBuffer.array(), inputBuffer.position()); // send a telegram from queue if available, time critical! send(false); // After senden we can process the last received telegram final EBusTelegram telegram = EBusUtils.processEBusData(receivedTelegram); if (telegram != null) { // execute event onEBusTelegramReceived(telegram); } else { logger.debug("Received telegram was invalid, skip!"); } } // reset receive buffer inputBuffer.clear(); }
/** * Add a byte array to send queue. * * @param data * @return */ public boolean send(byte[] data) { if (data == null || data.length == 0) { logger.debug("Send data is empty, skip"); return false; } byte crc = 0; for (int i = 0; i < data.length - 1; i++) { byte b = data[i]; crc = EBusUtils.crc8_tab(b, crc); } // replace crc with calculated value data[data.length - 1] = crc; return outputQueue.add(data); }
/** * Internal send function. Send and read to detect byte collisions. * * @param secondTry * @throws IOException */ protected void send(boolean secondTry) throws IOException { // blocked for this send slot because a collision if (blockNextSend) { logger.trace("Sender was blocked for this SYN ..."); blockNextSend = false; return; } // currently no data to send if (outputQueue.isEmpty()) { logger.trace("Send buffer is empty, nothing to send..."); return; } // counter not zero, it's not allowed to send yet if (lockCounter > 0) { logger.trace("No access to ebus because the lock counter ..."); return; } byte[] dataOutputBuffer = outputQueue.peek(); logger.debug( "EBusSerialPortEvent.send() data: {}", EBusUtils.toHexDumpString(dataOutputBuffer)); // clear first inputBuffer.clear(); boolean isMasterAddr = EBusUtils.isMasterAddress(dataOutputBuffer[1]); // send command for (int i = 0; i < dataOutputBuffer.length; i++) { byte b = dataOutputBuffer[i]; outputStream.write(b); // directly read the current wrote byte from bus int read = inputStream.read(); if (read != -1) { byte r = (byte) (read & 0xFF); inputBuffer.put(r); // do arbitation on on first byte only if (i == 0 && b != r) { // written and read byte not identical, that's // a collision logger.warn("eBus collision detected!"); // last send try was a collision if (lastSendCollisionDetected) { logger.warn("A second collision occured!"); resetSend(); return; } // priority class identical else if ((byte) (r & 0x0F) == (byte) (b & 0x0F)) { logger.trace("Priority class match, restart after next SYN ..."); lastSendCollisionDetected = true; } else { logger.trace("Priority class doesn't match, blocked for next SYN ..."); blockNextSend = true; } // stop after a collision return; } } } // sending master data finish // reset global variables lastSendCollisionDetected = false; blockNextSend = false; // if this telegram a broadcast? if (dataOutputBuffer[1] == (byte) 0xFE) { logger.warn("Broadcast send .............."); // sende master sync outputStream.write(EBusTelegram.SYN); inputBuffer.put(EBusTelegram.SYN); } else { int read = inputStream.read(); if (read != -1) { byte ack = (byte) (read & 0xFF); inputBuffer.put(ack); if (ack == EBusTelegram.ACK_OK) { // if the telegram is a slave telegram we will // get data from slave if (!isMasterAddr) { // len of answer byte nn2 = (byte) (inputStream.read() & 0xFF); inputBuffer.put(nn2); byte crc = EBusUtils.crc8_tab(nn2, (byte) 0); if (nn2 > 16) { logger.warn("slave data to lang, invalid!"); // resend telegram (max. once) if (!resend(secondTry)) return; } // read slave data, be aware of 0x0A bytes while (nn2 > 0) { byte d = (byte) (inputStream.read() & 0xFF); inputBuffer.put(d); crc = EBusUtils.crc8_tab(d, crc); if (d != (byte) 0xA) { nn2--; } } // read slave crc byte crc2 = (byte) (inputStream.read() & 0xFF); inputBuffer.put(crc2); // check slave crc if (crc2 != crc) { logger.warn("Slave CRC wrong, resend!"); // Resend telegram (max. once) if (!resend(secondTry)) return; } // sende master sync outputStream.write(EBusTelegram.ACK_OK); inputBuffer.put(EBusTelegram.ACK_OK); } // isMasterAddr check // send SYN byte outputStream.write(EBusTelegram.SYN); inputBuffer.put(EBusTelegram.SYN); } else if (ack == EBusTelegram.ACK_FAIL) { // clear uncompleted telegram inputBuffer.clear(); // resend telegram (max. once) if (!resend(secondTry)) return; } else if (ack == EBusTelegram.SYN) { logger.warn("No answer from slave, skip ..."); // clear uncompleted telegram or it will result // in uncomplete but valid telegram! inputBuffer.clear(); resetSend(); return; } else { // Wow, wrong answer, and now? logger.warn("Received wrong telegram: {}", EBusUtils.toHexDumpString(inputBuffer)); // clear uncompleted telegram inputBuffer.clear(); // resend telegram (max. once) if (!resend(secondTry)) return; } } } // after send process the received telegram byte[] buffer = Arrays.copyOf(inputBuffer.array(), inputBuffer.position()); final EBusTelegram telegram = EBusUtils.processEBusData(buffer); if (telegram != null) { onEBusTelegramReceived(telegram); } else { logger.debug("Received telegram was invalid, skip!"); } // reset send module resetSend(); }