今天我們來看的主角是 firmata class 中的 processInput , 從第二天看的 digital firmata sample 我們可以知道,所有arduino收到host端的輸入資料都是由 proceddInput 處理的,讓我們一段一段的抽絲剝繭來看看他是如何運作的:
void FirmataClass::processInput(void)
{
int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data
int command;
// TODO make sure it handles -1 properly
if (parsingSysex) { // 判斷是否開始解析 input command , 由 systemReset() 中我們得知這個參數預設值是 false
if(inputData == END_SYSEX) {
//stop sysex byte
parsingSysex = false;
//fire off handler function
processSysexMessage();
} else {
//normal data byte - add to buffer
storedInputData[sysexBytesRead] = inputData;
sysexBytesRead++;
}
} else if( (waitForData > 0) && (inputData < 128) ) { //繼續接收後面的資料逐筆放到 buffer 中
waitForData--;
storedInputData[waitForData] = inputData;
if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
// 接收由 command 送到 executeMultiByteCommand 的指令並等待收後面接續的資料長度,資料收滿 128 bit 後
switch(executeMultiByteCommand) { //判斷輸入的 command 型態,並把後面的資料分送的對應的 callback function , 當然要順便判斷 callback function 是否已經有被註冊上來了
case ANALOG_MESSAGE:
if(currentAnalogCallback) {
(*currentAnalogCallback)(multiByteChannel,
(storedInputData[0] << 7)
+ storedInputData[1]);
}
break;
case DIGITAL_MESSAGE:
if(currentDigitalCallback) {
(*currentDigitalCallback)(multiByteChannel,
(storedInputData[0] << 7)
+ storedInputData[1]);
}
break;
case SET_PIN_MODE:
if(currentPinModeCallback)
(*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
break;
case REPORT_ANALOG:
if(currentReportAnalogCallback)
(*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
break;
case REPORT_DIGITAL:
if(currentReportDigitalCallback)
(*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
break;
}
executeMultiByteCommand = 0; // 分送執行完 callback function 後,把 command 清空,讓 processInput 接收下一筆 command
}
} else {
// remove channel info from command byte if less than 0xF0
if(inputData < 0xF0) { // 判斷 command 的範圍
command = inputData & 0xF0;
multiByteChannel = inputData & 0x0F;
} else {
command = inputData;
// commands in the 0xF* range don't use channel data
}
switch (command) {
case ANALOG_MESSAGE:// 把 command 送到 executeMultiByteCommand 這邊暫存,然後回到上一段 router 中,等待接收後面接續的資料長度 case DIGITAL_MESSAGE:
case SET_PIN_MODE:
waitForData = 2; // two data bytes needed
executeMultiByteCommand = command;
break;
case REPORT_ANALOG:
case REPORT_DIGITAL:
waitForData = 1; // two data bytes needed
executeMultiByteCommand = command;
break;
case START_SYSEX: // 要直到收到這個 command 才把之後的 command 丟到上面那一大段的 router 中運作
parsingSysex = true;
sysexBytesRead = 0;
break;
case SYSTEM_RESET: // 執行 參數初始化
systemReset();
break;
case REPORT_VERSION:
Firmata.printVersion();
break;
}
}
}
結論是 processInput 是一個簡單的 router 負責等待指令/資料,並呼叫對應的 callback function 來執行。
我們明天見