Error Handling and Debugging Error handling and debugging
Обработка ошибок и отладка
Обработка ошибок и отладка

leJOS NXJ предоставляет несколько механизмов для обработки ошибок и отладки, включая:

  • Исключения (Exceptions)
  • Data Aborts
  • Отладку (Debugging)

Механизм удалённого мониторинга и пошаговой отладки (tracing facility), который описан ниже в отдельном разделе, может также использоваться для отладки.

Исключения (Exceptions)

Большинство стандартных классов исключений языка Java поддерживается leJOS и пользователь может также создавать свои собственные классы исключений.

Пример:

Следующий тестовый пример программы, демонстрирующий работу исключений, покажет, что может случиться, если исключение не перехвачено (в данном случае ArrayIndexOutOfBounds exception).

public class ExceptionTest {
    static void m1()
    {
        int test[] = new int[2];
        // Force an exception
        test[0] = test[1] + test[2]; // This is line 6
    }

    static void m2()
    {
        m1();
    }

    public static void main (String[] aArg) throws Exception
    {
        System.out.println("Running");
        m2();
    }
}

Когда этот код запускается "кирпич" NXT показывает экран необработанного исключения. Этот экран выглядит примерно так:

Exception: 28
  at:  20(11)
  at:  21(1)
  at:  22(9)

Но о чём эти числа нам говорят? Первая строка сообщает номер класса-исключения, который был выборошен, в данном случае класс 28. Следующие строки показывает миниатюрный дамп стека, по одной на каждый метод в стеке вызовов, показывается номер метода и положение program counter-а внутри метода. Самый верхний пункт - это место, где было выброшено исключение (в данном случае это произошло в месте (at location) 11 в методе номер 20.

Так что теперь мы понимаем что означают числа, но как соотнести их с нашей программой? Один из способов - использовать verbose output линкера, сокращённая версия которого выглядит примерно так:

Class 0: java.lang.Object
Class 1: java.lang.Throwable
Class 2: java.lang.Error
Class 3: java.lang.OutOfMemoryError
Class 4: boolean
Class 5: char
Class 6: float
Class 7: double
Class 8: byte
Class 9: short
Class 10: int
Class 11: long
Class 12: void
Class 13: java.lang.Object[]
Class 14: java.lang.NoSuchMethodError
Class 15: java.lang.StackOverflowError
Class 16: java.lang.NullPointerException
Class 17: boolean[]
Class 18: char[]
Class 19: float[]
Class 20: double[]
Class 21: byte[]
Class 22: short[]
Class 23: int[]
Class 24: long[]
Class 25: reserved
Class 26: java.lang.ClassCastException
Class 27: java.lang.ArithmeticException
Class 28: java.lang.ArrayIndexOutOfBoundsException
Class 29: java.lang.IllegalArgumentException
Class 30: java.lang.InterruptedException
Class 31: java.lang.IllegalStateException
Class 32: java.lang.IllegalMonitorStateException
Class 33: java.lang.ThreadDeath
.... other classes omitted
Method 0: java.lang.Object.<init>() PC 1976 Signature id 2
Method 1: java.lang.Object.getClass() PC 1977 Signature id 121
Method 2: java.lang.Object.toString() PC 1985 Signature id 123
Method 3: java.lang.Throwable.i<init>() PC 2013 Signature id 2
Method 4: java.lang.Throwable.<init>(java.lang.String) PC 2023 Signature id 124
Method 5: java.lang.Throwable.getLocalizedMessage() PC 2038 Signature id 125
Method 6: java.lang.Throwable.getMessage() PC 2043 Signature id 29
Method 7: java.lang.Throwable.toString() PC 2048 Signature id 123
Method 8: java.lang.Throwable.fillInStackTrace() PC 2096 Signature id 126
Method 9: java.lang.NullPointerException.<init>() PC 2109 Signature id 2
Method 10: java.lang.Class.isInterface() PC 2114 Signature id 133
Method 11: java.lang.Class.toString() PC 2131 Signature id 123
Method 12: java.lang.String.<init>(int) PC 2177 Signature id 128
Method 13: java.lang.String.<init>(char[], int, int) PC 2189 Signature id 141
Method 14: java.lang.String.charAt(int) PC 2206 Signature id 145
Method 15: java.lang.String.length() PC 2231 Signature id 155
Method 16: java.lang.String.toString() PC 2237 Signature id 123
Method 17: java.lang.String.valueOf(java.lang.Object) PC 2239 Signature id 167
Method 18: java.lang.Thread.run() PC 2253 Signature id 1
Method 19: java.lang.Thread.currentThread() Native id 12
Method 20: ExceptionTest.m1() PC 2273 Signature id 175
Method 21: ExceptionTest.m2() PC 2288 Signature id 176
Method 22: ExceptionTest.main(java.lang.String[]) PC 2292 Signature id 0
Method 23: lejos.nxt.VM.<clinit> PC 2304 Signature id 3
Method 24: lejos.nxt.VM.<init>() PC 2323 Signature id 2
Method 25: lejos.nxt.VM.getVM() PC 2358 Signature id 177
Method 26: lejos.nxt.VM.memPeek(int, int, int) Native id 103
.... другие методы опущены

Мы можем использовать таблицу классов чтоб найти в ней класс исключения - в нашем случае класс 28 это java.lang.ArrayIndexOutOfBoundsException так что мы теперь знаем, что столкнулись с ошибкой выхода за пределы массива. Теперь мы можем посмотреть имена методов. Метод 20 это метод ExceptionTest.m1, метод 21 это ExceptionTest.m2 и метод 22 это ExceptionTest.main. Это говорит нам о том, что исключение было выброшено в методе m1, который был вызван из метода m2, который, в свою очередь, был вызван из метода main. Это хорошо, но как мы используем значение location counter чтоб сузить диапазон поиска места, где возникло исключение? Мы можем декомпилировать байт-код классов и использовать это, но может есть способ полегче? Да есть. Вместе с leJOS идут два инструмента, которые сильно упрощают процесс отладки, один помогает декодировать упомянутые выше номера локаций, другой делает всю работу за нас. Оба инструмента требуют, чтоб вы использовали при линковке опцию -od, которая говорит линкеру, чтоб он добавлял дополнительную отладочную информацию в указанный файл. Имея этот файл, мы можем ипользовать NXJDebugTool чтоб декодировать данные от исключения как показано ниже:

C:\samples\ExceptionTest>nxjc ExceptionTest.java
C:\samples\ExceptionTest>nxjlink -o ExceptionTest.nxj -od ExceptionTest.nxd ExceptionTest
C:\samples\ExceptionTest>nxjdebugtool -di ExceptionTest.nxd -c -m 28 20 11

The class number 28 refers to:
  java.lang.ArrayIndexOutOfBoundsException (ArrayIndexOutOfBoundsException.java)

The method number 20 refers to:
  ExceptionTest.m1()V (ExceptionTest.java)

PC 11 refers to:
  line 6 in ExceptionTest.java

Как вы можете видеть, этот инструмент точно указывает на номер строки, где произошло исключение, в исходном коде.

И последняя возможность отладки это использовать leJOS remote console application (приложение удалённой консоли leJOS) (подробнее смотрите ниже). Опять же, нам нужны некоторые дополнительные опции линковки: в этот раз -od чтоб добавить информацию для отладки и -gr чтоб добавить дополнительный отладочный код для работы с удалённой консолью. Если мы слинкуем с этими опциями и запустим программу снова, то мы заметим три изменения: во-первых, программа будет ожидать remote console application чтоб соединиться с ней, во-вторых, любой вывод, который использует поток System.out будет перенаправлен на отладочную консоль (в данном случае будет выведено слово "Running") и, наконец, информация об исключении будет отображена на удалённой консоли в удобной для восприятия форме. Смотрите ниже пример:

C:\samples\ExceptionTest>nxjc ExceptionTest.java
C:\samples\ExceptionTest>nxjlink -gr -o ExceptionTest.nxj -od ExceptionTest.nxd ExceptionTest
C:\samples\ExceptionTest>nxjupload -r ExceptionTest.nxj
Found NXT: nxt2 001653015066
leJOS NXJ> Connected to nxt2
leJOS NXJ> Upload successful in 2904 milliseconds
C:\samples\ExceptionTest>nxjconsole -di ExceptionTest.nxd
Debug attached
Found NXT: nxt2 001653015066
leJOS NXJ> Connected to nxt2
Connected to nxt2 001653015066
Console open
Running
Exception: java.lang.ArrayIndexOutOfBoundsException
 at: ExceptionTest.m1(ExceptionTest.java:6)
 at: ExceptionTest.m2(ExceptionTest.java:12)
 at: ExceptionTest.main(ExceptionTest.java:18)
Console closed

Data Aborts

Если происходит сбой в работе прошивки leJOS - вы, наверняка, захотите получить Data Abort (здесь тоже не до конца уловил тонкости грамматики, в оригинале предложение выглядело так: "If the leJOS firmware crashes you will normally a Data Abort.") На экране будут показано значение регистра PC на котором произошёл сбой и другая информация о сбое.

На экране будет приблизительно следующее:

DATA ABORT

PC 00140BAC

AASR 1831BF01

ASR 00020601

OPCODE ???

DEBUG1 00020010

DEBUG2 00000000

Наиболее распространённая причина data abort-a это исполнение файла, который не является бинарным файлом leJOS NXJ, или исполнение "битого"(incomplete) исполняемого файла leJOS NXJ.

Если у вас произошёл data abort в каком-либо другом случае, необходимо сообщить об ошибке команде разработчиков leJOS путём размещения детального описания вашей ситуации на форуме leJOS NXJ.

Наверх страницы

Удалённая отладка

Вы можете использовать PC как удалённую консоль для отображения отладочных (трассировочных) сообщений, сгенерированных программой, работающей на стороне робота. У класса lejos.nxt.comm.RConsole есть методы для этого. Т.к. экземпляров этого класса не создаётся, то все методы статические.

Чтоб начать отладку, используйте один из этих методов:

  • void open()

    открывает соединение через USB без таймаута

  • void openUSB(int timeout)

  • void openBluetooth(int timeout)

На дисплее робота высвечивается USB Console.. или BT Console.

и начинается ожидание, когда программа-монитор на стороне PC соединится.

затем запускается программа nxjconsole на PC. Когда соединение установится, дисплей робота ("кирпича"-NXT) высветит Got Connection и, через несколько секунд, и NXT и PC отобразят Console open.

Если вы используете вариант открытия с таймаутом, то происходит ожидание указанного количества секунд и, если отладочный монитор не подключен, программа робота продолжает работу без возможности отладки/трассировки. Если таймаут задан равным нулю, то время ожидания - бесконечное.

Можно также использовать приложение ConsoleViewer чтоб отображать трассировочные/отладочные сообщения.

Отладочные сообщения могут быть выведены с помощью следующих методов:

  • void println(String s)

  • void print(String s);

Если вызов open завершился неудачей (соединение не было установлено), отладочные сообщения будут отброшены. Если соединение было установлено успешно, строка появится на потоке стандартного вывода в окне или терминале с которого была запущена на PC nxjconsole .

Когда отладка завершается, вы должны вызвать на стороне робота:

  • void close()

Это приведёт к закрытию USB или Bluetooth соединения.

Пример:

import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.comm.RConsole;

/**
 * example using RConsole
 */
public class TestRConsole {  
  public static void main(String[] args) {
    RConsole.open();
    RConsole.println("Start for loop ");
    for (int i = 0; i < 5; i++) {
      RConsole.print(" " + i);
      LCD.drawInt(i, 2, 2 * i, 4);
    }
    RConsole.println("\n done ");
    RConsole.close();
    Button.waitForAnyPress();
  }
}

Наверх страницы

Hosted by uCoz