From cc35325eb7c6915d313db5fd1453d7db0a403d73 Mon Sep 17 00:00:00 2001 From: rusefi Date: Fri, 7 Aug 2020 15:01:25 -0400 Subject: [PATCH] TS SD integration #1653 --- firmware/hw_layer/mmc_card_access.cpp | 22 +- .../com/rusefi/ts_plugin/ConnectPanel.java | 186 +++------------ .../com/rusefi/ts_plugin/SdCardReader.java | 217 +++++++++++++++++- 3 files changed, 268 insertions(+), 157 deletions(-) diff --git a/firmware/hw_layer/mmc_card_access.cpp b/firmware/hw_layer/mmc_card_access.cpp index 1eb39b6056..7f6b934a3a 100644 --- a/firmware/hw_layer/mmc_card_access.cpp +++ b/firmware/hw_layer/mmc_card_access.cpp @@ -43,6 +43,11 @@ bool isLogFile(const char *fileName) { #if EFI_FILE_LOGGING || EFI_SIMULATOR #include "mmc_card.h" + +#if EFI_SIMULATOR +static FILE *uploading; +#endif // EFI_SIMULATOR + extern LoggingWithStorage sharedLogger; #define TRANSFER_SIZE 2048 @@ -142,14 +147,20 @@ void handleTsR(ts_channel_s *tsChannel, char *input) { closedir(dr); #endif // EFI_SIMULATOR - sr5SendResponse(tsChannel, TS_CRC, buffer, 0x202); + sr5SendResponse(tsChannel, TS_CRC, buffer, DIR_RESPONSE_BUFFER_SIZE); } } else if (input[0] == 0 && input[1] == TS_SD_PROTOCOL_FETCH_DATA) { - int blockNumber = data16[1]; + uint16_t blockNumber = SWAP_UINT16(data16[1]); scheduleMsg(&sharedLogger, "TS_SD: fetch data command blockNumber=%d", blockNumber); int offset = blockNumber * TRANSFER_SIZE; + buffer[0] = input[2]; + buffer[1] = input[3]; + + int got = fread(&buffer[2], 1, TRANSFER_SIZE, uploading); + sr5SendResponse(tsChannel, TS_CRC, buffer, 2 + got); + } else { scheduleMsg(&sharedLogger, "TS_SD: unexpected r"); } @@ -219,15 +230,20 @@ void handleTsW(ts_channel_s *tsChannel, char *input) { int dotIndex = indexOf(fileName, DOT); if (0 == strncmp(input + 6, &fileName[dotIndex - 4], 4)) { printf("Will be uploading %s\n", fileName); + uploading = fopen(fileName, "rb"); + if (uploading == NULL) { + printf("Error opening %s\n", fileName); + exit(1); + } break; } } } closedir(dr); #endif // EFI_SIMULATOR + sendOkResponse(tsChannel, TS_CRC); } - } else { scheduleMsg(&sharedLogger, "TS_SD: unexpected w"); } diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java index 1de28de072..382741286a 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java @@ -1,160 +1,68 @@ package com.rusefi.ts_plugin; -import com.rusefi.autoupdate.AutoupdateUtil; -import com.rusefi.config.generated.Fields; import com.rusefi.io.ConnectionStateListener; -import com.rusefi.io.IoStream; import com.rusefi.io.LinkManager; -import org.putgemin.VerticalFlowLayout; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import static com.rusefi.config.generated.Fields.TS_SD_PROTOCOL_FETCH_INFO; +/** + * todo: move IO away from AWT thread + */ public class ConnectPanel { private final JPanel content = new JPanel(new BorderLayout()); - private final JPanel fileList = new JPanel(new VerticalFlowLayout()); private final JLabel status = new JLabel(); private LinkManager controllerConnector; - public ConnectPanel() { + public ConnectPanel(final ConnectionStateListener connectionStateListener) { JPanel flow = new JPanel(new FlowLayout()); - JButton connect = new JButton("Connect"); - connect.addActionListener(new ActionListener() { + JButton disconnect = new JButton("Disconnect"); + + disconnect.setEnabled(false); + disconnect.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - connect.setEnabled(false); - - controllerConnector = new LinkManager() - .setCompositeLogicEnabled(false) - .setNeedPullData(false); - - //controllerConnector.startAndConnect(":2390", ConnectionStateListener.VOID); - controllerConnector.startAndConnect(":29001", new ConnectionStateListener() { - public void onConnectionEstablished() { - status.setText("Connected to rusEFI"); - requestFileList(); - } - - public void onConnectionFailed() { - } - }); - + controllerConnector.close(); + status.setText("Disconnected"); + disconnect.setEnabled(false); + connect.setEnabled(true); } }); - JButton poke = new JButton("poke"); - poke.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - requestFileList(); - } + connect.addActionListener(e -> { + connect.setEnabled(false); + + controllerConnector = new LinkManager() + .setCompositeLogicEnabled(false) + .setNeedPullData(false); + + //controllerConnector.startAndConnect(":2390", ConnectionStateListener.VOID); + controllerConnector.startAndConnect(":29001", new ConnectionStateListener() { + public void onConnectionEstablished() { + status.setText("Connected to rusEFI"); + disconnect.setEnabled(true); + connectionStateListener.onConnectionEstablished(); + } + + + public void onConnectionFailed() { + } + }); }); flow.add(connect); - flow.add(poke); + flow.add(disconnect); content.add(flow, BorderLayout.NORTH); - content.add(fileList, BorderLayout.CENTER); content.add(status, BorderLayout.SOUTH); } - private void requestFileList() { - try { - byte[] packet; - byte[] response; - IoStream stream = controllerConnector.getConnector().getBinaryProtocol().getStream(); - - packet = new byte[3]; - packet[0] = Fields.TS_SD_R_COMMAND; - packet[2] = Fields.TS_SD_PROTOCOL_RTC; - stream.sendPacket(packet); - response = stream.getDataBuffer().getPacket("RTC status"); - System.out.println("RTC response " + IoStream.printHexBinary(response)); - if (response == null) - throw new IOException("RTC No packet"); - - packet = new byte[17]; - packet[0] = Fields.TS_SD_W_COMMAND; - packet[2] = TS_SD_PROTOCOL_FETCH_INFO; - packet[6] = Fields.TS_SD_PROTOCOL_READ_DIR; - stream.sendPacket(packet); - response = stream.getDataBuffer().getPacket("read dir command"); - if (response == null) - throw new IOException("Read Dir No packet"); - System.out.println("read dir command " + IoStream.printHexBinary(response)); - - packet = new byte[8]; - packet[0] = Fields.TS_SD_R_COMMAND; - packet[1] = 0; - packet[2] = TS_SD_PROTOCOL_FETCH_INFO; - packet[5] = 0x02; - packet[6] = 0x02; - stream.sendPacket(packet); - response = stream.getDataBuffer().getPacket("read command", true); - if (response == null) - throw new IOException("No packet"); - System.out.println("read command " + IoStream.printHexBinary(response)); - - fileList.removeAll(); - - for (int fileIndex = 0; fileIndex < 512 / 32; fileIndex++) { - int offset = 32 * fileIndex; - String fileNamePart = new String(response, 1 + offset, 8).trim(); - if (fileNamePart.trim().isEmpty()) - break; - String fileExt = new String(response, 1 + offset + 8, 3).trim(); - String fileName = fileNamePart + "." + fileExt; - - ByteBuffer bb = ByteBuffer.wrap(response, 1 + offset + 28, 4); - bb.order(ByteOrder.LITTLE_ENDIAN); - int size = bb.getInt(); - - JPanel filePanel = new JPanel(new FlowLayout()); - - filePanel.add(new JLabel(fileName + " " + size + " byte(s)")); - - JButton download = new JButton("Download"); - download.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - downloadFile(fileName); - - - } - }); - - filePanel.add(download); - JButton delete = new JButton("Delete"); - delete.addActionListener(e1 -> { - int result = JOptionPane.showConfirmDialog(null, "Are you sure you want to remove " + fileName, - "rusEfi", JOptionPane.YES_NO_OPTION); - if (result == JOptionPane.YES_OPTION) { - deleteFile(fileName); - requestFileList(); - } - }); - filePanel.add(delete); - - fileList.add(filePanel); - - System.out.println("Filename " + fileName + " size " + size); - - AutoupdateUtil.trueLayout(content.getParent()); - } - - } catch (IOException ioException) { - ioException.printStackTrace(); - } + public LinkManager getControllerConnector() { + return controllerConnector; } public static String getLastFour(String fileName) { @@ -165,32 +73,6 @@ public class ConnectPanel { return fileName.substring(fileName.length() - 4); } - private void downloadFile(String fileName) { - fileName = ConnectPanel.getLastFour(fileName); - - } - - private void deleteFile(String fileName) { - fileName = ConnectPanel.getLastFour(fileName); - - byte[] packet = new byte[17]; - packet[0] = Fields.TS_SD_W_COMMAND; - packet[2] = TS_SD_PROTOCOL_FETCH_INFO; - packet[6] = Fields.TS_SD_PROTOCOL_REMOVE_FILE; - for (int i = 0; i < 4; i++) - packet[7 + i] = (byte) fileName.charAt(i); - - IoStream stream = controllerConnector.getConnector().getBinaryProtocol().getStream(); - - try { - stream.sendPacket(packet); - byte[] response = stream.getDataBuffer().getPacket("delete file"); - System.out.println("delete file " + IoStream.printHexBinary(response)); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - public JComponent getContent() { return content; } diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java index cbe05440a8..ea95e60b4c 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java @@ -1,16 +1,229 @@ package com.rusefi.ts_plugin; +import com.rusefi.autoupdate.AutoupdateUtil; +import com.rusefi.config.generated.Fields; +import com.rusefi.io.ConnectionStateListener; +import com.rusefi.io.IoStream; +import org.putgemin.VerticalFlowLayout; + import javax.swing.*; import java.awt.*; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import static com.rusefi.config.generated.Fields.TS_SD_PROTOCOL_FETCH_INFO; +import static com.rusefi.shared.FileUtil.close; public class SdCardReader { - private final JPanel content = new JPanel(); + private final static int TRANSFER_HEADER_SIZE = 3; + private final JPanel content = new JPanel(new BorderLayout()); + + private final JPanel fileList = new JPanel(new VerticalFlowLayout()); + private final JLabel status = new JLabel(); + + private final ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() { + public void onConnectionEstablished() { + requestFileList(); + } + + public void onConnectionFailed() { + } + }); public SdCardReader() { - content.add(new ConnectPanel().getContent()); + JButton refresh = new JButton("Refresh"); + refresh.addActionListener(e -> requestFileList()); + + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.add(connectPanel.getContent(), BorderLayout.NORTH); + topPanel.add(status, BorderLayout.CENTER); + + content.add(topPanel, BorderLayout.NORTH); + content.add(fileList, BorderLayout.CENTER); + content.add(refresh, BorderLayout.SOUTH); } public Component getContent() { return content; } + + private void requestFileList() { + int fileCount = 0; + + try { + byte[] packet; + byte[] response; + IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream(); + + packet = new byte[3]; + packet[0] = Fields.TS_SD_R_COMMAND; + packet[2] = Fields.TS_SD_PROTOCOL_RTC; + stream.sendPacket(packet); + response = stream.getDataBuffer().getPacket("RTC status"); + System.out.println("RTC response " + IoStream.printHexBinary(response)); + if (response == null) + throw new IOException("RTC No packet"); + + packet = new byte[17]; + packet[0] = Fields.TS_SD_W_COMMAND; + packet[2] = TS_SD_PROTOCOL_FETCH_INFO; + packet[6] = Fields.TS_SD_PROTOCOL_READ_DIR; + stream.sendPacket(packet); + response = stream.getDataBuffer().getPacket("read dir command"); + if (response == null) + throw new IOException("Read Dir No packet"); + System.out.println("read dir command " + IoStream.printHexBinary(response)); + + packet = new byte[8]; + packet[0] = Fields.TS_SD_R_COMMAND; + packet[1] = 0; + packet[2] = TS_SD_PROTOCOL_FETCH_INFO; + packet[5] = 0x02; + packet[6] = 0x02; + stream.sendPacket(packet); + response = stream.getDataBuffer().getPacket("read command", true); + if (response == null) + throw new IOException("No packet"); + System.out.println("read command " + IoStream.printHexBinary(response)); + + fileList.removeAll(); + + for (int fileIndex = 0; fileIndex < 512 / 32; fileIndex++) { + int offset = 32 * fileIndex; + String fileNamePart = new String(response, 1 + offset, 8).trim(); + if (fileNamePart.trim().isEmpty()) + break; + fileCount++; + String fileExt = new String(response, 1 + offset + 8, 3).trim(); + String fileName = fileNamePart + "." + fileExt; + + ByteBuffer bb = ByteBuffer.wrap(response, 1 + offset + 28, 4); + bb.order(ByteOrder.LITTLE_ENDIAN); + int size = bb.getInt(); + + JPanel filePanel = new JPanel(new FlowLayout()); + + filePanel.add(new JLabel(fileName + " " + size + " byte(s)")); + + JButton download = new JButton("Download"); + download.addActionListener(e -> downloadFile(fileName)); + + filePanel.add(download); + JButton delete = new JButton("Delete"); + delete.addActionListener(e1 -> { + int result = JOptionPane.showConfirmDialog(null, "Are you sure you want to remove " + fileName, + "rusEfi", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + deleteFile(fileName); + status.setText("Deleted " + fileName); + requestFileList(); + } + }); + filePanel.add(delete); + + fileList.add(filePanel); + + System.out.println("Filename " + fileName + " size " + size); + + AutoupdateUtil.trueLayout(content.getParent()); + } + + } catch (IOException ioException) { + ioException.printStackTrace(); + } + + if (fileCount == 0) { + status.setText("No files found."); + } + } + + private void downloadFile(String fileName) { + String lastFour = ConnectPanel.getLastFour(fileName); + + byte[] packet = new byte[17]; + packet[0] = Fields.TS_SD_W_COMMAND; + packet[2] = TS_SD_PROTOCOL_FETCH_INFO; + packet[6] = Fields.TS_SD_PROTOCOL_FETCH_COMPRESSED; + applyLastFour(lastFour, packet); + + IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream(); + + FileOutputStream fos = null; + try { + stream.sendPacket(packet); + byte[] response = stream.getDataBuffer().getPacket("Download file"); + System.out.println("Download file " + IoStream.printHexBinary(response)); + + status.setText("Downloading " + fileName); + + + fos = new FileOutputStream("downloaded_" + fileName, false); + + int chunk = 0; + + int totalSize = 0; + + while (true) { + packet = new byte[17]; + packet[0] = Fields.TS_SD_R_COMMAND; + packet[2] = Fields.TS_SD_PROTOCOL_FETCH_DATA; + packet[3] = (byte) chunk; + packet[4] = (byte) (chunk >> 8); + + stream.sendPacket(packet); + response = stream.getDataBuffer().getPacket("Get file", true); + + if (response == null) { + System.out.println("No content response"); + break; + } + + System.out.println("Got content package size " + response.length); + + + int dataBytes = response.length - TRANSFER_HEADER_SIZE; + fos.write(response, TRANSFER_HEADER_SIZE, dataBytes); + + totalSize += dataBytes; + + if (dataBytes != 2048) { + System.out.println(response.length + " must be the last packet"); + status.setText(fileName + " downloaded " + totalSize + " byte(s)"); + break; + } + chunk++; + } + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + close(fos); + } + } + + private void deleteFile(String fileName) { + String lastFour = ConnectPanel.getLastFour(fileName); + + byte[] packet = new byte[17]; + packet[0] = Fields.TS_SD_W_COMMAND; + packet[2] = TS_SD_PROTOCOL_FETCH_INFO; + packet[6] = Fields.TS_SD_PROTOCOL_REMOVE_FILE; + applyLastFour(lastFour, packet); + + IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream(); + + try { + stream.sendPacket(packet); + byte[] response = stream.getDataBuffer().getPacket("delete file"); + System.out.println("Delete file " + IoStream.printHexBinary(response)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private void applyLastFour(String lastFour, byte[] packet) { + for (int i = 0; i < 4; i++) + packet[7 + i] = (byte) lastFour.charAt(i); + } }