8/30/2021

RS485 Modbus 와 SCADA 시스템

1. Modbus 와 SCADA 시스템

Modbus는 Modicon에서 처음 개발한 Protocol로 주로 Serial (RS485/RS232/RS422)와 TCP를 이용하여 사용되어지는 Protcol 이다. 
대체적으로 보면 Modbus의 이용은 SCADA(Supervisory control and data acquisition)기반의 Platform 동작되는 것으로 보인다.

물론 유저에 따라 다르게 사용가능 할 것이며, 일단 SCADA의 기본구조부터 알아보자. 
Serial (RS485/RS232/RS422)기반으로 Modbus를 처음 사용해보며, 
주로 SCADA에서 쓰임새를 보니, PLC를 제어하기 위해서 사용하는 것 같다. 

  • SCADA의 시스템구조 
중앙 컴퓨터에서 명령을 내리고 DATA를 얻어오는 구조이며, 각각의 Level을 부여하여 동작되어진다.
이곳에서는 Modbus이외 MQTT를 비롯하여, TCP/IP기반의 Protocol도 지원이 된다. 
Modbus 관점에서 보면, Modbus의 기본구조는 Master / Slave 구조이기 때문에, 
상위 Layer가 Master가 되고 하위 Layer가 Slave가 되는 구조인 것 같다. 

https://en.wikipedia.org/wiki/SCADA

중간 Level 2~3의 경우 경우에 따라 생략가능하며, 최종 Center 시스템으로도 Control이 가능할 것 같으며 상위 구조는 대규모 Control를 위한 구조 
상위 Level 1이 실제 Modbus RTU로 IoT 혹은 최종 Device로 구성 

SCADA

  • SCADA의 구성 예제 
실제 SCADA의 내부 세부 구성을 비롯하여, 관련부분을 이해하기에 너무 좋은 사이트 인 것 같다.
SCADA 솔루션을 제공하는 것으로 보이며, Modbus ,MQTT 관련 설명 Index


1.1 SCADA의 실제 Modbus 구성 

상위 구성처럼 상위 Center Computer가 존재하며, 이를 Modbus TCP로 쉽게 제어를 하려고 한다.
중앙컴퓨터는 Modbus TCP Slave 와 통신하며, 중간 Bridge Device는 이를 Modbus RTU로 변경하여 보내준다.

  • SCADA (중앙시스템)
  • Modbus RTU Slave (RS485/RS232로 연결)
  • Modbus TCP Master
  • Modbus TCP Slave
  • Modbus RTU Master
  • Modbus RTU Slave (각 장비)


http://www.epnc.co.kr/news/articleView.html?idxno=73320


  • Gateway의 동작 - Modbus TCP와 Modbus RTU의 Portmapping 
각 Gateway역할은 Modbus RTU Master 와  Modbus TCP Slave와 Port Map이 되어 동작 
http://www.epnc.co.kr/news/articleView.html?idxno=73320


  • Gateway의 구성 및 문제사항
아래와 같이 직접 Portmapping 후 구현이 되면, Gateway는 각 Message를 Forward만 하면 되지만, 문제가 발생하는데, 바로 Timeout 과 수신여부 일 것 같다.

https://www.epnc.co.kr/news/articleView.html?idxno=73320


상위와 다르게 Gateway에 내부 메모리가 존재하며, TCP로 받아서 Gateway에 지속적으로 쿼리하는 방식이라고 한다.
https://www.epnc.co.kr/news/articleView.html?idxno=73320


SCADA의 Modbus구조 및 시스템설계방법
상위그림 및 내용은 아래 글에서 가져왔으며, 자세한 설명이 되어있어 너무 감사하다.


2. ESP32 RS485 와 Modbus 

ESP32에서 아래와 같이 Modbus RTU의 Master 와 Slave를 지원해주고 있으며, 관련 회로도 구성 및 Example들을 제공해주고 있다. 



2.1 RS232 와 FlowControl 

ESP32에서 RS232만 지원하므로, 일단 RS232에서 기본 동작들을 알아보자. 
RS232 RTS 정보와 동작만 알면될 것 같다. 

  • RS232 RTS/CTS (Flow Control, 수신버퍼)
  1. RTS (Request to Send): Output, 본인의 수신버퍼의 상태
  2. CTS (Clear to Send): Input, 상대방의 수신버퍼의 상태 
Serial 통신이나보니, Flow Control에서 주요한게 Buffer이며, 본인의 수신버퍼의 상태를 확인한다. 

  • RS232 DRT/DSR (Flow Control, 송신버퍼)
  1. DTR (Data Terminal Ready), Output, 나의 통신준비 확인 
  2. DSR (Data Set Ready), Input, 상대방 통신준비 확인

RS232 FlowControl 및 관련자료 
RS232의 Flow Control에 대해 너무 잘 설명해주고 있어 감사하다

RS485 diffrential 파형 과 IC의 구조 
RS455 Transceiver 구조와 differential 나가는 신호 처리 부분과 Noise 처리부분 (Refection/Terminal Registor) 


2.2 RS232 와 RS485 연결구성  

ESP32와 RS485로 구성시 RS232와 RS485의 Transeiver를 구성회로도는 아래와 같이 2가지로 제공되며,
기본으로 연결방법-A 기반으로 상위 Example을 제공하고 있다. 
그 구성에 대해 간단히 알아보도록 하자. 

  • RS232-RS485 연결방법-A  
출력은 일반적인 Differential 로 나가는것로 확인되며 관련 회로도 및 관련내용 참조 
  

         VCC ---------------+                               +--------------- VCC
                            |                               |
                    +-------x-------+               +-------x-------+
         RXD <------| RO            | DIFFERENTIAL  |             RO|-----> RXD
                    |              B|---------------|B              |
         TXD ------>| DI   MAX485   |    \  /       |    MAX485   DI|<----- TXD
ESP32 WROVER KIT 1  |               |   RS-485 side |               |    Modbus master
         RTS --+--->| DE            |    /  \       |             DE|---+       
               |    |              A|---------------|A              |   |
               +----| /RE           |    PAIR       |            /RE|---+-- RTS
                    +-------x--------+              +-------x-------+
                            |                               |
                           ---                             --- 


** UART 와 RS485 Transeiver 연결 
RTS(Request To Send)  - DE  (Driver  Enable)  (TX 할 경우)
                       /RE  (Reciver Enable)  (RX 할 경우)  

RTS에 신호에 따라 DE 와 /RE 중 하나만 Enable되는 구조이며, CD를 못한다고 한다.

ESP32의 RS485관련 내부설정 
RS232 register로 설정하여 동작되는걸로 확인

ESP32의 RS232 와 RS485 Transeiver 충돌감지(CD) 없음 
정상적인 RS485의 Half duplex 구조로 TX or RX만 둘 중 하나만 ON되며, RTS는 ESP32의 상위 RS485 설정에서조절 (상위 회로도와 동일) 



  • RS232->RS485 연결방법-B 
현재 이 부분은 ESP32에서 테스트용(only TEST)으로만 지원하며, CD(Collision Dection)이 가능하다고 한다. 
  
        VCC ---------------+
                           |
                   +-------x-------+
        RXD <------| R             |
                   |              B|----------<> B
        TXD ------>| D    ADM483   |
ESP                |               |     RS485 bus side
        RTS ------>| DE            |
                   |              A|----------<> A
              +----| /RE           |
              |    +-------x-------+
              |            |
             GND          GND             
** UART 와 RS485 Transeiver 연결 
RTS(Request To Send)  - DE  (Driver  Enable)  (TX 할 경우)
                       /RE  (Reciver Enable)  (RX는 항상 on)  

ESP32의 RS232 와 RS485 Transeiver 충돌감지(CD) 존재
현재 이방법을 왜 사용하는지 정확히 이해를 못하지만, Receive는 항상 On이 되므로, 
Half duplex의 경우 문제 발생요지가 있을지도 모르겠다. (Data가 TX or RX 만되어야 하므로) 
하지만 결론적으로 RS485 Transeiver 자체가 Half duplex이므로, TX 와 RX 동시 껴질경우에 Master가 아닌 다른 Device 가 통신 중 일때가 궁금하다. 
즉, 각 Device들이 RS485 Transeiver를 통해 CS(Carrier Sense)가 되는지가 궁금하다. 

RS485의 충돌감지(CD)에 대해 아래링크에서 간단히 설명해주고 있는데, 원리는 다음과 같다고 한다. 
  1. Device가 TX로 보낸 Data도 RX를 On하여 받아서 DATA 동일하면, 정상동작
  2. Device가 TX로 보낸 Data도 RX를 On하여 받지 못할 경우는 충돌이라고 생각 
가만히 생각해보면, Ethernet의 JAM 과 거의 유사할 것 같으며, Voltage 변화로 인해 충돌을 감지할 걸로 예상하지만, RS485는 이를 SW로 구현해야함
상위 궁금증은 기본적으로 해결되어진 것 같으나, 문제는 이를 Ethernet 처럼 HW가 아닌 SW로 해야한다는 것이다.
이런식이면, Ethernet 처럼 CSMA/CD도 RS485에서 SW로 충분히 구현가능할 것 같기도 하지만 골치아프다. 
예를들면, RS232 Reciver가 Data가 들어오면, CS(Carreir Sense)를 기능이 되어 TX를 멈추고,대기, CD는 상위와 같이 SW로 DATA를 비교하면 될 것 같다. 

현재 ESP32의 RS485 SW는 충돌감지(CD)의 경우 오직 테스트용만 지원 (주의) 


2.3 RS232/RS485  통신속도 와 에러율 

일단 RS232 기준으로 Baudrate 와 Bps는 동일하지만 UART에는 Start/Stop Bit가 존재한다.
옵션에 따라 Parity Bit도 존재하지만 잘 사용하지 않는다. (UART Protocol 참조)

좀 더 나아가 RS232 와 RS485는 거의 Async 기반으로 사용하므로 에러율이 좀 더 많아진다.
이유는 내부 Clock과 실제 Data 받은 것과 Timing 오차가 시간이 지나면서 발생하다.

  • Baudrate 의 통신속도 차이발생(Actual Speed)   
Baudrate 와 Bps(Bit Per Second) 와 일치하지만, 실제 전송속도와는 일치하지 않으므로 주의
아래의 기반으로 Bandwith 점유율(Share Rate)를 본인 직접 만들어서 확인가능하다.


  • RS232/RS485 의 통신 에러율(Error rate)  
HW 통신에서 항상 나중에 확인해야 할 것이 에러율이라고 봐야할 것 같다.  
Ethernet도 통신에러율이 존재하며, 관련부분은 검색하면 알수 있다. 
Async 기반의 Serial 통신이므로, 기본적으로 Sync 통신보다 에러율이 높을 수 밖에 없다.

ESP32도 아래와 같이 Baudrate가 딱 떨어지지 않을 것이므로, 간단히 계산가능하다.

각 Baudrate와 Clock 부분관련한 통신에러율 과 Baudrate 설정 부분관련사항이다.

8/24/2021

ESP32 OpenOCD 설정 과 VS Code 설정

1. ESP32 OpenOCD 설정 

이전까지 내가 가지고 있던 OpenOCD는 FT2232 기반으로 다른 보드에서 각각 동작되는 것들을 리눅스에서 해왔지만, 
최근 Window 기반으로 이를 해결해야할 것 같아 관련자료들을 정리해본다.

ESP32 OpenOCD 관련내용 과 gdbgui 연결 
바로 이전 ESP32로 구성한 것이며, 반드시 참조 


JTAG과 OpenOCD 이해와 이전 Raspberry Pi 적용사항 (반드시 확인)
A. JTAG의 기본이해 와 OpenOCD관련내용
B. Raspberry PI OpenOCD 관련내용 과 VS Code/ VS Community 연결

OpenOCD User Guide 와 GDB Command
A. OpenOCD User Guide 반드시 확인 
B. OpenOCD에서 처음 gdb 직접연결하여 테스트 할 경우 각 gdb 명령어들 설명 


1.1 ESP Prog Board

기존에 내가 사용하던 FT2232H와 동일하며, 2개 포트를 하나는 Serial 는 다른 하나는 JTAG으로 사용한다.
세부내용은 이전의 FT2232관련 OpenOCD 참조 

https://github.com/espressif/esp-dev-kits/blob/master/docs/_static/esp-prog/block.png




  1. Interface 0 / A: JTAG
  2. interface 1 / B: UART

  • USB Serial Port 설정 
  1. 장치관리자->범용 직렬버스 컨트롤러
  2. USB Serial Converter B 선택 후 속성 
  3. 고급-> VCP 드라이버 설치 


속성에서 고급 과 Power Menagement 탭이 없다면, 다시시작한 후 다시 진행
USB Serial Converter B (Serial)이므로 VCP설정 



  • USB Serial Converter B기반의 Serial Port 설정완료 
  1. 포트-> USB Serial Port (COM6) 확인 후  USB Serial Convert B 연결확인 (Serial 용) 
  2. 포트-> USB Serial Port (COMx) 확인 후  USB Serial Convert A 있을 경우 삭제(JTAG 용)
  3. 포트-> USB Serial Port의 Port를 변경하고자 할 경우 포트설정이용
  4. 장치관리자->보기->숨겨진장치 표시 (설정되어진 Serial 포트 확인가능)
 


FTDI Driver가  반드시 상위 USB Serial Port로 잡혀야하며, 내 두번째 노트북에서는 Serial이 자꾸 Dual RS232 Serial로 잡혀서 동작이 전혀 안됨 
이부분을 아래 Tool 혹은 Driver를 변경하여 해결진행 

  • Window LibUSB 설정 (JTAG 설정)
Download
  1. Download 후 실행
  2. Option->List All Devices 선택 
  3. Dual RS232 HS Interface 0 선택
  4. FTDIBUS -> WinUSB로 변경 


  • USBDriverTool 
상위와 동일한 기능이며, OpenOCD 내부에도 동일한 Tool이 존재 
세부사용은 상위 Raspberry PI OpenOCD 관련내용 과 VS Code/ VS Community 연결 참조
이게 더 편한 것 같음 


1.2 ESP32 OpenOCD 설정 

상위 ESP-IDF를 설치를 진행했다면, esp tool 내에 openocd도 함께 들어있으며, VS Code에서도 쉽게 OpenOCD를 Start/Stop를 진행가능하다.

  1. View->Command Palette 실행 
  2. 창에서 ESP 치면 ESP 관련 Command들이 나오며 그중 OpenOCD 선택
  3. View->Output 선택 후 Output의 우측 메뉴에 "OpenOCD" 현재상태 확인가능   

하지만 나의 경우는 OpenOCD의 세부설정을 위해서 별도로 bat 파일을 만들어서 동작하도록 별도로 또 구성하였다. 


  • esp_openocd.bat
아래와 같이 별도의 TCL script 별도설정을 해주어 동작하며, 아래의 appimage_offset은 본인의 Partition Table에서 참고 
TITLE OpenOCD for ESP32 Prog 
rem Author: Jeonghun Lee
rem TEST OpenOCD
set SCR_PATH=%userprofile%\.espressif\tools\openocd-esp32\v0.10.0-esp32-20200709\openocd-esp32\share\openocd\scripts
set BIN_PATH=%userprofile%\.espressif\tools\openocd-esp32\v0.10.0-esp32-20200709\openocd-esp32\bin
set SET_ESP32_FLASH="init; halt; esp appimage_offset 0x50000"
set SET_ESP32_OS="set ESP32_RTOS \"FreeRTOS\" "
%BIN_PATH%\openocd.exe  -f  %SCR_PATH%\board\esp32-wrover-kit-3.3v.cfg -c %SET_ESP32_FLASH% -c %SET_ESP32_OS%

ESP32 OpenOCD의 관련설정 내용

  • SET_ESP32_FLASH 설정
esp32에서 내부 partition을 사용하고 있다면, 별도의 실행할 offset을 넣어 상위와 같이 설정 
재미있는것은 SPI ROM인데, profile 해보면 이 영역이 NOR Flash처럼 XIP(Execute In Place)도 되는 것으로 나온다. 
SW영역에서 그렇게 표시되어있는데, 이부분은 ESP 내부 Flash만 되는지 외부 Flash도 지원가능한지 반드시 추후에 확인 

현재 MTDI의 설정에 따라 내부 LDO로  FLASH 전원 3.3 or 1.8로 변경되며 관련설정은 별도가능 (ESP32_FLASH_VOLTAGE 값 참조)

ESP32 전용 내부변수들( 이를 이해하려면 아래내용들을 분석하면 쉽게이해)
상위 SET_ESP32_OS 에 설정을 별도로 했으며, 관련내용들 


1.3 ESP32 OpenOCD Configuration 분석 

상위에서 사용하는 esp32-wrover-kit-3.3v.cfg 을 세부적으로 분석 및 수정방법 

  • board/esp32-wrover-kit-3.3v.cfg
Main을 보면 다시 2개를 참조하며, ESP32_FLASH_VOLTAGE를 설정하고 구성됨
# Example OpenOCD configuration file for ESP32-WROVER-KIT board.
#
# For example, OpenOCD can be started for ESP32 debugging on
#
#   openocd -f board/esp32-wrover-kit-3.3v.cfg
#

# Source the JTAG interface configuration file
source [find interface/ftdi/esp32_devkitj_v1.cfg]
set ESP32_FLASH_VOLTAGE 3.3


# Source the ESP32 configuration file
source [find target/esp32.cfg]

  • interface/ftdi/esp32_devkitj_v1.cfg
ESP32 Prog Board의 설정 구성이며, FT2232 설정과 유사하며 이는 FTDI 사용법을 알면 쉽게 설정도 변경가능하다.
#
# Driver for the FT2232H JTAG chip on the Espressif DevkitJ board
# (and most other FT2232H and FT232H based boards)
#
 

interface ftdi
ftdi_vid_pid 0x0403 0x6010 0x0403 0x6014

# interface 1 is the uart
ftdi_channel 0

# TCK, TDI, TDO, TMS: ADBUS0-3
# LEDs: ACBUS4-7

ftdi_layout_init 0x0008 0xf00b
ftdi_layout_signal LED -data 0x1000
ftdi_layout_signal LED2 -data 0x2000
ftdi_layout_signal LED3 -data 0x4000
ftdi_layout_signal LED4 -data 0x8000

# ESP32 series chips do not have a TRST input, and the SRST line is connected
# to the EN pin. 
# The target code doesn't handle SRST reset properly yet, so this is
# commented out:
# ftdi_layout_signal nSRST -oe 0x0020

reset_config none

# The speed of the JTAG interface, in KHz. If you get DSR/DIR errors (and they
# do not relate to OpenOCD trying to read from a memory range without physical
# memory being present there), you can try lowering this.
#
# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz
# if CPU frequency is 160MHz or 240MHz.
adapter_khz 20000

ESP32 JTAG Speed
JTAG을 연결하면 간혹 DSR/DIR Error가 발생하는데, 이는 OpenOCD와 관련이 없다고 한다.
처음 이 문제를 JTAG Speed 문제, 즉 JTAG의 속도가 너무 부족하여 동작안되는 줄 알았는데, 알아보니 아니다.
JTAG의 속도는 20Mhz or 26Mhz 설정이며,  존재하지 않은 Memory 영역을 접근했을때 문제가 발생하는 것이라고 한다.  

  • target/esp32.cfg
ESP32의 전반적인 설정이며, TAP으로 얻는 정보들을 확인 및 관련부분 설정과정이며 이전 OpenOCD를 보면 쉽게 이해가능하다.(esp_common 생략)
# The ESP32 only supports JTAG.
transport select jtag

# Source the ESP common configuration file
source [find target/esp_common.cfg]

if { [info exists CHIPNAME] } {
	set _CHIPNAME $CHIPNAME
} else {
	set _CHIPNAME esp32
}

if { [info exists CPUTAPID] } {
	set _CPUTAPID $CPUTAPID
} else {
	set _CPUTAPID 0x120034e5
}

if { [info exists ESP32_ONLYCPU] } {
	set _ONLYCPU $ESP32_ONLYCPU
} else {
	set _ONLYCPU 3
}

if { [info exists ESP32_FLASH_VOLTAGE] } {
	set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE
} else {
	set _FLASH_VOLTAGE 3.3
}

set _TARGETNAME $_CHIPNAME
set _CPU0NAME cpu0
set _CPU1NAME cpu1
set _TAPNAME $_CHIPNAME.$_CPU0NAME

jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 -expected-id $_CPUTAPID
if { $_ONLYCPU != 1 } {
	jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -expected-id $_CPUTAPID
} else {
	jtag newtap $_CHIPNAME $_CPU1NAME -irlen 5 -disable -expected-id $_CPUTAPID
}

if { $_RTOS == "none" } {
	target create $_TARGETNAME esp32 -endian little -chain-position $_TAPNAME
} else {
	target create $_TARGETNAME esp32 -endian little -chain-position $_TAPNAME -rtos $_RTOS
}

configure_esp_workarea $_TARGETNAME 0x40090000 0x3400 0x3FFC0000 0x6000
configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE

esp32 flashbootstrap $_FLASH_VOLTAGE
xtensa maskisr on
if { $_SEMIHOST_BASEDIR != "" } {
	esp semihost_basedir $_SEMIHOST_BASEDIR
}
if { $_FLASH_SIZE == 0 } {
	gdb_breakpoint_override hard
}

# special function to program ESP32, it differs from the original 'program' that
# it verifies written image by reading flash directly, instead of reading memory mapped flash regions
proc program_esp32 {filename args} {
	program_esp $filename $args
}

add_help_text program_esp32 "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
add_usage_text program_esp32 "<filename> \[address\] \[verify\] \[reset\] \[exit\]"

1.4 OpenOCD 와 SDKCONFIG 설정 

ESP32의 경우 Linux Kernel 처럼 Kconfig 기반으로 menuconfig로 설정가능하며 이때 나오는 결과 설정값이 sdkconfig 이며, 이를 쉽게 변경가능하다. 
VS Code의 경우 GUI로 멋지게 제공을 해주고 있으므로 쉽게 설정가능하다. 

  • OpenOCD사용시 SDKCONFIG 설정변경값
기본적으로 OpenOCD기반으로 Debugger로 이용시 설정해야하는 설정들 
  1. CONFIG_ESP_DEBUG_OCDAWARE 
  2. CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
  https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/tips-and-quirks.html#support-options-for-openocd-at-compile-time


HEAP TRACE와 APP TRACE는 ESP-IDF Extension에서 세부사항을 확인가능 

  • APP TRACE 관련예제
이전에 간단하게 App Trace 테스트 구동 했으며, Heap trace는 추후 테스트 진행

  • HEAP_TRACE 기능제공 (SDKCONFIG 설정변경)
heap tracing 방법은 2가지로 제공해주고 있으며, 각각 sdkconfig 설정기반으로 본인이 선택

  • APP_TRACE  기능제공 (SDKCONFIG 설정변경)
두 개의 Trace가 다 Trace Log기반으로 동작이 되므로 관련부분은 상위 메뉴얼 참조 
APP TRACE의 경우 세부분석은 SYSTEM VIEW가 별도로 필요 (아직사용못해봄) 



2. VS Code 내부 설정 


  • VS Code Setup Manual 
ESP-IDF 설치 방법 (내부에 Git/Python을 비롯하여 전부 포함되어있음)


2.1 VS Code의 MS-CPPTool 기반설정  

상위에서 이미 CPPTool은 이미 설치가 되어있고, 아래와 같이 Run and Debug에서 launch.json만 설정해주면 된다.
OpenOCD와 동작은되는데, 이상하게 Breakpoint가 동작이 안되며, Exception이 발생하여 진행하기 힘들다.
예제프로그램으로 하면 괜찮을 것 같은데, 아직 해보지는 않음 


  • launch.json 설정 
launch.json 생성 후 자동으로 c_cpp_properties.json 자동생성 이게 다시 build/compile_commands.json 관리 
  {
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "ESP32 Debugger",             //launch.json 의 Name 
            "type": "cppdbg",                      //cppdbg 기반으로 작동  
            "request": "launch",
            
             //만약 인식을 못한다면, \\build\\xxxx.elf" 변경을 해보도록 하자 Window에서 매번 PATH문제 발생 
            "program": "${workspaceRoot}/build/xxxxx.elf",

            "miDebuggerServerAddress": "localhost:3333",    // GDB:3333/ TCL:6666/ Telnet:4444 (OpenOCD 참조) 
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "C:/Users/jhlee/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-gdb.exe",
            
            "setupCommands": [
                {
                     //gdbinit 정보를 넣으려고 했는데, 동작이 제대로 안됨 
                    "description": "gdb에 자동 서식 지정 사용",
                    "text": "symbol-file d:\\project\\mod\\mod610_sw\\build\\xxxxx.elf",
                    "ignoreFailures": true
                }
            ]

        }
    ]
}  

  • 상위 설정기반으로 진행방법 
  1. OpenOCD Start  (상위 batch 파일참조)
  2. VS Code의 Run and Debug->launch.json 설정 (상위참조)
  3. Run and Debug에서 Debug 실행진행 




  • OpenOCD Server 확인 
  1. port 4444 for Telnet communication
  2. port 6666 for TCL communication 
  3. port 3333 for gdb

2.2 ESP-IDF Debug Adapter 기반설정 (이방법 추천) 

View->Output -> ESP-IDF Debug Adapter가 존재하며, 이를 Run and Debug에 연결을하여 launch.json을 생성한다. 
이를 생성을 하게되면, 자동으로 task.json 과 setting.json이 생성이 되어진다. 
이는 예전에 Linux에서 동작하는 것으로 관련설정과 task.json을 쉽게 볼수 있다. 

상위에 내가 별도로 만든 OpenOCD batch 파일 설정도 필요가 없으며, 내부설정해서 모두 해결하면된다.

실행을 해보면 처음 breakpoint는 한번은 동작은하는데, 다음부터 exception 때문에 잘 동작이 되지 않는다. 
이전에 Linux에서도 사용했는데, 그때는 gdbgui로 집중해서 사용했던것 같다. 
 

  • lauch.json 생성
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "espidf",         //espidf 기반으로 작동 (VS Code ESP IDF를 이미 설치)  
      "name": "Launch-name", 
      "request": "launch",
       "gdbinitFile":"${workspaceFolder}/gdbinit",   
    }
  ]
}
  • gdbinit 생성
 //gdbinit 생성 후 elf에서 symbol을 찾도록 연결 
target remote :3333
set remote hardware-watchpoint-limit 2           //ESP32가 2 까지만,   
symbol-file ./build/xxxxx.elf                    //반드시 Symbol Table 연결 
mon reset halt
flushregs
thb app_main
c
  • launch.json 생성 및 관련설정 
상위설정은 기본으로 auto이며, 이외  별도로 세부설정가능 아래 링크참조 

  • 기본동작 및 확인 
본인의 Thread 갯수가 맞는 지 부터 확인 (elf 심볼테이블 매치)



아래사항들 확인 각 로그확인 
  1. View->OUTPUT ESP-IDF Debug adapter 선택 로그확인 
  2. View->OUTPUT 의 OpenOCD 선택 로그확인 (특히 Symbols 부분)
  3. View->DEBUG CONSOLE을 확인

이전과의 다른점은 Call Stack에서 각 Thread의 이름을 알수 있으며, 개별 Thread Control도 가능하며, 제어가 가능하다는 부분이다.

  • 참고
WATCH POINT를 사용하고자 하면 원하는 변수를 넣으면 감시가 된다. (물론 SDKCONFIG설정필요)


  • VSCode의 동작 
아래처럼 동작하지만 PERIPHERALS/REGISTERS/MEMORY/DiSASSEMBLEY는 없음 


  • esp-idf-vscode-generated.gdb 
gdbinit 처럼 생성된 파일로 gdb를 초기설정값 
target remote :3333
mon reset halt
flushregs
thb app_main

gdbinit 처럼 gdb 초기화 부분 
  https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/tips-and-quirks.html#what-is-the-meaning-of-debugger-s-startup-commands

  • ESP32의 제약사항 
ESP32의 경우 HW-BP(breakpoint)는 2개까지 지원되며, HW-BP기반으로 SW-BP 생성하여 FLASH(32개)와 IRAM (32개) 사용가능하지만
gdb는 SW-BP를 사용하지 못한다고 한다. 


  • Terminal->Run Task 이용하여 각 Task 실행 
기존에 제공해주는 메뉴와 비슷하며, 거의 별도로 사용할 일은 없을 것 같다. 
Linux에서는 별도로 Task를 만들어 내마음대로 구성을 했지만, 현재 ESP-IDF 에서 기본으로 각 메뉴로 제공해주고 있다. 

  • VS Code IDF Setting 
View -> Command Palette -> Preferences: Open Settings (UI))
Extensions->ESP-IDF 세부참조확인 
.vscode/task.json 참조 


상위대로하면, WATCH기능과 BreakPoints기반으로 디버깅이 가능하며 Call Stack도 분석이 가능하며 나름 어느 정도 쓸만한 것으로 보인다.

  • VS Code ESP-IDF 단점 
  1. Disasemble 
  2. Memory Read/Write 
  3. Peripheral 
상위와 같은 정보를 제공을 못해주고 있으며, 다소 불안전한 모습으로 동작한다.
사용하면 사용할 수로 많은 부분이 JTAG 디버거 기능으로 부족하다고 느끼는 바이다.


3. VS Code 기반의 ESP-IDF 의 TIPs

ESP-IDF VS Code Extension 설치 후 하단에 아래 아이콘이 생성되며 각각의 idf.py 의 기능을 손쉽게 사용가능하다.


얼마전에 새로 업데이트가 되어 새로운 기능들이 추가되고 있으며, 약간씩 변경될지도 모른다.



ESP-IDF Monitor 혹은 VS Code에서 제공해주는 기능은 PowerShell 기반으로 동작이 되며 이를 응용하여 간단하게 확장하여 사용가능하다.

  • ESP-IDF Monitor 의 경우 (tee를 이용)

Ctrl+C로 정지 후 아래와 같이 tee를 이용하여 log capture를 하자 PS에서 tee가 될줄은 정말 몰랐는데, PS(Power Shell)이 가만보면 
Linux 환경을 비롯하여 기능들을 최대한 지원해주려고 하는 것으로 보인다.
 C:\Users\jhlee\.espressif\python_env\idf4.2_py3.8_env\Scripts\python.exe C:\Users\jhlee\esp\esp-idf\tools\idf.py -p COM6 monitor | tee debug.log  

  • ESP-IDF Terminal 사용할 경우
기존 리눅스 처럼 idf.py 기반으로 메뉴를 사용가능하지만, menuconfig는 제대로 동작이 안됨
그래서 별도로 VS Code에서 GUI로 제공해줌 

 idf.py --help
......
  add-dependency           Add dependency to the manifest file. For now we only support adding dependencies on the default service.
  all                      Aliases: build. Build the project.
  app                      Build only the app.
  app-flash                Flash the app only.
  bootloader               Build only bootloader.
  bootloader-flash         Flash bootloader only.
  clean                    Delete build output files from the build directory.
  confserver               Run JSON configuration server.
  create-manifest          Create manifest for specified component.
  create-remote-component  Register a new component on the component service.
  delete-version           Delete version in dist directory from the component service.
  efuse_common_table       Generate C-source for IDF's eFuse fields.
  efuse_custom_table       Generate C-source for user's eFuse fields.
  encrypted-app-flash      Flash the encrypted app only.
  encrypted-flash          Flash the encrypted project.
  erase_flash              Erase entire flash chip.
  erase_otadata            Erase otadata partition.
  flash                    Flash the project.
  fullclean                Delete the entire build directory contents.
  gdb                      Run the GDB.
  gdbgui                   GDB UI in default browser.
  gdbtui                   GDB TUI mode.
  menuconfig               Run "menuconfig" project configuration tool.
  monitor                  Display serial output.
  openocd                  Run openocd from current path
  pack-component           Create component archive.
  partition_table          Build only partition table.
  partition_table-flash    Flash partition table only.
  post_debug               Utility target to read the output of async debug action and stop them.
  python-clean             Delete generated Python byte code from the IDF directory
  read_otadata             Read otadata partition.
  reconfigure              Re-run CMake.
  set-target               Set the chip target to build.
  show_efuse_table         Print eFuse table.
  size                     Print basic size information about the app.
  size-components          Print per-component size information.
  size-files               Print per-source-file size information.
  upload-component         Upload component in dist directory to the component service.
  upload-component-status  Check status of component upload


로지텍 mk850

로지텍 키보드 와 마우스 

오래전부터 집에서는 로지텍 키보드/ 마우스 세트가 구입하여 사용하고 있었는데, 마우스만 고장 나서 이를 해결 할 방법을 찾다가 
내 모델이 Nano Receiver 기반으로 동작 되는 것을 알고 남은 키보드와 굴러다니는 로지텍 마우스와 같이 로지텍사의 툴을 이용하여 두 개를 새로 연결하여 사용하고 있다. 
Nano Receiver의 경우 한번 연결하면 변경 못한다고 하니, 주의해서 사용하자. 

  • Nano Receiver 설정
한번 Keyboard 와 마우스를 결합하면 변경 못하므로 주의 


최근 로지텍 키보드/마우스를 다시 구입하게 되었는데,  아래 모델을 구입한 이유는 Unifying Receiver 가 지원되어 동시에 한 키보드/마우스로 3개까지 Control 가능하기 때문인데,
물론 Bluetooth도 지원 가능하지만, 집에 있는 Bluetooth 키보드도 잘 안 쓰기 때문인데, 막상 구입해서 보니 키보드가 영 아닌 것 같다. 
기존 꺼 보다 불편하게 느껴지며, 오타가 잦다. 난 역시 싼 게 제일 잘 맞는 것 같다. 
다만 편한 점은 노트북을 동시 2개사용할때 쉽게 버튼으로 Receiver를 변경해서 사용하기 때문에 제어가 쉽다.


  • Unifying Receiver 설정 
별도의 Unifying Receiver를 추가로 구입 후 이를 상위 키보드/마우스에 등록하면 됨 

8/20/2021

MQTT Broker Mosquitto 설치 및 설정

1. MQTT Broker Mosquitto 설치

Mosquitto Download

Mosquitto OpenSSL 적용

아래 사이트에서 설치방법 쉽게 나옴 


2. MQTT Mosquitto 설정 및 bat 파일 

  • mosquitto.conf 설정 
C:\Program Files\Mosquitto\mosquitto.conf 
# =================================================================
# General configuration
# =================================================================

listener 1883 0.0.0.0
allow_anonymous true

username 과 password 사용 할 경우 설정변경.

listener 1883 0.0.0.0
#allow_anonymous true
allow_anonymous false
password_file password.txt

password.txt 생성 후 아래와 같이 등록 
C:
CD C:\Program Files\Mosquitto
mosquitto_passwd.exe -b password.txt username password  //username 과 password 를 password.txt 등록 
type password.txt   // 확인 

  • mosquitto.bat
처음 실행할 경우 mosquitto.conf를 설정값을 상위 값으로 적용 후 실행 
C:
CD C:\Program Files\Mosquitto
mosquitto.exe -c mosquitto.conf -v
rem mosquitto.exe  -v
pAUSE

주석: rem or :: 사용 

  • check_mqtt.bat
0.0.0.0:1883으로 동작해야 다중 interface 가진 경우 각각의 IP로 서비스 동작가능 
netstat -an | findstr 1883
pAUSE


  • mqtt_off.bat
관리자 권한으로 실행하여 서비스로 실행된 mosquitto를 종료 한 후 mosquitto.bat 로 실행하여 동작상태를 확인 
net stop mosquitto
pAUSE


  • 기본테스트 
publish test 진행 (-t TOPIC , -m message,  -d debug)
username, password, client id도 별도로 설정가능 
C:
CD C:\Program Files\Mosquitto
mosquitto_pub.exe -h 192.168.1.26 -t topic/test  -m "testmessage" -d

subscribe test 진행 
C:
CD C:\Program Files\Mosquitto
mosquitto_sub.exe -h 192.168.1.26 -t topic/test -v



3. MQTT broker 동작 중 문제사항 


  • Window 방화벽문제 
Window 10에서 방화벽이 기본적으로 동작하므로 설정에서 방화벽을 임시적으로 꺼두록하자
설정->네트워크 및 인터넷

  • MQTT Broker Error
Error: 액세스 권한에 의해 숨겨진 소켓에 액세스를 시도했습니다.
MQTT broker(mosquitto)가 이미 실행되었거나, 혹은 1883 Port를 다른 Service가 사용중일때 발생 


상위 check_mqtt 확인 후 mqtt 서비스 종료





8/04/2021

Sphinx 기반의 문서정리2 (Doxygen)

1. Sphinx 기본사용법 


Sphinx 기본설치 및 기본사용법 
문서를 처음 5월/6월에 작성했으나, 너무 길어져서 확장하여 8월 분할작성 

Sphinx기반의 ReadTheDoc Hosting
ReadTheDoc Hosting 및 관리가 쉬워서 개인이라면 이방법을 강력추천

Sphinx 와 Github를 연결해보고 사용하겠다고 여러방법으로 테스트 해봤지만, 
가장좋은 것은 현재 ReadtheDoc 사이트에서 Hosting하는게 가장편한 것으로 보인다.  

1.1 Sphinx extension 확장사용 

요즘 Markdown File이 대세이므로, RST파일과 Markdown를 동시에 같이 사용하도록 기능을 확장하도록하자. 
기존에는Markdown은 recommonmark기반으로 사용했다고 하는데, 
myst가 이를 호환해준다고 하고 Sphinx 사이트에서도 이걸로 거의 권장하는 것 같다. 
그리고, 가장 큰 이유는 Github와 호환성때문이다. 


  • markdown 과 mermaid 관련설치
myst_parser만 사용진행 (recommonmakr는 생략사용법은 생략)
(py38-sphinx) $ pip3 install myst_parser
(py38-sphinx) $ pip3 install sphinxcontrib-mermaid  // 옵션이며, extensions 씨 필요없다면 삭제  (간단한 diagram 사용) 

  • mermaid 기본사용법
Mermaid는 Diagram Tool로 오래전부터 Doxygen과 같이 많이 사용되어진  프로그램으로, 가장 많이 사용되는 Tool 이다. 
최근 Github에서도 지원가능하므로, 알아두도록하자 


  • Markdown 관련설정변경 
Markdown 기반으로 하기 위해서 아래와 같이 설정을 변경
(py38-sphinx) $ vi conf.py

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
        'sphinx.ext.autodoc',      # autodoc 안에 automodule 도 포함
        'sphinx.ext.autosummary',  # 현재미사용
        'myst_parser',            # Markdown을 위해서 사용
        'sphinxcontrib.mermaid',  # Mermaid Diagram을 위해서 사용  
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

## 옵션으로 markdown 안에 ::: 되는 것을 동작되기 위해서 설정 RST와 같이 사용가능할것 같음 
## :::{note}
## And here's a note with a colon fence!
## :::
myst_enable_extensions = [
  "colon_fence",
]

## Source Suffix 설정 (rst,md) 
source_suffix = {
    '.rst': 'restructuredtext',
    '.txt': 'restructuredtext',
    '.md': 'markdown',
}


Sphinx-markdown 설치 및 설정 

  • Markdown 예제구성
일반 Markdown이 아닌 RST에서도 사용가능한 기능으로 확장 및 이외 diagram 추가
class에 warning/note/이외 다양한 rst directive 추가가능    
(py38-sphinx) $ vi test1.md
## TEST MD 

Markdown 에서 RST의 directive를 사용해보자  

```{admonition} Here's my note
:class: note

Here's my admonition content 
```

```{admonition} TEST Title
:class: warning

Here's my admonition content 
```

:::{note}
상위에서 설정한 colon fence! 기능 ㅋㅋㅋ
:::


mermaid 사용법임 아래 링크 참조
```{mermaid}
sequenceDiagram
  participant Alice
  participant Bob
  Alice->John: Hello John, how are you?
  loop Healthcheck
      John->John: Fight against hypochondria
  end
  Note right of John: Rational thoughts <br/>prevail...
  John-->Alice: Great!
  John->Bob: How about you?
  Bob-->John: Jolly good!
```
Markdown에서 상위 directive 사용법 

  • Markdown 관련 주의사항
  1. markdown의 # 와 ## 와 ###에 따라 계층이 나누어지므로 조심해서 사용
  2. markdown 외부 Link (http) 동작확인
  3. markdown 내부 Link는 동작확인 (HTML로 자동변경)
  4. markdown 내부 title 링크가 제대로 동작안됨 (*.md->*.html로 변경안됨)

  • index.rst의 재구성 (Markdown 사용)
Markdown을 추가하여 index를 재구성한 후 다시 확인 
(py38-sphinx) $ vi index.rst
.. toctree::
   :maxdepth: 3
   :caption:  Table of Contents
   :numbered:
   
   intro
   test1.md   
   mytest/testa.md
   mytest/testb.md   

(py38-sphinx) $ make clean  //삭제 후 진행 
(py38-sphinx) $ make html   //_build/html/index.html 확인 

index.rst 의 toctree 설정구성 

  • Markdown 상위 결과확인 (Mermaid)
테스트 용으로 Github(Mermaid 지원) 일단 기본으로 동작확인




Github 기반으로 아래와 같이 구성 후 간단히 테스트만 해봤지만, Github의 docs/ 내부는 세부적으로 연결해줘야하는 것 같다.

(py38-sphinx) $ vi index.rst   //Github일 경우 아래 구성으로 구성후 기본테스트만함(불필요한 index 및 다 지움)
.. toctree::
   :maxdepth: 3
   :caption:  Table of Contents
   :numbered:
   
   README.md
              
(py38-sphinx) $ make clean  //삭제 후 진행 
(py38-sphinx) $ make html   //_build/html/index.html 확인 

1.2 Sphinx 의 Output 변경 (Latex/Others) 

HTML 이외의 Output은 구성은 어떻게 되는 지 궁금해서 일단 테스트 진행 
하지만 테스트 결과 HTML만 괜찮은 걸로 보임 

  • 관련 Tool 설치 
(py38-sphinx) $ sudo apt-get install -y latexmk //latexmk 필요   
(py38-sphinx) $ sudo apt-get install texlive-full  //texlive  필요   

  • Latex 설정변경 
Letex 관련설정하여 테스트만 해보고 괜찮게 나오는지만 파악 
(py38-sphinx) $ vi conf.py   // Latex 관련설정추가   

# -- Options for LaTeX output ------------------------------------------------
latex_engine = 'xelatex'
latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    'papersize': 'a4paper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    'preamble': '',

    # Latex figure (float) alignment
    #
    'figure_align': 'htbp',


    # kotex config
    'figure_align': 'htbp',

    'fontpkg': r'''
\usepackage{kotex}
''',
} 

Sphinx Latex 관련설정 및 Font 설정 (출처)
  • Sphinx Builder 로 Output 변경 
(py38-sphinx) $ make latexpdf   // Latex로 출력  
(py38-sphinx) $ make epub   // epub로 출력  
(py38-sphinx) $ make man   // man로 출력  
(py38-sphinx) $ sphinx-build --help  //sphinx-build 사용법확인

일단 한글은 제대로 안되었는데, PDF 파일 뿐만 아니라 다른 Output도 구성이 너무 좋지 않음  

Sphinx의 다양한 output 지원
HTML를 빼고 Theme 및 구성이 제대로 되지 않아 거의 사용안할 듯 


2. Sphinx 와 doxygen 연결  

  • Sphinx 기반의 Doxygen 구성이해(필독)
Python Sphinx 기반의 Doxygen 구성분석 및 필요 Package들 파악 
toctree 예제 및 ESP-IDF이 구성을 자세히 이해할수가 있음 


2.1 ESP32의 Sphinx 와 doxygen 테스트

ESP의 Sphinx가 너무 잘 구현되어있어서, 그것을 그대로 한번 따라 해보려고 했는데, 
버전이 너무 낮아서 아래는 진행하지 않기로 했다. 
나와 같이 삽질하는 사람이 있을 거 같아 기록으로만 남김. 
  • ESP32 의 Sphinx 와 doxygen 사용
sphinx와 doxygen을 TEST을 위해서 기존의  ESP관련부분 참조 
(py38-sphinx) $ cp -a ~/esp/esp-idf/docs espdocs   //esp의 doc를 doxygen으로 만들예정 

(py38-sphinx) $ cd espdocs   //esp의 doc를 doxygen으로 만들예정 

(py38-sphinx) $ pip3 install breathe           //sphinx 와 doxygen 사이의 bridge 역할한다고 함

(py38-sphinx) $ cat requirements.txt 
# This is a list of python packages used to generate documentation. This file is used with pip:
# pip install --user -r requirements.txt
#
# matplotlib is currently required only by the script generate_chart.py
matplotlib==3.3.1 ; python_version>="3"
matplotlib==2.0.1 ; python_version=="2.7"
cairosvg==2.5.1 # required by sphinxcontrib-svg2pdfconverter[CairoSVG]
sphinx==2.3.1
breathe==4.14.1
sphinx-copybutton==0.3.0
sphinx-notfound-page
sphinxcontrib-blockdiag==2.0.0
sphinxcontrib-seqdiag==2.0.0
sphinxcontrib-actdiag==2.0.0
sphinxcontrib-nwdiag==2.0.0
sphinxcontrib-wavedrom==2.0.0
sphinxcontrib-svg2pdfconverter[CairoSVG]==1.1.0
nwdiag==2.0.0
recommonmark
future>=0.16.0 # for ../tools/gen_esp_err_to_name.py
sphinx_selective_exclude==1.0.3
sphinx_idf_theme==0.2.2

(py38-sphinx) $ pip3 install -r requirements.txt   //절대 실행하지 말자. 버전에 전부 너무 아래이며 오래된 package 사용 (venv 다시 설치, 젠장) 
(py38-sphinx) $ python3 build_docs.py   //확실히 기존의 sphinx 구조와 다르며 필요한 것은 다 직접구현 
IDF_PATH로 문제발생 

상위부분은 실패했으며, 분석해서 하려고 했으나 내가 원하는 방향하고 다른 것 같아 여기서 멈춘다 
상위 Sphinx는 ESP-IDF의 Sphinx인데, 너무 오래된 Version의 Sphinx를 사용하고 있다. 
그리고 부족한 부분들의 거의 직접구현하고 연결해서 사용하는 것으로 보인다. 

상위를 진행하면 전부 Version이 Downgrade 되므로 주의 
귀찮아서 기존의 venv를 지우고, 다시 venv 기반으로 sphinx 재설치
상위는 하지말도록하자. 

2.2  Doxygen 과 Sphinx를 Breath 연결구성 

  • ESP Exampel을 이용하여 Doxygen 생성 
일단 C소스가 필요하니, ESP Example을 가져와서 이 기반으로 doxygen을 생성하자. 
관련 package들은 우선 설치를 진행 
(py38-sphinx) $ sudo apt install doxygen     //doxygen 이 없어서 설치 
(py38-sphinx) $ sudo apt install doxygen-latex doxygen-doc  //doxygen 관련 package 설치
(py38-sphinx) $ doxygen-gui graphviz   //오래전부터 graphviz랑 같이사용 

(py38-sphinx) $ mkdir doxydocs   //venv로 이미 설치진행완료 

(py38-sphinx) $ cd doxydocs 

(py38-sphinx) $ cp -a ~/esp/esp-idf/examples  .    //esp32 examples 소스만 가져옴 

(py38-sphinx) $ cmake -version
cmake version 3.16.3

(py38-sphinx) $ doxygen -v
1.8.17 

(py38-sphinx) $ doxygen -g   //Doxyfile 생성 

(py38-sphinx) $ vi Doxyfile    //생성된 Doxyfile 의 설정들을 변경해주자 (소스위치/XML/기타등등)
PROJECT_NAME           = "ESP Sample"
INPUT                  = ./examples 
RECURSIVE              = YES
GENERATE_XML           = YES

(py38-sphinx) $ doxygen       //Doxyfile 기준으로 Doxygen 실행  

(py38-sphinx) $ ls    //html 와 xml 생성확인 HTML을 우선확인해보자  
Doxyfile  examples  html  latex   xml

  • 생성된 Doxygen 구성확인 
  1. 상위 HTML에서 쉽게 생성된 Doxygen 파일 확인 가능 (index.html)
  2. Latex에서는 PDF 파일 확인가능 
  3. XML은 breathe를 위해 사용예정 

나의 경우 Doxygen 자료가 없어서 ESP의 Sample 이용 



  • Sphinx 와 Breathe 기반으로 Doxygen 연결 
Breathe를 기반으로 Doxygen XML을 이용하여 Sphinx 와 연결 

(py38-sphinx) $ mkdir docs
(py38-sphinx) $ cd docs

(py38-sphinx) $ pip3 install breathe           //sphinx 와 doxygen 사이의 bridge 역할한다고 함

(py38-sphinx) $ sphinx-quickstart     //sphinx start 실행  

(py38-sphinx) $ vi conf.py 
## Extension을 위해서 설정 
import os
import sys
sys.path.insert(0, os.path.abspath('.'))

## 만약 Shell Script 형식으로 사용하고자 하면 사용 
#import subprocess
#subprocess.call('make clean', shell=True)
#subprocess.call('cd ../../doxygen ; doxygen', shell=True)

## breathe 설정으로 상위생성된 XML 연결  
breathe_projects = { "ESP Sample": "../xml/" }
breathe_default_project = "ESP Sample"


## Extension에 breathe 추가 및 기타 추가 (필요 없다면 빼자) 
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.doctest',
    'sphinx.ext.mathjax',
    'sphinx.ext.viewcode',
    'sphinx.ext.imgmath',
    'sphinx.ext.todo',
    'breathe',
]

html_theme = 'sphinx_rtd_theme'

(py38-sphinx) $ vi index.rst      // 아래와 같이 설정하면 시간 엄청 오래걸리며 이상하게 생성됨  
.. toctree::
   :maxdepth: 2
   :caption: Contents:

.. doxygenindex::
.. doxygenfunction::
.. doxygenstruct::
.. doxygenenum::
.. doxygentypedef::
.. doxygenclass::

(py38-sphinx) $ make html

  • 결과확인 
비록 ESP의 Sample을 가지고 했지만, 아래와 같이 Doxygen 형태로 나옴




(py38-sphinx) $ vi test0.rst      // @breif 가 있는 함수를 찾아 함수명으로 추출  
C  Functions
-------------

.. doxygenfunction:: ws2812_rmt_adapter

(py38-sphinx) $ vi index.rst      // 확인  
.. toctree::
   :maxdepth: 2
   :caption: Contents:

   test0   
   
(py38-sphinx) $ make html

breathe 기본사용법 


2.3 기타 Doxygen 테스트 

  • Cmake 와 Doxygen 설치 및 확인 

$ cmake -version
cmake version 3.16.3

$ sudo apt install doxygen
$ sudo apt install doxygen-latex doxygen-doc doxygen-gui graphviz 
$ sudo apt install xapian-tools

$ doxygen -v
1.8.17 

https://github.com/jacking75/examples_CMake
git clone https://github.com/ttroy50/cmake-examples.git
//git clone https://github.com/sinairv/Cpp-Tutorial-Samples.git
//$ git clone https://github.com/googleapis/google-cloud-cpp
//$ git clone https://github.com/GoogleCloudPlatform/cpp-samples

https://github.com/GoogleCloudPlatform/python-docs-samples
https://github.com/GoogleCloudPlatform/nodejs-docs-samples
https://github.com/GoogleCloudPlatform/ai-platform-samples


https://breathe.readthedocs.io/en/latest/directives.html#doxygenstruct

$ mkdir docs
$ cd docs
$ doxygen -g   //Doxyfile 생성 

$ vi Doxyfile
PROJECT_NAME           = "Google CPP Sample"
INPUT                  = ../cpp-samples
RECURSIVE              = YES

$ doxygen         // 생성확인


$ cd ..
$ ls 
cpp-samples  docs  py38-sphinx

$ find . -name CMakeLists.txt
./cpp-samples/gcs-fast-transfers/CMakeLists.txt
./cpp-samples/iot/mqtt-ciotc/CMakeLists.txt
./cpp-samples/cloud-run-hello-world/CMakeLists.txt
./cpp-samples/populate-bucket/CMakeLists.txt
./cpp-samples/speech/api/CMakeLists.txt
./cpp-samples/gcs-indexer/CMakeLists.txt


$ vi CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("Sphinx Example")
add_subdirectory ("Cpp-Tutorial-Samples")
add_subdirectory ("docs")

$ vi docs/CMakeLists.txt
find_package(Doxygen REQUIRED)

#This will be the main output of our command
set(DOXYGEN_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/html/index.html)

add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
                   DEPENDS ${CAT_CUTIFIER_PUBLIC_HEADERS}
                   COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile
                   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                   MAIN_DEPENDENCY Doxyfile
                   COMMENT "Generating docs")

add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})

$ vi docs/Doxyfile.in
#...
INPUT = "@DOXYGEN_INPUT_DIR@"
#...
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
#...

$ vi docs/CMakeLists.txt
find_package(Doxygen REQUIRED)

set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/cpp-samples)
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/docs/doxygen)
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/html/index.html)
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

#Replace variables inside @@ with the current values
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)

file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) #Doxygen won't create this for us
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
                   DEPENDS ${CAT_CUTIFIER_PUBLIC_HEADERS}
                   COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
                   MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
                   COMMENT "Generating docs")

add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})

$ cmake -Btest
$ cmkae --build test
$ cmake CMakeLists.txt

$ vi cpp-samples/CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("Google Sample")

add_subdirectory ("gcs-fast-transfers")
add_subdirectory ("iot/mqtt-ciotc")
add_subdirectory ("cloud-run-hello-world")
add_subdirectory ("populate-bucket")
add_subdirectory ("speech/api")
add_subdirectory ("gcs-indexer")



$ sudo apt-get install lynx    // HTML viewer로 설치했으나, 너무 좋지않아 필요없음 


bazel 사용법


Github Page 설정관련 (Web 관련부분)

RST 와 Markdown

Github 기반으로 Technical 관련문서를 만드는 사이트 

Github기반으로 Sphinx로 이용하여 문서만드는 예제 


8/01/2021

Sphinx 기반의 문서정리-1

1. Sphinx 설치 

  • Python venv기반으로 구성 
호환성문제로 virtualenv를 사용하기로 결정했으며, 상위참조하여 생성 
$ python -V  //python이 없다면 /us/bin 에서 확인 후 설치 
Python 3.8.5
# sudo ln -s /usr/bin/python3 /usr/bin/python   //나의 경우 이전에 python2를 python 심볼링크 사용 (옵션) 
# sudo apt-get install python3-venv     //venv 설치 (옵션)

$ mkdir works
$ cd works
$ python -m venv py38-sphinx      //py38-sphinx venv 생성

$ ls
py38-sphinx

$ ls py38-sphinx/bin/           //python 과 python3 는 symbollink 확인 
Activate.ps1  activate  activate.csh  activate.fish  easy_install  easy_install-3.8  pip  pip3  pip3.8  python  python3

$ source py38-sphinx/bin/activate   //virtual env의 python 사용 
매번 py38-sphinx 내부의 virtualenv를 사용하기위해서는 source를 진행하거나, .bashrc 등 기타 로그인때 자동으로 설정해도 된다.


  • venv 안에 Python package 설치 
sphinx package 설치 및 확인 
(py38-sphinx) $ pip list
Package       Version
------------- -------
pip           20.0.2 
pkg-resources 0.0.0  
setuptools    44.0.0 

(py38-sphinx) $ pip install sphinx   //venv에 sphinx 설치

(py38-sphinx) $ pip list
Package                       Version  
----------------------------- ---------
alabaster                     0.7.12   
Babel                         2.9.1    
certifi                       2021.10.8
charset-normalizer            2.0.7    
docutils                      0.17.1   
idna                          3.3      
imagesize                     1.2.0    
Jinja2                        3.0.2    
MarkupSafe                    2.0.1    
packaging                     21.0     
pip                           20.0.2   
pkg-resources                 0.0.0    
Pygments                      2.10.0   
pyparsing                     2.4.7    
pytz                          2021.3   
requests                      2.26.0   
setuptools                    44.0.0   
snowballstemmer               2.1.0    
Sphinx                        4.2.0    
sphinxcontrib-applehelp       1.0.2    
sphinxcontrib-devhelp         1.0.2    
sphinxcontrib-htmlhelp        2.0.0    
sphinxcontrib-jsmath          1.0.1    
sphinxcontrib-qthelp          1.0.3    
sphinxcontrib-serializinghtml 1.1.5    
urllib3                       1.26.7 

(py38-sphinx) $ pip list | wc -l    //전부 28 line 이며 -2개를 하면 26 package 가지고 있음(계산하기 귀찮음) 
28

(py38-sphinx) $ pip list | wc      //newline:28  word:56  byte counts:1120
     28      56    1120


Python venv 기본사용법



1.1. sphinx 기본 테스트

  • Sphinx 기본사용 및 확인 

(py38-sphinx) $ mkdir docs
(py38-sphinx) $ cd docs

(py38-sphinx) $ sphinx-quickstart  // 실행하면, 현재 directory기준 
Sphinx 4.0.2 빠른 시작 유틸리티에 오신 것을 환영합니다.

다음 설정에 대한 값을 입력하십시오 (대괄호로 묶여 있는 기본값이 존재하고
이 값을 사용하려면 바로 Enter를 누릅니다).

선택한 루트 경로: .

Sphinx 출력을 위한 빌드 디렉토리를 배치하는 두 가지 옵션이 있습니다.
루트 경로 내에서 "_build" 디렉토리를 사용하거나, 루트 경로 내에서
"source"와 "build" 디렉토리로 분리합니다.
> 원본과 빌드 디렉토리 분리 (y/n) [n]:
> 프로젝트 이름: testSphinx
> 작성자 이름: Jeonghun Lee
> 프로젝트 릴리스 []: 1.0

문서를 영어 이외의 언어로 작성하려는 경우, 여기에서 해당 언어 코드로 언어를
선택할 수 있습니다. 그러면 Sphinx가 생성한 텍스트를 해당 언어로 번역합니다.

지원되는 코드 목록은
https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-language
를 참조하십시오.
> 프로젝트 언어 [en]:
/home/jhlee/works/docs/conf.py 파일을 만드는 중입니다.
/home/jhlee/works/docs/index.rst 파일을 만드는 중입니다.
/home/jhlee/works/docs/Makefile 파일을 만드는 중입니다.
/home/jhlee/works/docs/make.bat 파일을 만드는 중입니다.

완료됨: 초기 디렉토리 구조가 생성되었습니다.

이제 마스터 파일 /home/jhlee/works/docs/index.rst을(를) 채우고 다른 원본 문서 파일을 만들어야 합니다. Makefile을 사용하여 다음과 같이 문서를 빌드하십시오:
   make builder
여기서 "builder"는 지원되는 빌더 중 하나(예: html, latex, linkcheck)입니다.

(py3-sphinx) $ ls      // 원본과 빌드 디렉토리 분리 [n] 일경우 구성 
Makefile  _build  _static  _templates  conf.py  index.rst  make.bat


(py38-sphinx) $ ls      // 원본과 빌드 디렉토리 분리 [y] 일경우 구성 
Makefile  build  make.bat  source 
(py3-sphinx) $ ls source
_static  _templates  conf.py  index.rst

(py3-sphinx) $ make html   //_build 안에 html 안에 html구성 index.html 확인

  • _build/html/index.html
상위내용 및 venv 기반의 sphinx 설정 
  https://www.docslikecode.com/learn/01-sphinx-python-rtd/

1.2. Sphinx의 theme 변경 

Sphinx에서 제공하는 Theme들을 찾아 설치 후 이를 설정하고 이 기반으로 변경해보자.
아래는 ReadTheDoc의 theme이며, 이외에도 많으므로 각 설정해보면서 바꾸어 보자.


(py38-sphinx) $ pip install sphinx_rtd_theme      //sphinx theme 설치 esp32는 별도로 변경해서 사용함
(py38-sphinx) $ pip list | wc                     //sphinx_rtd_theme 만 설치됨
     29      58    1160

(py38-sphinx) $ vi conf.py   //sphinx_rtd_theme 만 변경
#html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'

(py3-sphinx) $ make html   //_build 안에 html 안에 html구성 index.html 확인

  • _build/html/index.html


Sphinx는 이외에도 다양한 Theme을 제공
아래사이트에서 본인이 원하는 Theme 찾고 설치진행 후 상위와 동일하게 설정 



1.3. Sphinx extension 설정 (conf.py)

  • sphinx에서 필요한 기능을 확장하여 설정
  1. extension 기능을 사용하기 위해서 아래와 같이 python 소스의 주석을 제거한 후 진행 
  2. 원하는 extension 기능을 아래와 같이 추가 
(py38-sphinx) $ vi conf.py   //각 관련부분 수정 
## 아래부분은 기본으로 주석으로 되어짐 
import os
import sys
sys.path.insert(0, os.path.abspath('.'))

## 확장기능으로 아래 링크참조 
extensions = [
        'sphinx.ext.autodoc',      # autodoc 안에 automodule 도 포함
        'sphinx.ext.autosummary',  # 현재미사용 
]
## 이전설정으로 다른 Theme으로 변경가능 
html_theme = 'sphinx_rtd_theme'

extension을 이용하여 다양하게 확장가능
상위에 각각의 링크확인가능 


1.4. Sphinx 의 index.rst 설정 


  • index.rst 파일설정 
index.rst 기본값 확인 후 toctree 설정진행 
(py38-sphinx) $ cat index.rst   //기본설정확인
Welcome to testSphinx's documentation!
======================================

.. toctree::
   :maxdepth: 2
   :caption: Contents:


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

각 구성할 *.rst 파일과 함께 최종 index.rst 에 연결진행 

  • about.rst 구성 
(py38-sphinx) $ vi about.rst    //상위에서 source 와 build를 분리하지않음 (분리하면 source 안에)
about 
=====

about 에대한 파일이며 이것은 오직 테스트용으로 사용함 

.. math::
   
   (a + b)^2 = a^2 + 2ab + b^2

   (a - b)^2 = a^2 - 2ab + b^2




  • intro.rst 구성 
(py38-sphinx) $ vi intro.rst  //아래내용들은 toctree 예제참조
intro^^
=========

정말 이게 인트로인지 테스트 해보자 

.. note::

   This function is not suitable for sending spam e-mails.

.. versionadded:: 2.5
   The *spam* parameter.


.. deprecated:: 3.1
   Use :func:`spam` instead.


.. seealso::

   Module :py:mod:`zipfile`
      Documentation of the :py:mod:`zipfile` standard module.

   `GNU tar manual, Basic Tar Format ???
      Documentation for tar archive files, including GNU tar extensions.   




  • source.rst
(py38-sphinx) $ vi source.rst
Python source 
==============

.. automodule:: pysrc.testclass
    :members: 
    
(py38-sphinx) $ mkdir pysrc    
(py38-sphinx) $ vi pysrc/testclass.py  //아래사이트에서 얻은예제 추가 (상위 conf.py 확장) 
"""
    My Module
    ~~~~~~~~~
"""

class Test(object):
    """두 개의 int 값을 입력받아 다양한 연산을 할 수 있도록 하는 클래스.

    :param int a: a 값
    :param int b: b 값
    """

    def __init__(self, a, b):
        self._a = a
        self._b = b

    def is_same(self):
        """미리 입력받은 a와 b값이 같은지 확인하여 결과를 반환합니다.

        :return: boolean True or False에 대한 결과, a와 b가 값으면 True, 다르면 False

        예제:
            다음과 같이 사용하세요:

            >>> Test(1, 2).is_same()
            False

        """
        return self._a == self._b

    def plus(self):
        """미리 입력받은 a와 b값을 더한 결과를 반환합니다.

        :returns: int a + b에 대한 결과

        예제:
            다음과 같이 사용하세요:

            >>> Test(2, 1).plus()
            3


        """
        return self._a + self._b




  • index.rst 변경 
(py38-sphinx) $ vi index.rst   //상위에서 추가한 *rst 파일들 추가 혹은 directory 추가 
Welcome to my Sphinx TEST !!!!!!!!!!!!
======================================

This is the documentation for TEST 
is it ok???   
한글도 되는 지 테스트를 해보도록하자 ㅋㅋㅋㅋㅋ   
MarkDown 과 유사하지만 "toctree" 별도로 제어로사용??   

.. toctree::
   :maxdepth: 2
   :caption: Table of Contents
   :numbered:   

   about
   intro
   source

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`


(py3-sphinx) $ make html   //_build 안에 html 안에 html구성 index.html 확인 

  • 결과확인 
상위설정 후 make html로 생성된 파일확인 






상위 sphinx quickstart 기본설명
  https://www.sphinx-doc.org/en/master/usage/quickstart.html