package mars.tools; import mars.*; import mars.mips.hardware.*; import mars.venus.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; /** * Simple Demo of Mars tool capability */ public class MarsBot implements Observer, MarsTool { private static final int GRAPHIC_WIDTH = 512; private static final int GRAPHIC_HEIGHT = 512; private static final int ADDR_HEADING = 0xffff8010; private static final int ADDR_LEAVETRACK = 0xffff8020; private static final int ADDR_WHEREAREWEX = 0xffff8030; private static final int ADDR_WHEREAREWEY = 0xffff8040; private static final int ADDR_MOVE = 0xffff8050; private MarsBotDisplay graphicArea; private int MarsBotHeading = 0; // 0 --> North (up), 90 --> East (right), etc. private boolean MarsBotLeaveTrack = false; // true --> leave track when moving, false --> do not ... private double MarsBotXPosition = 0; // X pixel position of MarsBot private double MarsBotYPosition = 0; // Y pixel position of MarsBot private boolean MarsBotMoving = false; // true --> MarsBot is moving, false --> MarsBot not moving // The begin and end points of a "track" segment are kept in neighboring pairs // of elements of the array. arrayOfTrack[i] is the start pt, arrayOfTrack[i+1] is // the end point of a path that should leave a track. private final int trackPts = 256; // TBD Hardcoded. Array contains start-end points for segments in track. private Point[] arrayOfTrack = new Point[trackPts]; private int trackIndex = 0; // private inner class private class BotRunnable implements Runnable { JPanel panel; public BotRunnable() // constructor { final JFrame frame = new JFrame("Bot"); panel = new JPanel(new BorderLayout()); graphicArea = new MarsBotDisplay(GRAPHIC_WIDTH, GRAPHIC_HEIGHT); JPanel buttonPanel = new JPanel(); JButton clearButton = new JButton("Clear"); clearButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { graphicArea.clear(); MarsBotLeaveTrack = false; // true --> leave track when moving, false --> do not ... MarsBotXPosition = 0; // X pixel position of MarsBot MarsBotYPosition = 0; // Y pixel position of MarsBot MarsBotMoving = false; // true --> MarsBot is moving, false --> MarsBot not moving trackIndex = 0; } }); buttonPanel.add(clearButton); JButton closeButton = new JButton("Close"); closeButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setVisible(false); } }); buttonPanel.add(closeButton); panel.add(graphicArea, BorderLayout.CENTER); panel.add(buttonPanel, BorderLayout.SOUTH); frame.getContentPane().add(panel); frame.pack(); frame.setVisible(true); frame.setTitle(" This is the MarsBot"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // changed 12/12/09 DPS (was EXIT) frame.setSize(GRAPHIC_WIDTH + 200, GRAPHIC_HEIGHT + 100); // TBD SIZE frame.setVisible(true); // show(); } // end BotRunnable() constructor public void run() { double tempAngle; // infinite loop: move the bot according to the current directives // (which may be to NOT move) do { if (MarsBotMoving) { //System.out.println("BotRunnable.run: bot IS moving."); // TBD This is an arbitrary distance for bot movement. This could just // as easily be a random distance to simulate terrain, etc. // adjust bot position. // The "mathematical angle" is zero at east, 90 at north, etc. // The "heading" is 0 at north, 90 at east, etc. // Conversion: MathAngle = [(360 - heading) + 90] mod 360 tempAngle = ((360 - MarsBotHeading) + 90) % 360; MarsBotXPosition += Math.cos(Math.toRadians(tempAngle)); // Math.cos parameter unit is radians MarsBotYPosition += -Math.sin(Math.toRadians(tempAngle)); // Negate value because Y coord grows down // Write this new information to MARS memory area try { Globals.memory.setWord(ADDR_WHEREAREWEX, (int) MarsBotXPosition); Globals.memory.setWord(ADDR_WHEREAREWEY, (int) MarsBotYPosition); } catch ( AddressErrorException e) { // TBD TBD TBD No action } //System.out.println(" ------- Heading is " + MarsBotHeading + ", angle is " + tempAngle); //System.out.println(" ------- New X,Y is (" + MarsBotXPosition + "," + MarsBotYPosition + ")" ); // Whether or not we're leaving a track, write the current point to the // current position in the array. // -- If we are not leaving a track now, we will need the current point to // start a future track, and that goes into the array. // -- If we are leaving a track now, the current point may end the track, // and that goes into the array. arrayOfTrack[trackIndex] = new Point((int)MarsBotXPosition, (int)MarsBotYPosition); } else { // Action for if the MarsBot isn't moving // System.out.println("BotRunnable.run: bot is not moving."); } // TBD Pause whether the bot is or is not moving. This gives the MIPS program // opportunity to consider results of movement, or to make the bot move. // ??? What is relationship of robot speed to MARS's // execution time for a single instruction? Does the robot speed have to // be slow enough to allow a MARS busy loop to detect the bot position // at a specific pixel? try { //System.out.println(" Hello from the bot runner"); Thread.sleep(40); } catch (InterruptedException exception) {// no action } panel.repaint(); // show new bot position } while (true); } // end run method of BotRunnable class } // end BotRunnable class /* ------------------------------------------------------------------------- */ private class MarsBotDisplay extends JPanel { private int width; private int height; private boolean clearTheDisplay = true; public MarsBotDisplay(int tw, int th) { width = tw; height = th; } public void redraw() { repaint(); } public void clear() { // clear the graphic display clearTheDisplay = true; //System.out.println("MarsBotDisplay.clear: called to clear the display"); repaint(); } public void paintComponent(Graphics g) { long tempN; // System.out.println("MarsBotDisplay.paintComponent: I'm painting! n is " + n); // Recover Graphics2D Graphics2D g2 = (Graphics2D) g; /* if (clearTheDisplay) { g2.setColor(Color.lightGray); g2.fillRect(0, 0, width - 1, height - 1); // Clear all previous drawn information clearTheDisplay = false; } */ // Draw the track left behind, for each segment of the path g2.setColor(Color.blue); for (int i = 1; i <= trackIndex; i += 2) // Index grows by two (begin-end pair) { //System.out.print("."); try { g2.drawLine((int)arrayOfTrack[i-1].getX(), (int)arrayOfTrack[i-1].getY(), (int)arrayOfTrack[i].getX(), (int)arrayOfTrack[i].getY() ); } catch (ArrayIndexOutOfBoundsException e) { // No action TBD sloppy } catch (NullPointerException e) { // No action TBD sloppy } } g2.setColor(Color.black); g2.fillRect((int) MarsBotXPosition, (int) MarsBotYPosition, 20, 20); // Draw bot at its current position /* g2.setColor(Color.blue); g2.setFont(new Font(g2.getFont().getName(), g2.getFont().getStyle(), 20) ); // same font and style in larger size g2.drawOval( width/2 - 30, // TBD Hardcoded oval size height/2 - 30, 60, 60); g2.drawString(" " + n, width/2, height/2); */ } } // end private inner class MarsBotDisplay /* ------------------------------------------------------------------------- */ public String getName() { return "Mars Bot"; } /* * This will set up the Bot's GUI. Invoked when Bot menu item selected. */ public void action() { BotRunnable br1 = new BotRunnable(); Thread t1 = new Thread(br1); t1.start(); // New: DPS 27 Feb 2006. Register observer for memory subrange. try { Globals.memory.addObserver(this,0xffff8000,0xffff8060); } catch (AddressErrorException aee) { System.out.println(aee); } } /* * This method observes MIPS program directives to modify Bot activity (that is, * MIPS program write to MMIO) and updates instance variables to reflect that * directive. */ public void update(Observable o, Object arg) { MemoryAccessNotice notice; int address; if (arg instanceof MemoryAccessNotice) { notice = (MemoryAccessNotice) arg; address = notice.getAddress(); if (address < 0 && notice.getAccessType() == AccessNotice.WRITE) { String message = ""; if (address == ADDR_HEADING) { message = "MarsBot.update: got move heading value: "; MarsBotHeading = notice.getValue(); //System.out.println(message + notice.getValue() ); } else if (address == ADDR_LEAVETRACK) { message = "MarsBot.update: got leave track directive value "; // If we HAD NOT been leaving a track, but we should NOW leave // a track, put start point into array. if (MarsBotLeaveTrack == false && notice.getValue() == 1) { MarsBotLeaveTrack = true; arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition); trackIndex++; // the index of the end point } // If we HAD NOT been leaving a track, and get another directive // to NOT leave a track, do nothing (nothing to do). else if (MarsBotLeaveTrack == false && notice.getValue() == 0) { // NO ACTION } // If we HAD been leaving a track, and get another directive // to LEAVE a track, do nothing (nothing to do). else if (MarsBotLeaveTrack == true && notice.getValue() == 1) { // NO ACTION } // If we HAD been leaving a track, and get another directive // to NOT leave a track, put end point into array. else if (MarsBotLeaveTrack == true && notice.getValue() == 0) { MarsBotLeaveTrack = false; arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition); trackIndex++; // the index of the next start point } //System.out.println("MarsBotDisplay.paintComponent: putting point in track array at " + trackIndex); //System.out.println(message + notice.getValue() ); } else if (address == ADDR_MOVE) { message = "MarsBot.update: got move control value: "; if (notice.getValue() == 0) MarsBotMoving = false; else MarsBotMoving = true; //System.out.println(message + notice.getValue() ); } else if (address == ADDR_WHEREAREWEX || address == ADDR_WHEREAREWEY) { // Ignore these memory writes, because the writes originated within // this tool. This tool is being notified of the writes in the usual // manner, but the writes are already known to this tool. // NO ACTION } else { //message = "MarsBot.update: HEY!!! unknown address of " + Integer.toString(address) + ", value: "; //System.out.println(message + notice.getValue() ); } } } } }