/** * The Dialog Class * * @author Frank Kunz The dialog class draws the basic dialog with a grid layout. The dialog * consists of three main parts. A settings panel, a table panel and three buttons. */ public final class UARTProtocolAnalysisDialog extends BaseAsyncToolDialog<UARTDataSet, UARTAnalyserWorker> { // INNER TYPES /** Provides a combobox renderer for {@link UARTParity} values. */ static final class UARTParityItemRenderer extends EnumItemRenderer<UARTParity> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final UARTParity aValue) { String text = super.getDisplayValue(aValue); if (UARTParity.EVEN.equals(aValue)) { text = "Even parity"; } else if (UARTParity.NONE.equals(aValue)) { text = "No parity"; } else if (UARTParity.ODD.equals(aValue)) { text = "Odd parity"; } return text; } } /** Provides a combobox renderer for {@link UARTStopBits} values. */ static final class UARTStopBitsItemRenderer extends EnumItemRenderer<UARTStopBits> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final UARTStopBits aValue) { String text = super.getDisplayValue(aValue); if (UARTStopBits.STOP_1.equals(aValue)) { text = "1"; } else if (UARTStopBits.STOP_15.equals(aValue)) { text = "1.5"; } else if (UARTStopBits.STOP_2.equals(aValue)) { text = "2"; } return text; } } // CONSTANTS private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(UARTProtocolAnalysisDialog.class.getName()); // VARIABLES private JComboBox rxd; private JComboBox txd; private JComboBox cts; private JComboBox rts; private JComboBox dtr; private JComboBox dsr; private JComboBox dcd; private JComboBox ri; private JComboBox parity; private JComboBox bits; private JComboBox stop; private JCheckBox inv; private JEditorPane outText; private RestorableAction runAnalysisAction; private Action exportAction; private Action closeAction; // CONSTRUCTORS /** * @param aOwner * @param aName */ public UARTProtocolAnalysisDialog(final Window aOwner, final String aName) { super(aOwner, aName); initDialog(); setLocationRelativeTo(getOwner()); } // METHODS /** * This is the UART protocol decoder core The decoder scans for a decode start event like CS high * to low edge or the trigger of the captured data. After this the decoder starts to decode the * data by the selected mode, number of bits and bit order. The decoded data are put to a JTable * object directly. */ @Override public void onToolWorkerReady(final UARTDataSet aAnalysisResult) { super.onToolWorkerReady(aAnalysisResult); try { final String htmlPage; if (aAnalysisResult != null) { htmlPage = toHtmlPage(null /* aFile */, aAnalysisResult); this.exportAction.setEnabled(!aAnalysisResult.isEmpty()); } else { htmlPage = getEmptyHtmlPage(); this.exportAction.setEnabled(false); } this.outText.setText(htmlPage); this.outText.setEditable(false); this.runAnalysisAction.restore(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { // Should not happen in this situation! throw new RuntimeException(exception); } } } /** @see nl.lxtreme.ols.api.Configurable#readPreferences(nl.lxtreme.ols.api.UserSettings) */ @Override public void readPreferences(final UserSettings aSettings) { this.rxd.setSelectedIndex(aSettings.getInt("rxd", this.rxd.getSelectedIndex())); this.txd.setSelectedIndex(aSettings.getInt("txd", this.txd.getSelectedIndex())); this.cts.setSelectedIndex(aSettings.getInt("cts", this.cts.getSelectedIndex())); this.rts.setSelectedIndex(aSettings.getInt("rts", this.rts.getSelectedIndex())); this.dtr.setSelectedIndex(aSettings.getInt("dtr", this.dtr.getSelectedIndex())); this.dsr.setSelectedIndex(aSettings.getInt("dsr", this.dsr.getSelectedIndex())); this.dcd.setSelectedIndex(aSettings.getInt("dcd", this.dcd.getSelectedIndex())); this.ri.setSelectedIndex(aSettings.getInt("ri", this.ri.getSelectedIndex())); this.parity.setSelectedIndex(aSettings.getInt("parity", this.parity.getSelectedIndex())); this.bits.setSelectedIndex(aSettings.getInt("bits", this.bits.getSelectedIndex())); this.stop.setSelectedIndex(aSettings.getInt("stop", this.stop.getSelectedIndex())); this.inv.setSelected(aSettings.getBoolean("inverted", this.inv.isSelected())); } /** @see nl.lxtreme.ols.tool.base.ToolDialog#reset() */ @Override public void reset() { this.outText.setText(getEmptyHtmlPage()); this.outText.setEditable(false); this.exportAction.setEnabled(false); this.runAnalysisAction.restore(); setControlsEnabled(true); } /** @see nl.lxtreme.ols.api.Configurable#writePreferences(nl.lxtreme.ols.api.UserSettings) */ @Override public void writePreferences(final UserSettings aSettings) { aSettings.putInt("rxd", this.rxd.getSelectedIndex()); aSettings.putInt("txd", this.txd.getSelectedIndex()); aSettings.putInt("cts", this.cts.getSelectedIndex()); aSettings.putInt("rts", this.rts.getSelectedIndex()); aSettings.putInt("dtr", this.dtr.getSelectedIndex()); aSettings.putInt("dsr", this.dsr.getSelectedIndex()); aSettings.putInt("dcd", this.dcd.getSelectedIndex()); aSettings.putInt("ri", this.ri.getSelectedIndex()); aSettings.putInt("parity", this.parity.getSelectedIndex()); aSettings.putInt("bits", this.bits.getSelectedIndex()); aSettings.putInt("stop", this.stop.getSelectedIndex()); aSettings.putBoolean("inverted", this.inv.isSelected()); } /** * set the controls of the dialog enabled/disabled * * @param aEnable status of the controls */ @Override protected void setControlsEnabled(final boolean aEnable) { this.rxd.setEnabled(aEnable); this.txd.setEnabled(aEnable); this.cts.setEnabled(aEnable); this.rts.setEnabled(aEnable); this.dtr.setEnabled(aEnable); this.dsr.setEnabled(aEnable); this.dcd.setEnabled(aEnable); this.ri.setEnabled(aEnable); this.parity.setEnabled(aEnable); this.bits.setEnabled(aEnable); this.stop.setEnabled(aEnable); this.inv.setEnabled(aEnable); this.closeAction.setEnabled(aEnable); } /** * @see * nl.lxtreme.ols.tool.base.BaseAsyncToolDialog#setupToolWorker(nl.lxtreme.ols.tool.base.BaseAsyncToolWorker) */ @Override protected void setupToolWorker(final UARTAnalyserWorker aToolWorker) { // The value at index zero is "Unused", so extracting one of all items // causes all "unused" values to be equivalent to -1, which is interpreted // as not used... aToolWorker.setRxdIndex(this.rxd.getSelectedIndex() - 1); aToolWorker.setTxdIndex(this.txd.getSelectedIndex() - 1); aToolWorker.setCtsIndex(this.cts.getSelectedIndex() - 1); aToolWorker.setRtsIndex(this.rts.getSelectedIndex() - 1); aToolWorker.setDcdIndex(this.dcd.getSelectedIndex() - 1); aToolWorker.setRiIndex(this.ri.getSelectedIndex() - 1); aToolWorker.setDsrIndex(this.dsr.getSelectedIndex() - 1); aToolWorker.setDtrIndex(this.dtr.getSelectedIndex() - 1); // Other properties... aToolWorker.setInverted(this.inv.isSelected()); aToolWorker.setParity((UARTParity) this.parity.getSelectedItem()); aToolWorker.setStopBits((UARTStopBits) this.stop.getSelectedItem()); aToolWorker.setBitCount(NumberUtils.smartParseInt((String) this.bits.getSelectedItem(), 8)); } /** * exports the data to a CSV file * * @param aFile File object */ @Override protected void storeToCsvFile(final File aFile, final UARTDataSet aDataSet) { try { final CsvExporter exporter = ExportUtils.createCsvExporter(aFile); exporter.setHeaders( "index", "start-time", "end-time", "event?", "event-type", "RxD event", "TxD event", "RxD data", "TxD data"); final List<UARTData> decodedData = aDataSet.getData(); for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); final String startTime = aDataSet.getDisplayTime(ds.getStartSampleIndex()); final String endTime = aDataSet.getDisplayTime(ds.getEndSampleIndex()); String eventType = null; String rxdEvent = null; String txdEvent = null; String rxdData = null; String txdData = null; switch (ds.getType()) { case UARTData.UART_TYPE_EVENT: eventType = ds.getEventName(); break; case UARTData.UART_TYPE_RXEVENT: rxdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_TXEVENT: txdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_RXDATA: rxdData = Integer.toString(ds.getData()); break; case UARTData.UART_TYPE_TXDATA: txdData = Integer.toString(ds.getData()); break; default: break; } exporter.addRow( Integer.valueOf(i), startTime, endTime, Boolean.valueOf(ds.isEvent()), eventType, rxdEvent, txdEvent, rxdData, txdData); } exporter.close(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "CSV export failed!", exception); } } } /** * stores the data to a HTML file * * @param aFile file object */ @Override protected void storeToHtmlFile(final File aFile, final UARTDataSet aDataSet) { try { toHtmlPage(aFile, aDataSet); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "HTML export failed!", exception); } } } /** * Creates the HTML template for exports to HTML. * * @param aExporter the HTML exporter instance to use, cannot be <code>null</code>. * @return a HTML exporter filled with the template, never <code>null</code>. */ private HtmlExporter createHtmlTemplate(final HtmlExporter aExporter) { aExporter.addCssStyle("body { font-family: sans-serif; } "); aExporter.addCssStyle( "table { border-width: 1px; border-spacing: 0px; border-color: gray;" + " border-collapse: collapse; border-style: solid; margin-bottom: 15px; } "); aExporter.addCssStyle( "table th { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " background-color: #C0C0FF; text-align: left; font-weight: bold; font-family: sans-serif; } "); aExporter.addCssStyle( "table td { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " font-family: monospace; } "); aExporter.addCssStyle(".error { color: red; } "); aExporter.addCssStyle(".warning { color: orange; } "); aExporter.addCssStyle(".date { text-align: right; font-size: x-small; margin-bottom: 15px; } "); aExporter.addCssStyle(".w100 { width: 100%; } "); aExporter.addCssStyle(".w35 { width: 35%; } "); aExporter.addCssStyle(".w30 { width: 30%; } "); aExporter.addCssStyle(".w15 { width: 15%; } "); aExporter.addCssStyle(".w10 { width: 10%; } "); aExporter.addCssStyle(".w8 { width: 8%; } "); aExporter.addCssStyle(".w7 { width: 7%; } "); final Element body = aExporter.getBody(); body.addChild(H1).addContent("UART Analysis results"); body.addChild(HR); body.addChild(DIV).addAttribute("class", "date").addContent("Generated: ", "{date-now}"); Element table, tr, thead, tbody; table = body.addChild(TABLE).addAttribute("class", "w100"); tbody = table.addChild(TBODY); tr = tbody.addChild(TR); tr.addChild(TH).addAttribute("colspan", "2").addContent("Statistics"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Decoded bytes"); tr.addChild(TD).addContent("{decoded-bytes}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Detected bus errors"); tr.addChild(TD).addContent("{detected-bus-errors}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Baudrate"); tr.addChild(TD).addContent("{baudrate}"); table = body.addChild(TABLE).addAttribute("class", "w100"); thead = table.addChild(THEAD); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w30").addAttribute("colspan", "2"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("RxD"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("TxD"); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w15").addContent("Index"); tr.addChild(TH).addAttribute("class", "w15").addContent("Time"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tbody = table.addChild(TBODY); tbody.addContent("{decoded-data}"); return aExporter; } /** @return */ private JPanel createPreviewPane() { final JPanel panTable = new JPanel(new GridLayout(1, 1, 0, 0)); this.outText = new JEditorPane("text/html", getEmptyHtmlPage()); this.outText.setEditable(false); panTable.add(new JScrollPane(this.outText)); return panTable; } /** @return */ private JPanel createSettingsPane() { final String channels[] = new String[33]; channels[0] = "Unused"; for (int i = 0; i < 32; i++) { channels[i + 1] = new String("Channel " + i); } final JPanel settings = new JPanel(new SpringLayout()); SpringLayoutUtils.addSeparator(settings, "Settings"); settings.add(createRightAlignedLabel("RxD")); this.rxd = new JComboBox(channels); this.rxd.setSelectedIndex(0); settings.add(this.rxd); settings.add(createRightAlignedLabel("TxD")); this.txd = new JComboBox(channels); this.txd.setSelectedIndex(0); settings.add(this.txd); settings.add(createRightAlignedLabel("CTS")); this.cts = new JComboBox(channels); this.cts.setSelectedIndex(0); settings.add(this.cts); settings.add(createRightAlignedLabel("RTS")); this.rts = new JComboBox(channels); this.rts.setSelectedIndex(0); settings.add(this.rts); settings.add(createRightAlignedLabel("DTR")); this.dtr = new JComboBox(channels); this.dtr.setSelectedIndex(0); settings.add(this.dtr); settings.add(createRightAlignedLabel("DSR")); this.dsr = new JComboBox(channels); this.dsr.setSelectedIndex(0); settings.add(this.dsr); settings.add(createRightAlignedLabel("DCD")); this.dcd = new JComboBox(channels); this.dcd.setSelectedIndex(0); settings.add(this.dcd); settings.add(createRightAlignedLabel("RI")); this.ri = new JComboBox(channels); this.ri.setSelectedIndex(0); settings.add(this.ri); settings.add(createRightAlignedLabel("Parity")); this.parity = new JComboBox(UARTParity.values()); this.parity.setSelectedIndex(0); this.parity.setRenderer(new UARTParityItemRenderer()); settings.add(this.parity); settings.add(createRightAlignedLabel("Bits")); final String[] bitarray = new String[4]; for (int i = 0; i < bitarray.length; i++) { bitarray[i] = String.format("%d", Integer.valueOf(i + 5)); } this.bits = new JComboBox(bitarray); this.bits.setSelectedIndex(3); settings.add(this.bits); settings.add(createRightAlignedLabel("Stopbits")); this.stop = new JComboBox(UARTStopBits.values()); this.stop.setSelectedIndex(0); this.stop.setRenderer(new UARTStopBitsItemRenderer()); settings.add(this.stop); this.inv = new JCheckBox(); this.inv.setSelected(false); settings.add(createRightAlignedLabel("Invert?")); settings.add(this.inv); SpringLayoutUtils.makeEditorGrid(settings, 10, 4); return settings; } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String getEmptyHtmlPage() { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString( new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro) || "detected-bus-errors".equals(aMacro) || "baudrate".equals(aMacro)) { return "-"; } else if ("decoded-data".equals(aMacro)) { return null; } return null; } }); } /** Initializes this dialog. */ private void initDialog() { setMinimumSize(new Dimension(640, 480)); final JComponent settingsPane = createSettingsPane(); final JComponent previewPane = createPreviewPane(); final JPanel contentPane = new JPanel(new GridBagLayout()); contentPane.add( settingsPane, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 0, 2, 0), 0, 0)); contentPane.add( previewPane, new GridBagConstraints( 1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(2, 0, 2, 0), 0, 0)); final JButton runAnalysisButton = createRunAnalysisButton(); this.runAnalysisAction = (RestorableAction) runAnalysisButton.getAction(); final JButton exportButton = createExportButton(); this.exportAction = exportButton.getAction(); this.exportAction.setEnabled(false); final JButton closeButton = createCloseButton(); this.closeAction = closeButton.getAction(); final JComponent buttons = SwingComponentUtils.createButtonPane(runAnalysisButton, exportButton, closeButton); SwingComponentUtils.setupDialogContentPane(this, contentPane, buttons, runAnalysisButton); } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String toHtmlPage(final File aFile, final UARTDataSet aDataSet) throws IOException { final int bitCount = Integer.parseInt((String) this.bits.getSelectedItem()); final int bitAdder = (bitCount % 4 != 0) ? 1 : 0; final MacroResolver macroResolver = new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro)) { return Integer.valueOf(aDataSet.getDecodedSymbols()); } else if ("detected-bus-errors".equals(aMacro)) { return Integer.valueOf(aDataSet.getDetectedErrors()); } else if ("baudrate".equals(aMacro)) { final String baudrate; if (aDataSet.getBitLength() <= 0) { baudrate = "<span class='error'>Baudrate calculation failed!</span>"; } else { baudrate = String.format( "%d (exact: %d)", Integer.valueOf(aDataSet.getBaudRate()), Integer.valueOf(aDataSet.getBaudRateExact())); if (aDataSet.getBitLength() < 15) { return baudrate.concat( " <span class='warning'>The baudrate may be wrong, use a higher samplerate to avoid this!</span>"); } return baudrate; } } else if ("decoded-data".equals(aMacro)) { final List<UARTData> decodedData = aDataSet.getData(); Element tr; for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); if (ds.isEvent()) { String rxEventData = ""; String txEventData = ""; String bgColor; if (UARTData.UART_TYPE_EVENT == ds.getType()) { rxEventData = txEventData = ds.getEventName(); bgColor = "#e0e0e0"; } else if (UARTData.UART_TYPE_RXEVENT == ds.getType()) { rxEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else if (UARTData.UART_TYPE_TXEVENT == ds.getType()) { txEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else { // unknown event bgColor = "#ff8000"; } if (txEventData.endsWith("_ERR") || rxEventData.endsWith("_ERR")) { bgColor = "#ff8000"; } tr = aParent .addChild(TR) .addAttribute("style", "background-color: " + bgColor + ";"); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD).addContent(aDataSet.getDisplayTime(ds.getStartSampleIndex())); tr.addChild(TD).addContent(rxEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD).addContent(txEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); } else { String rxDataHex = "", rxDataBin = "", rxDataDec = "", rxDataASCII = ""; String txDataHex = "", txDataBin = "", txDataDec = "", txDataASCII = ""; // Normal data... if (UARTData.UART_TYPE_RXDATA == ds.getType()) { final int rxData = ds.getData(); rxDataHex = "0x" + DisplayUtils.integerToHexString(rxData, bitCount / 4 + bitAdder); rxDataBin = "0b" + DisplayUtils.integerToBinString(rxData, bitCount); rxDataDec = String.valueOf(rxData); if ((rxData >= 32) && (bitCount == 8)) { rxDataASCII = String.valueOf((char) rxData); } } else /* if ( UARTData.UART_TYPE_TXDATA == ds.getType() ) */ { final int txData = ds.getData(); txDataHex = "0x" + DisplayUtils.integerToHexString(txData, bitCount / 4 + bitAdder); txDataBin = "0b" + DisplayUtils.integerToBinString(txData, bitCount); txDataDec = String.valueOf(txData); if ((txData >= 32) && (bitCount == 8)) { txDataASCII = String.valueOf((char) txData); } } tr = aParent.addChild(TR); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD).addContent(aDataSet.getDisplayTime(ds.getStartSampleIndex())); tr.addChild(TD).addContent(rxDataHex); tr.addChild(TD).addContent(rxDataBin); tr.addChild(TD).addContent(rxDataDec); tr.addChild(TD).addContent(rxDataASCII); tr.addChild(TD).addContent(txDataHex); tr.addChild(TD).addContent(txDataBin); tr.addChild(TD).addContent(txDataDec); tr.addChild(TD).addContent(txDataASCII); } } } return null; } }; if (aFile == null) { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString(macroResolver); } else { final HtmlFileExporter exporter = (HtmlFileExporter) createHtmlTemplate(ExportUtils.createHtmlExporter(aFile)); exporter.write(macroResolver); exporter.close(); } return null; } }
/** * The Dialog Class * * @author Frank Kunz The dialog class draws the basic dialog with a grid layout. The dialog * consists of three main parts. A settings panel, a table panel and three buttons. */ public final class UARTProtocolAnalysisDialog extends BaseToolDialog<UARTDataSet> implements ExportAware<UARTDataSet> { // INNER TYPES /** Provides a combobox renderer for {@link UARTParity} values. */ static final class UARTParityItemRenderer extends EnumItemRenderer<Parity> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final Parity aValue) { String text = super.getDisplayValue(aValue); if (Parity.EVEN.equals(aValue)) { text = "Even parity"; } else if (Parity.NONE.equals(aValue)) { text = "No parity"; } else if (Parity.ODD.equals(aValue)) { text = "Odd parity"; } return text; } } /** Provides a combobox renderer for {@link UARTStopBits} values. */ static final class UARTStopBitsItemRenderer extends EnumItemRenderer<StopBits> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final StopBits aValue) { String text = super.getDisplayValue(aValue); if (StopBits.ONE.equals(aValue)) { text = "1"; } else if (StopBits.ONE_HALF.equals(aValue)) { text = "1.5"; } else if (StopBits.TWO.equals(aValue)) { text = "2"; } return text; } } /** Provides a combobox renderer for {@link BitOrder} values. */ static final class UARTBitOrderItemRenderer extends EnumItemRenderer<BitOrder> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitOrder aValue) { String text = super.getDisplayValue(aValue); if (BitOrder.LSB_FIRST.equals(aValue)) { text = "LSB first"; } else if (BitOrder.MSB_FIRST.equals(aValue)) { text = "MSB first"; } return text; } } /** Provides a combobox renderer for {@link BitEncoding} values. */ static final class UARTBitEncodingItemRenderer extends EnumItemRenderer<BitEncoding> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitEncoding aValue) { String text = super.getDisplayValue(aValue); if (BitEncoding.HIGH_IS_MARK.equals(aValue)) { text = "High is mark (1)"; } else if (BitEncoding.HIGH_IS_SPACE.equals(aValue)) { text = "High is space (0)"; } return text; } } /** Provides a combobox renderer for {@link BitLevel} values. */ static final class UARTIdleLevelItemRenderer extends EnumItemRenderer<BitLevel> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitLevel aValue) { String text = super.getDisplayValue(aValue); if (BitLevel.HIGH.equals(aValue)) { text = "High (start = L, stop = H)"; } else if (BitLevel.LOW.equals(aValue)) { text = "Low (start = H, stop = L)"; } return text; } } // CONSTANTS private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(UARTProtocolAnalysisDialog.class.getName()); // VARIABLES private JComboBox rxd; private JComboBox txd; private JComboBox cts; private JComboBox rts; private JComboBox dtr; private JComboBox dsr; private JComboBox dcd; private JComboBox ri; private JComboBox parity; private JComboBox bits; private JComboBox stop; private JComboBox bitEncoding; private JComboBox bitOrder; private JComboBox idleLevel; private JCheckBox autoDetectBaudRate; private JComboBox baudrate; private JEditorPane outText; private RestorableAction runAnalysisAction; private Action closeAction; private Action exportAction; // CONSTRUCTORS /** * Creates a new UARTProtocolAnalysisDialog instance. * * @param aOwner the owner of this dialog; * @param aToolContext the tool context; * @param aContext the OSGi bundle context to use; * @param aTool the {@link UARTAnalyser} tool. */ public UARTProtocolAnalysisDialog( final Window aOwner, final ToolContext aToolContext, final BundleContext aContext, final UARTAnalyser aTool) { super(aOwner, aToolContext, aContext, aTool); initDialog(); setLocationRelativeTo(getOwner()); } // METHODS /** {@inheritDoc} */ @Override public void exportToFile( final File aOutputFile, final nl.lxtreme.ols.tool.base.ExportAware.ExportFormat aFormat) throws IOException { if (ExportFormat.HTML.equals(aFormat)) { storeToHtmlFile(aOutputFile, getLastResult()); } else if (ExportFormat.CSV.equals(aFormat)) { storeToCsvFile(aOutputFile, getLastResult()); } } /** {@inheritDoc} */ @Override public void readPreferences(final UserSettings aSettings) { // Issue #114: avoid setting illegal values... setComboBoxIndex(this.rxd, aSettings, "rxd"); setComboBoxIndex(this.txd, aSettings, "txd"); setComboBoxIndex(this.cts, aSettings, "cts"); setComboBoxIndex(this.rts, aSettings, "rts"); setComboBoxIndex(this.dtr, aSettings, "dtr"); setComboBoxIndex(this.dsr, aSettings, "dsr"); setComboBoxIndex(this.dcd, aSettings, "dcd"); setComboBoxIndex(this.ri, aSettings, "ri"); this.parity.setSelectedIndex(aSettings.getInt("parity", this.parity.getSelectedIndex())); this.bits.setSelectedIndex(aSettings.getInt("bits", this.bits.getSelectedIndex())); this.stop.setSelectedIndex(aSettings.getInt("stop", this.stop.getSelectedIndex())); this.idleLevel.setSelectedIndex( aSettings.getInt("idle-state", this.idleLevel.getSelectedIndex())); this.bitEncoding.setSelectedIndex( aSettings.getInt("bit-encoding", this.bitEncoding.getSelectedIndex())); this.bitOrder.setSelectedIndex(aSettings.getInt("bit-order", this.bitOrder.getSelectedIndex())); this.baudrate.setSelectedItem(Integer.valueOf(aSettings.getInt("baudrate", 9600))); this.autoDetectBaudRate.setSelected( aSettings.getBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected())); } /** {@inheritDoc} */ @Override public void reset() { this.outText.setText(getEmptyHtmlPage()); this.outText.setEditable(false); this.runAnalysisAction.restore(); setControlsEnabled(true); this.exportAction.setEnabled(false); } /** @see nl.lxtreme.ols.api.Configurable#writePreferences(nl.lxtreme.ols.api.UserSettings) */ @Override public void writePreferences(final UserSettings aSettings) { aSettings.putInt("rxd", this.rxd.getSelectedIndex()); aSettings.putInt("txd", this.txd.getSelectedIndex()); aSettings.putInt("cts", this.cts.getSelectedIndex()); aSettings.putInt("rts", this.rts.getSelectedIndex()); aSettings.putInt("dtr", this.dtr.getSelectedIndex()); aSettings.putInt("dsr", this.dsr.getSelectedIndex()); aSettings.putInt("dcd", this.dcd.getSelectedIndex()); aSettings.putInt("ri", this.ri.getSelectedIndex()); aSettings.putInt("parity", this.parity.getSelectedIndex()); aSettings.putInt("bits", this.bits.getSelectedIndex()); aSettings.putInt("stop", this.stop.getSelectedIndex()); aSettings.putInt("idle-state", this.idleLevel.getSelectedIndex()); aSettings.putInt("bit-encoding", this.bitEncoding.getSelectedIndex()); aSettings.putInt("bit-order", this.bitOrder.getSelectedIndex()); aSettings.putInt("baudrate", ((Integer) this.baudrate.getSelectedItem()).intValue()); aSettings.putBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected()); } /** {@inheritDoc} */ @Override protected void onToolEnded(final UARTDataSet aAnalysisResult) { try { final String htmlPage; if (aAnalysisResult != null) { htmlPage = toHtmlPage(null /* aFile */, aAnalysisResult); } else { htmlPage = getEmptyHtmlPage(); } this.outText.setText(htmlPage); this.outText.setEditable(false); this.runAnalysisAction.restore(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { // Should not happen in this situation! throw new RuntimeException(exception); } } } /** {@inheritDoc} */ @Override protected void onToolStarted() { // NO-op } /** {@inheritDoc} */ @Override protected void prepareToolTask(final ToolTask<UARTDataSet> aToolTask) { final UARTAnalyserTask toolTask = (UARTAnalyserTask) aToolTask; // The value at index zero is "Unused", so extracting one of all items // causes all "unused" values to be equivalent to -1, which is interpreted // as not used... toolTask.setRxdIndex(this.rxd.getSelectedIndex() - 1); toolTask.setTxdIndex(this.txd.getSelectedIndex() - 1); toolTask.setCtsIndex(this.cts.getSelectedIndex() - 1); toolTask.setRtsIndex(this.rts.getSelectedIndex() - 1); toolTask.setDcdIndex(this.dcd.getSelectedIndex() - 1); toolTask.setRiIndex(this.ri.getSelectedIndex() - 1); toolTask.setDsrIndex(this.dsr.getSelectedIndex() - 1); toolTask.setDtrIndex(this.dtr.getSelectedIndex() - 1); // Handle the auto detect option for baudrates... if (this.autoDetectBaudRate.isSelected()) { toolTask.setBaudRate(UARTAnalyserTask.AUTO_DETECT_BAUDRATE); } else { toolTask.setBaudRate(((Integer) this.baudrate.getSelectedItem()).intValue()); } // Other properties... toolTask.setIdleLevel((BitLevel) this.idleLevel.getSelectedItem()); toolTask.setBitEncoding((BitEncoding) this.bitEncoding.getSelectedItem()); toolTask.setBitOrder((BitOrder) this.bitOrder.getSelectedItem()); toolTask.setParity((Parity) this.parity.getSelectedItem()); toolTask.setStopBits((StopBits) this.stop.getSelectedItem()); toolTask.setBitCount(NumberUtils.smartParseInt((String) this.bits.getSelectedItem(), 8)); } /** * set the controls of the dialog enabled/disabled * * @param aEnable status of the controls */ @Override protected void setControlsEnabled(final boolean aEnable) { this.rxd.setEnabled(aEnable); this.txd.setEnabled(aEnable); this.cts.setEnabled(aEnable); this.rts.setEnabled(aEnable); this.dtr.setEnabled(aEnable); this.dsr.setEnabled(aEnable); this.dcd.setEnabled(aEnable); this.ri.setEnabled(aEnable); this.parity.setEnabled(aEnable); this.bits.setEnabled(aEnable); this.stop.setEnabled(aEnable); this.idleLevel.setEnabled(aEnable); this.bitEncoding.setEnabled(aEnable); this.bitOrder.setEnabled(aEnable); this.closeAction.setEnabled(aEnable); this.exportAction.setEnabled(aEnable); } /** * Creates the HTML template for exports to HTML. * * @param aExporter the HTML exporter instance to use, cannot be <code>null</code>. * @return a HTML exporter filled with the template, never <code>null</code>. */ private HtmlExporter createHtmlTemplate(final HtmlExporter aExporter) { aExporter.addCssStyle("body { font-family: sans-serif; } "); aExporter.addCssStyle( "table { border-width: 1px; border-spacing: 0px; border-color: gray;" + " border-collapse: collapse; border-style: solid; margin-bottom: 15px; } "); aExporter.addCssStyle( "table th { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " background-color: #C0C0FF; text-align: left; font-weight: bold; font-family: sans-serif; } "); aExporter.addCssStyle( "table td { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " font-family: monospace; } "); aExporter.addCssStyle(".error { color: red; } "); aExporter.addCssStyle(".warning { color: orange; } "); aExporter.addCssStyle(".date { text-align: right; font-size: x-small; margin-bottom: 15px; } "); aExporter.addCssStyle(".w100 { width: 100%; } "); aExporter.addCssStyle(".w35 { width: 35%; } "); aExporter.addCssStyle(".w30 { width: 30%; } "); aExporter.addCssStyle(".w15 { width: 15%; } "); aExporter.addCssStyle(".w10 { width: 10%; } "); aExporter.addCssStyle(".w8 { width: 8%; } "); aExporter.addCssStyle(".w7 { width: 7%; } "); final Element body = aExporter.getBody(); body.addChild(H1).addContent("UART Analysis results"); body.addChild(HR); body.addChild(DIV).addAttribute("class", "date").addContent("Generated: ", "{date-now}"); Element table, tr, thead, tbody; table = body.addChild(TABLE).addAttribute("class", "w100"); tbody = table.addChild(TBODY); tr = tbody.addChild(TR); tr.addChild(TH).addAttribute("colspan", "2").addContent("Statistics"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Decoded bytes"); tr.addChild(TD).addContent("{decoded-bytes}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Detected bus errors"); tr.addChild(TD).addContent("{detected-bus-errors}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Baudrate"); tr.addChild(TD).addContent("{baudrate}"); table = body.addChild(TABLE).addAttribute("class", "w100"); thead = table.addChild(THEAD); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w30").addAttribute("colspan", "2"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("RxD"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("TxD"); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w15").addContent("Index"); tr.addChild(TH).addAttribute("class", "w15").addContent("Time"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tbody = table.addChild(TBODY); tbody.addContent("{decoded-data}"); return aExporter; } /** @return */ private JPanel createPreviewPane() { final JPanel panTable = new JPanel(new GridLayout(1, 1, 0, 0)); this.outText = new JEditorPane("text/html", getEmptyHtmlPage()); this.outText.setEditable(false); panTable.add(new JScrollPane(this.outText)); return panTable; } /** @return */ private JPanel createSettingsPane() { final int channelCount = getData().getChannels(); final Integer[] baudrates = new Integer[AsyncSerialDataDecoder.COMMON_BAUDRATES.length]; for (int i = 0; i < baudrates.length; i++) { baudrates[i] = Integer.valueOf(AsyncSerialDataDecoder.COMMON_BAUDRATES[i]); } final String[] bitarray = new String[10]; // allow symbol lengths between 5 and 14 bits... for (int i = 0; i < bitarray.length; i++) { bitarray[i] = String.format("%d", Integer.valueOf(i + 5)); } final JPanel settings = new JPanel(new SpringLayout()); SpringLayoutUtils.addSeparator(settings, "Settings"); settings.add(createRightAlignedLabel("RxD")); this.rxd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rxd); settings.add(createRightAlignedLabel("TxD")); this.txd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.txd); settings.add(createRightAlignedLabel("CTS")); this.cts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.cts); settings.add(createRightAlignedLabel("RTS")); this.rts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rts); settings.add(createRightAlignedLabel("DTR")); this.dtr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dtr); settings.add(createRightAlignedLabel("DSR")); this.dsr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dsr); settings.add(createRightAlignedLabel("DCD")); this.dcd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dcd); settings.add(createRightAlignedLabel("RI")); this.ri = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.ri); settings.add(createRightAlignedLabel("Baudrate")); this.autoDetectBaudRate = new JCheckBox("Auto detect"); settings.add(this.autoDetectBaudRate); settings.add(new JLabel("")); this.baudrate = new JComboBox(baudrates); // Issue #90: allow custom baudrates to be specified... this.baudrate.setEditable(true); this.baudrate.setSelectedIndex(0); settings.add(this.baudrate); this.autoDetectBaudRate.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent aEvent) { final JCheckBox cb = (JCheckBox) aEvent.getSource(); UARTProtocolAnalysisDialog.this.baudrate.setEnabled(!cb.isSelected()); } }); settings.add(createRightAlignedLabel("Parity")); this.parity = new JComboBox(Parity.values()); this.parity.setSelectedIndex(0); this.parity.setRenderer(new UARTParityItemRenderer()); settings.add(this.parity); settings.add(createRightAlignedLabel("Bits")); this.bits = new JComboBox(bitarray); this.bits.setSelectedIndex(3); settings.add(this.bits); settings.add(createRightAlignedLabel("Stopbits")); this.stop = new JComboBox(StopBits.values()); this.stop.setSelectedIndex(0); this.stop.setRenderer(new UARTStopBitsItemRenderer()); settings.add(this.stop); settings.add(createRightAlignedLabel("Idle level")); this.idleLevel = new JComboBox(BitLevel.values()); this.idleLevel.setSelectedIndex(0); this.idleLevel.setRenderer(new UARTIdleLevelItemRenderer()); settings.add(this.idleLevel); settings.add(createRightAlignedLabel("Bit encoding")); this.bitEncoding = new JComboBox(BitEncoding.values()); this.bitEncoding.setSelectedIndex(0); this.bitEncoding.setRenderer(new UARTBitEncodingItemRenderer()); settings.add(this.bitEncoding); settings.add(createRightAlignedLabel("Bit order")); this.bitOrder = new JComboBox(BitOrder.values()); this.bitOrder.setSelectedIndex(0); this.bitOrder.setRenderer(new UARTBitOrderItemRenderer()); settings.add(this.bitOrder); SpringLayoutUtils.makeEditorGrid(settings, 10, 4); return settings; } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String getEmptyHtmlPage() { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString( new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro) || "detected-bus-errors".equals(aMacro) || "baudrate".equals(aMacro)) { return "-"; } else if ("decoded-data".equals(aMacro)) { return null; } return null; } }); } /** Initializes this dialog. */ private void initDialog() { setMinimumSize(new Dimension(640, 480)); final JComponent settingsPane = createSettingsPane(); final JComponent previewPane = createPreviewPane(); final JPanel contentPane = new JPanel(new GridBagLayout()); contentPane.add( settingsPane, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 0, 2, 0), 0, 0)); contentPane.add( previewPane, new GridBagConstraints( 1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(2, 0, 2, 0), 0, 0)); final JButton runAnalysisButton = ToolUtils.createRunAnalysisButton(this); this.runAnalysisAction = (RestorableAction) runAnalysisButton.getAction(); final JButton exportButton = ToolUtils.createExportButton(this); this.exportAction = exportButton.getAction(); this.exportAction.setEnabled(false); final JButton closeButton = ToolUtils.createCloseButton(); this.closeAction = closeButton.getAction(); final JComponent buttons = SwingComponentUtils.createButtonPane(runAnalysisButton, exportButton, closeButton); SwingComponentUtils.setupWindowContentPane(this, contentPane, buttons, runAnalysisButton); } /** * exports the data to a CSV file * * @param aFile File object */ private void storeToCsvFile(final File aFile, final UARTDataSet aDataSet) { try { final CsvExporter exporter = ExportUtils.createCsvExporter(aFile); exporter.setHeaders( "index", "start-time", "end-time", "event?", "event-type", "RxD event", "TxD event", "RxD data", "TxD data"); final List<UARTData> decodedData = aDataSet.getData(); for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); final String startTime = Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex())); final String endTime = Unit.Time.format(aDataSet.getTime(ds.getEndSampleIndex())); String eventType = null; String rxdEvent = null; String txdEvent = null; String rxdData = null; String txdData = null; switch (ds.getType()) { case UARTData.UART_TYPE_EVENT: eventType = ds.getEventName(); break; case UARTData.UART_TYPE_RXEVENT: rxdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_TXEVENT: txdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_RXDATA: rxdData = Integer.toString(ds.getData()); break; case UARTData.UART_TYPE_TXDATA: txdData = Integer.toString(ds.getData()); break; default: break; } exporter.addRow( Integer.valueOf(i), startTime, endTime, Boolean.valueOf(ds.isEvent()), eventType, rxdEvent, txdEvent, rxdData, txdData); } exporter.close(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "CSV export failed!", exception); } } } /** * stores the data to a HTML file * * @param aFile file object */ private void storeToHtmlFile(final File aFile, final UARTDataSet aDataSet) { try { toHtmlPage(aFile, aDataSet); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "HTML export failed!", exception); } } } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String toHtmlPage(final File aFile, final UARTDataSet aDataSet) throws IOException { final int bitCount = Integer.parseInt((String) this.bits.getSelectedItem()); final int bitAdder = ((bitCount % 4) != 0) ? 1 : 0; final MacroResolver macroResolver = new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro)) { return Integer.valueOf(aDataSet.getDecodedSymbols()); } else if ("detected-bus-errors".equals(aMacro)) { return Integer.valueOf(aDataSet.getDetectedErrors()); } else if ("baudrate".equals(aMacro)) { final String baudrate; if (aDataSet.getBaudRate() <= 0) { baudrate = "<span class='error'>Baudrate calculation failed!</span>"; } else { baudrate = String.format( "%d (exact: %d)", Integer.valueOf(aDataSet.getBaudRate()), Integer.valueOf(aDataSet.getBaudRateExact())); if (!aDataSet.isBitLengthUsable()) { return baudrate.concat( " <span class='warning'>The baudrate may be wrong, use a higher samplerate to avoid this!</span>"); } return baudrate; } } else if ("decoded-data".equals(aMacro)) { final List<UARTData> decodedData = aDataSet.getData(); Element tr; for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); if (ds.isEvent()) { String rxEventData = ""; String txEventData = ""; String bgColor; if (UARTData.UART_TYPE_EVENT == ds.getType()) { rxEventData = txEventData = ds.getEventName(); bgColor = "#e0e0e0"; } else if (UARTData.UART_TYPE_RXEVENT == ds.getType()) { rxEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else if (UARTData.UART_TYPE_TXEVENT == ds.getType()) { txEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else { // unknown event bgColor = "#ff8000"; } if (txEventData.endsWith("_ERR") || rxEventData.endsWith("_ERR")) { bgColor = "#ff8000"; } tr = aParent .addChild(TR) .addAttribute("style", "background-color: " + bgColor + ";"); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent(rxEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD).addContent(txEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); } else { String rxDataHex = "", rxDataBin = "", rxDataDec = "", rxDataASCII = ""; String txDataHex = "", txDataBin = "", txDataDec = "", txDataASCII = ""; // Normal data... if (UARTData.UART_TYPE_RXDATA == ds.getType()) { final int rxData = ds.getData(); rxDataHex = integerToHexString(rxData, (bitCount / 4) + bitAdder); rxDataBin = integerToBinString(rxData, bitCount); rxDataDec = String.valueOf(rxData); rxDataASCII = toASCII((char) rxData); } else /* if ( UARTData.UART_TYPE_TXDATA == ds.getType() ) */ { final int txData = ds.getData(); txDataHex = integerToHexString(txData, (bitCount / 4) + bitAdder); txDataBin = integerToBinString(txData, bitCount); txDataDec = String.valueOf(txData); txDataASCII = toASCII(txData); } tr = aParent.addChild(TR); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent("0x", rxDataHex); tr.addChild(TD).addContent("0b", rxDataBin); tr.addChild(TD).addContent(rxDataDec); tr.addChild(TD).addContent(rxDataASCII); tr.addChild(TD).addContent("0x", txDataHex); tr.addChild(TD).addContent("0b", txDataBin); tr.addChild(TD).addContent(txDataDec); tr.addChild(TD).addContent(txDataASCII); } } } return null; } }; if (aFile == null) { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString(macroResolver); } else { final HtmlFileExporter exporter = (HtmlFileExporter) createHtmlTemplate(ExportUtils.createHtmlExporter(aFile)); exporter.write(macroResolver); exporter.close(); } return null; } }
/** * A representation of the LogicSniffer device. * * @author J.W. Janssen */ public class LogicSnifferDevice implements Device { // CONSTANTS private static final String NAME = "OpenBench LogicSniffer"; private static final Logger LOG = Logger.getLogger(LogicSnifferDevice.class.getName()); // VARIABLES private LogicSnifferConfig config; private volatile DependencyManager dependencyManager; private volatile ManagedServiceFactory deviceProfileManagerServiceFactory; private volatile ConnectorService connectorService; private volatile StreamConnection connection; private volatile LogicSnifferConfigDialog configDialog; // METHODS public LogicSnifferConfig getConfig() { return config; } /** {@inheritDoc} */ @Override public void close() throws IOException { if (this.connection != null) { this.connection.close(); this.connection = null; } } /** {@inheritDoc} */ @Override public AcquisitionTask createAcquisitionTask(final AcquisitionProgressListener aProgressListener) throws IOException { return new LogicSnifferAcquisitionTask( this.config, getStreamConnection(), getDeviceProfileManager(), aProgressListener); } /** {@inheritDoc} */ @Override public CancelTask createCancelTask() throws IOException { if (this.config.isRleEnabled()) { return new LogicSnifferCancelTask(getStreamConnection()); } // Simply use the default behaviour... return null; } /** @see nl.lxtreme.ols.api.devices.Device#getName() */ public String getName() { return NAME; } /** @see nl.lxtreme.ols.api.devices.Device#isSetup() */ @Override public boolean isSetup() { return this.config != null; } /** * Displays the device controller dialog with enabled configuration portion and waits for user * input. * * @see nl.lxtreme.ols.api.devices.Device#setupCapture() */ @Override public boolean setupCapture(final Window aOwner) { // Just to be sure... disposeConfigDialog(); this.configDialog = new LogicSnifferConfigDialog(aOwner, this); try { boolean configConfirmed = this.configDialog.showDialog(); if (configConfirmed) { this.config = this.configDialog.getConfiguration(); } return configConfirmed; } finally { this.configDialog.dispose(); this.configDialog = null; } } /** * @param uri * @return * @throws IOException */ final StreamConnection createStreamConnection(final String uri) throws IOException { return (StreamConnection) this.connectorService.open(uri, ConnectorService.READ_WRITE, true /* timeouts */); } /** * Returns the default device profile. * * @return a default profile, never <code>null</code>. */ final DeviceProfile getDefaultProfile() { return getDeviceProfileManager().getDefaultProfile(); } /** * Returns the current device profile manager. * * @return a device profile manager, never <code>null</code>. */ final DeviceProfileManager getDeviceProfileManager() { return (DeviceProfileManager) this.deviceProfileManagerServiceFactory; } /** Called when this class is unregistered as OSGi service. */ protected void destroy(final Component aComponent) { disposeConfigDialog(); } /** * Called when this class is registered as OSGi service. * * @param aComponent the bundle context to use, cannot be <code>null</code>. */ protected void init(final Component aComponent) { final String pmFilter = String.format("(%s=%s)", Constants.SERVICE_PID, DeviceProfileManager.SERVICE_PID); aComponent // .add( this.dependencyManager .createServiceDependency() // .setService(ManagedServiceFactory.class, pmFilter) // .setAutoConfig("deviceProfileManagerServiceFactory") // .setInstanceBound(true) // .setRequired(true)) // .add( this.dependencyManager .createServiceDependency() // .setService(ConnectorService.class) // .setAutoConfig("connectorService") // .setInstanceBound(true) // .setRequired(true) // ); } /** * Disposes the current configuration dialog, if one is still visible on screen. If no * configuration dialog is visible, this method does nothing. */ private void disposeConfigDialog() { if (this.configDialog != null) { SwingComponentUtils.dispose(this.configDialog); this.configDialog = null; } } /** * Returns the current stream connection that is opened. * * @return a stream connection, can be a cached one, never <code>null</code>. * @throws IOException in case of I/O problems creating the stream connection. */ private StreamConnection getStreamConnection() throws IOException { if (this.connection == null) { final String uri = this.config.getConnectionURI(); if (LOG.isLoggable(Level.INFO)) { LOG.info("Connecting to " + uri); } this.connection = createStreamConnection(uri); } return this.connection; } }