# 如何看懂Open Source : 帶你閱讀一座程式III ###### tags: `libmodbus` Copyright 2021, [月下麒麟](https://hackmd.io/@YMont/note-catalog) --- ## 概念 文章回顧: [如何看懂Open Source : 帶你閱讀一座程式I](https://hackmd.io/@YMont/c-libmodbus_I) [如何看懂Open Source : 帶你閱讀一座程式II](https://hackmd.io/@YMont/c-libmodbus_II) 前面兩篇探討了一些,C語言的架構與基礎知識 此篇重點會著墨在Modbus的reply, 再帶到一些跟**Modbus Specification**有關的內容 以下會先提及一些**libmodbus Header file**, 主要會說明**modbus_reply**函式 >會選擇modbus_reply()來探討, >主要原因為透由modbus回覆,可更清楚modbus行為與相關程式實作的對應關係 ## Learning Header file reference:[stephane/libmodbus/src/modbus.h](https://github.com/stephane/libmodbus/blob/master/src/modbus.h) **Modbus function code** ```c= #define MODBUS_FC_READ_COILS 0x01 #define MODBUS_FC_READ_DISCRETE_INPUTS 0x02 //... #define MODBUS_FC_MASK_WRITE_REGISTER 0x16 #define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17 ``` 定義Modbus function code, function code就是用來定義modbus行為, 如0x01就是指讀取遠端設備的輸出值。 **quantity of bit, register, input** ```c= /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0) * (chapter 6 section 11 page 29) * Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0) */ #define MODBUS_MAX_READ_BITS 2000 #define MODBUS_MAX_WRITE_BITS 1968 ``` 原著作者很貼心,還附上Spectification的出處來源 定義PDU(protocol data unit的) ![](https://i.imgur.com/o4gzoL4.png) (Modbus對資料格式的框架圖示) **小結:** FC 0x01 -> quanlity: 1 to 2000 Read Coil FC 0x02 -> quanlity: 1 to 2000 Read Discrete Input FC 0x03 -> quanlity: 1 to 125 Read Holding Register FC 0x04 -> quanlity: 1 to 125 Read Input Register FC 0x05 -> quanlity: 1 to 255 Write Single Coil FC 0x06 -> quanlity: 1 to 65535 Write Single Register FC 0x10 -> quanlity: 1 to 123 Write Multiple register FC 0x17 -> quanlity: 1 to 125/121 Read/Write Multiple register reference[Modbus_Application_Protocol_V1_1b.pdf](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf) 以上,對於libmodbus程式位置與modbus功能碼有一些基礎的對應關係, 那麼,接著往下看reply函式 --- reference:[stephane/libmodbus/src/modbus.c](https://github.com/stephane/libmodbus/blob/master/src/modbus.c#L705) ```c int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping) ``` >在這個函式裡面會利用switch..case..來做一些進入哪個function code的判斷 MODBUS_FC_READ_COILS -> 0x01 MODBUS_FC_READ_DISCRETE_INPUTS -> 0x02 (小巧思,共用程式碼,故僅寫在0x02的case裡) MODBUS_FC_READ_HOLDING_REGISTERS -> 0x03 MODBUS_FC_READ_INPUT_REGISTERS -> 0x04 (小巧思,共用程式碼,故僅寫在0x04的case裡) MODBUS_FC_WRITE_SINGLE_COIL -> 0x05 MODBUS_FC_WRITE_SINGLE_REGISTER -> 0x06 MODBUS_FC_WRITE_MULTIPLE_COILS-> 0x0F MODBUS_FC_WRITE_MULTIPLE_REGISTERS -> 0x10 MODBUS_FC_REPORT_SLAVE_ID -> 0x11 MODBUS_FC_READ_EXCEPTION_STATUS -> 0x07 MODBUS_FC_MASK_WRITE_REGISTER -> 0x16 MODBUS_FC_WRITE_AND_READ_REGISTERS -> 0x17 **作者是怎麼做判斷的呢?** ~~為什麼寫到這裡就斷了 我不是富堅阿~ 9/9復刊...~~ 作者利用switch..case..去回應function code ```c= int offset; int slave; int function; uint16_t address; //... offset = ctx->backend->header_length; slave = req[offset - 1]; function = req[offset]; address = (req[offset + 1] << 8) + req[offset + 2]; //... /* Data are flushed on illegal number of values errors. */ switch (function) ```