Arduino IDEで例外処理（Try-Catchなど：ほとんど失敗）

# Arduino IDEで例外処理
Arduino IDEで例外処理（Try-Catchなど）を「トライ」したときの記録。ただし、期待どおり動作せず。

## まずは情報から
### Arduinoボード向けコンパイルオプション
”try-catch”が含まれるコードをBuildしようとすると、コンパイルオプション”-fexceptions”を使え、、というエラーメッセージが表示される。platform.txt（どこか深いところにある）にある”-fno-exceptions”を削除し、”-fexceptions”を記載することが必要。下記リンクは参考情報。
- [Exception Handling with the Arduino IDE](https://arduino.stackexchange.com/questions/65392/exception-handling-with-the-arduino-ide)

なお、ESP32ボード向け（今回はM5Stack利用）では、このコンパイルオプション追加は不要であった。

### 単純なコードだが
下記コードは単純なコードだが、Arduino UnoではBuildできず。どうも、tryやcatch内に”Serial.println()”があるためのようだ。
```c++
// ESP32:OK   Arduino Uno:NG

void setup() {
  Serial.begin(9600);
}

void loop() {
  try {
    Serial.println("1");
  } catch (...) {
    Serial.println("2");
  }
}
```
もしかしたら、これもコンパイルオプションで回避できるのかもしれない（見つからず、、ではあったが）。ただし、ESP32ボード向けでは、上記コードはBuildできる。

### 深堀り（調査）
調べると次のサイトに、
- [How to enable exception handling on the Arduino Due?](https://arduino.stackexchange.com/questions/80634/how-to-enable-exception-handling-on-the-arduino-due)

"Since there are no standard exception classes defined (and the ArduinoSTL library doesn't compile on the due out-of-the-box), you'll have to write your own exception classes, i.e something like this:"
という記述が見つかる。自分で例外クラスを定義する必要があるのかもしれない、、。

## サンプルコード
上記サイトをほぼそのまま利用し、次のコードを作成（ESP32ボード向け）。

```c++
class Exception
{
  private:
  const char* _msg;
  public:
  Exception(const char* msg)
  {
    _msg = msg;
  }

  const char* Message() const
  {
    return _msg;
  }
};

void ThrowExceptionFunc(int n)
{
  if (n > 1) {
    throw Exception("Something bad happened");
  }
}

void ValidateExceptionHandling(int val)
{
  Serial.print("val = "); Serial.println(val);
  try
  {
    ThrowExceptionFunc(10/val);
    Serial.println("Exception was not thrown:");
  }
  catch(Exception& ex)
  {
    Serial.print("Exception happened:");
    Serial.println(ex.Message());
  }
  catch (...) {
    Serial.println("Other exceptions");
  }
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  while (Serial.available()) {
    String data = Serial.readStringUntil('\n');
    int num = data.toInt();
    ValidateExceptionHandling(num);
  }
}
```
概要は下記のとおり。
- PC（シリアル）から入力された数値（エラー処理は未考慮）を、例外処理関数（ValidateExceptionHandling()）に渡して処理
- その処理関数内で、入力数値（val）により、定義した例外クラスを呼び出し
    - ”10/val”の値が１以上でThrow（ThrowExceptionFunc()にて）
- Throwを受け取る処理（catch(Exception& ex)）を定義
- すべての例外を受け取る処理（catch(...)）を定義

### 結果
```
val = 2
Exception happened:Something bad happened
val = 14
Exception was not thrown:
val = 0
Guru Meditation Error: Core  1 panic'ed (IntegerDivideByZero). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d0c5c  PS      : 0x00060b30  A0      : 0x800d0d3e  A1      : 0x3ffb1f60  
A2      : 0x00000000  A3      : 0x3ffbfe88  A4      : 0x3ffbfe88  A5      : 0x3ffb1f80  
A6      : 0x00000003  A7      : 0x00000000  A8      : 0x800d0c5a  A9      : 0x3ffb1f40  
A10     : 0x0000000a  A11     : 0x00000001  A12     : 0x0000000a  A13     : 0x3ffb84ac  
A14     : 0x00ff0000  A15     : 0x3ffb1e70  SAR     : 0x0000000a  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

ELF file SHA256: 0000000000000000

Backtrace: 0x400d0c5c:0x3ffb1f60 0x400d0d3b:0x3ffb1f80 0x400d1f29:0x3ffb1fb0 0x400860ed:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
```
”val = 2”がThrowされるケース、”val = 14”がThrowされないケースとなる。”val = 0”にて、0で割るが発生し、すべての例外を受け取る処理（catch(...)）が動作することを期待したが、そのとおりにならず、リセットしてしまった。

少々調べると、ESP32向けでは、”stdexcept”というファイルに、例外クラスが定義されていることがわかった。
- logic_error
- domain_error
- invalid_argument
- length_error
- out_of_range
- runtime_error
- range_error
- overflow_error
- underflow_error

これらを、catch()に記載してもうまくいかず。また、他のロジック（アルゴリズム）により、上記に類似した例外を発生させようとしたが、うまくいかず。

## 終わりに
結局、期待どおりとならず。忘れた頃にリトライするかもしれない。