EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Hardware / อ่านค่าจากอุปกรณ์ Modbus ที่ไม่รู้ว่าเป็นตัวอะไร พิสูจน์ก่อนตีความ
Hardware

อ่านค่าจากอุปกรณ์ Modbus ที่ไม่รู้ว่าเป็นตัวอะไร พิสูจน์ก่อนตีความ

โดย Ton-Or ·14 ต.ค. 2026·อ่าน 11 นาที
อ่านค่าจากอุปกรณ์ Modbus ที่ไม่รู้ว่าเป็นตัวอะไร พิสูจน์ก่อนตีความ

ก่อนจะถอดความหมายของ register ได้ ต้องรู้ก่อนว่ากำลังคุยกับอะไรอยู่ และคำว่ารู้ในที่นี้หมายถึงเดินไปอ่านป้ายที่ตัวเครื่อง ไม่ใช่เดาจากรูปทรงของตัวเลขที่วิ่งออกมา

พอดีผมรับงานต่อจากระบบเก่าที่ผู้ติดตั้งเดิมหายไปแล้ว สิ่งที่ได้มาคือสายคู่หนึ่งจากตู้คอนโทรล กับคำบอกเล่าว่า "มันเป็น Modbus นะ" จบแค่นั้น ไม่มีเอกสาร ไม่มี register map ไม่มีแม้แต่ยี่ห้อ ตัวจอเดิมที่เคยโชว์ค่าก็ตายไปพร้อมกับบริการคลาวด์ที่ปิดตัว งานคือทำให้ค่าพวกนั้นกลับมาอ่านได้อีกครั้ง บทความนี้ผมเล่าขั้นที่อยู่ก่อนการถอด register map คือขั้นที่ยังไม่รู้ด้วยซ้ำว่ากำลังอ่านอะไรอยู่ ซึ่งเป็นขั้นที่ผมพลาดเองแล้วตีความผิดอยู่เป็นเดือน

ยี่ห้อ รุ่น สถานที่ และเลขวง IP ในบทความนี้ผมเปลี่ยนเป็นค่าสมมุติหมดแล้วนะครับ ส่วนวิธีไล่กับตัวเลขสถิติคือของจริง

กฎข้อแรกก่อนจะแตะอะไร: อ่านอย่างเดียวเท่านั้น

ระบบที่ผมไปต่อคือระบบที่ กำลังเดินอยู่จริง มีของอยู่ในนั้น มีมอเตอร์ที่ทำงานตามคำสั่งของคอนโทรลเลอร์ ไม่ใช่ชุดทดลองบนโต๊ะ สิ่งแรกที่ผมทำก่อนเขียนสคริปต์บรรทัดแรกคือตั้งกติกาว่าทุกเครื่องมือที่ผมเขียนจะใช้ได้แค่สองฟังก์ชัน

บนระบบที่เดินอยู่จริง ใช้ได้แค่ FC01 กับ FC03

FC01 (อ่าน coil) และ FC03 (อ่าน holding register) เท่านั้น ห้ามใช้ FC05 FC06 FC10 ซึ่งเป็นคำสั่งเขียน แม้เอกสารของอุปกรณ์จะบอกว่าเขียนค่าตั้งต้นหรือสั่งบังคับทำงานได้ก็ตาม เพราะการเขียนค่าผิดหนึ่งครั้งบนระบบที่มีของจริงอยู่ข้างใน แปลว่าของเสียหายทั้งล็อต หรือคอมเพรสเซอร์พัง ซึ่งแพงกว่าค่าจ้างทั้งงานหลายเท่า เครื่องมือที่ผมเขียนทุกตัวมีแบนเนอร์ READ-ONLY ขึ้นตอนสตาร์ท และผม grep หา func=5, func=6, func=16 ในโค้ดก่อนรันทุกครั้ง

มีอีกเรื่องที่ต้องระวังคู่กัน คือ log ของเราต้องเขียนให้ชัดว่าค่าไหน "อ่านมา" ครั้งหนึ่งผมโชว์ค่าตั้งต้นของคอนโทรลเลอร์ใน log เป็น set 100.0C เจ้าของระบบเห็นแล้วตกใจนึกว่าสคริปต์ผมไปตั้งค่าให้ ทั้งที่มันคือค่าที่อ่านมาจาก register เฉยๆ หลังจากนั้นผมเปลี่ยนเป็น set(อ่านมา): 100.0C ทุกจุด เรื่องเล็กแต่ช่วยไม่ให้คนตกใจฟรี

กวาดหาว่าอุปกรณ์คุยที่ความเร็วไหน

ก่อนเริ่มกวาด เช็กก่อนว่าฝั่งระบบปฏิบัติการเห็นพอร์ตจริงและไม่มีใครแย่งใช้อยู่ ผมเคยนั่งไล่อยู่ครึ่งชั่วโมงเพราะมีสคริปต์เก่าของผมเองค้างอยู่อีกหน้าต่าง แย่งพอร์ตกันจนอ่านไม่ขึ้น

ls -l /dev/serial/by-id/            # ดูว่าตัวแปลง USB-RS485 เสียบอยู่จริงไหม
sudo fuser -v /dev/ttyUSB0          # มีโปรเซสไหนถือพอร์ตนี้อยู่หรือเปล่า
stty -F /dev/ttyUSB0 -a | head -3   # ค่าปัจจุบันของพอร์ต
sudo usermod -aG dialout "$USER"    # จะได้ไม่ต้อง sudo ทุกครั้ง (ต้อง logout/login)

Modbus RTU ไม่มีกลไกค้นหาอุปกรณ์ในตัว เราต้องเดาพารามิเตอร์แล้วลองยิงเอง ตัวแปรที่ต้องกวาดมีสี่ชั้นคูณกัน

7ค่า baud ที่ต้องลอง
3แบบ parity
2จำนวน data bit
247ที่อยู่ต่ออุปกรณ์

คูณกันแล้วเป็นหมื่นครั้ง ถ้ายิงทุกช่องรอ timeout เต็มทุกครั้งคือรอข้ามคืน ผมเลยทำสองชั้น ชั้นแรกกวาดหยาบด้วย address ตัวอย่างไม่กี่ตัวเพื่อหาชุดพารามิเตอร์ที่มีคนตอบ ชั้นที่สองค่อยกวาด address ครบ 1 ถึง 247 เฉพาะบนชุดพารามิเตอร์ที่เจอแล้ว

#!/usr/bin/env python3
"""bus_sweep.py - READ-ONLY: กวาดหาอุปกรณ์บนบัส RS485
   ใช้ FC03 อย่างเดียว ไม่มีคำสั่งเขียนในไฟล์นี้"""
import itertools, time, serial

BAUDS   = [1200, 2400, 4800, 9600, 19200, 38400, 115200]
PARITY  = ["N", "E", "O"]
BYTES   = [8, 7]
PROBE   = [1, 2, 10, 20, 32, 247]      # ชั้นแรกลองแค่ไม่กี่ที่อยู่

print(">>> READ-ONLY MODE - FC03 only <<<")

def crc16(frame: bytes) -> bytes:
    crc = 0xFFFF
    for b in frame:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return bytes([crc & 0xFF, crc >> 8])

def probe(ser, slave, addr=0, count=1):
    req = bytes([slave, 0x03, addr >> 8, addr & 0xFF, 0x00, count])
    ser.reset_input_buffer()
    ser.write(req + crc16(req))
    return ser.read(256)

for baud, par, bits in itertools.product(BAUDS, PARITY, BYTES):
    try:
        ser = serial.Serial("/dev/ttyUSB0", baud, bytesize=bits,
                            parity=par, stopbits=1, timeout=0.35)
    except serial.SerialException as e:
        print(f"  เปิดพอร์ตไม่ได้ {baud}/{bits}{par}1: {e}")
        continue
    for sl in PROBE:
        resp = probe(ser, sl)
        if valid(resp, sl):                 # ตัวตรวจอยู่หัวข้อถัดไป
            print(f"[พบ] {baud}/{bits}{par}1 slave={sl} "
                  f"raw={resp.hex(' ')}")
        time.sleep(0.05)
    ser.close()

ผลของผมคือเจอชุดเดียวที่มีคนตอบ คือ 19200 8N1 ส่วน baud อื่นเงียบสนิททุกที่อยู่ ตรงนี้ได้ข้อมูลชิ้นแรกที่เชื่อได้แล้ว หน้าตาผลที่รันออกมาประมาณนี้

$ python3 bus_sweep.py
>>> READ-ONLY MODE - FC03 only <<<
  ... 1200/8N1 เงียบทุกที่อยู่
  ... 9600/8N1 เงียบทุกที่อยู่
[พบ] 19200/8N1 slave=20 raw=14 03 02 00 00 c4 2b
  ... 38400/8N1 เงียบทุกที่อยู่
  ... 115200/8N1 เงียบทุกที่อยู่
สรุป: ชุดที่ใช้ได้ = 19200 8N1 · มีอุปกรณ์ตอบ 1 ที่อยู่

ไบต์แรก 14 คือเลขฐานสิบหกของ 20 ตรงกับที่อยู่ที่เราถาม ไบต์ที่สอง 03 คือฟังก์ชันที่เราส่งไป และสองไบต์ท้ายคือ CRC ที่คำนวณตรง ครบทั้งสามด่านคือของจริง

เฟรมคำตอบ 7 ไบต์จากที่อยู่ 20 และด่านที่ตรวจแต่ละไบต์1403020000c42bที่อยู่ 20ตรงที่ถามฟังก์ชัน 03ที่ส่งไปไบต์ข้อมูลตรงกลางไม่อยู่ในด่านตรวจCRC 2 ไบต์คำนวณเทียบแล้วตรงผ่านครบสามด่านคือของจริง
ไบต์สีน้ำเงินคือไบต์ที่ตัวกวาดตรวจ ไบต์ตรงกลางไม่ถูกใช้ตัดสิน

ตัวกวาดที่ไม่ตรวจ CRC จะให้ที่อยู่ปลอมมาเป็นพวง

รอบแรกที่ผมกวาดครบ 1 ถึง 247 ผลออกมาว่าเจออุปกรณ์ที่ address 13, 15, 17, 20, 22 ไปจนถึง 37 เป็นสิบตัว ผมดีใจอยู่พักหนึ่งว่าเจอเยอะ ก่อนจะสังเกตว่ามันเรียงห่างเท่าๆ กันแบบผิดธรรมชาติ ความจริงคือ มีอุปกรณ์จริงตัวเดียว ที่เหลือคือเศษของเฟรมเดิมที่ค้างอยู่ในบัฟเฟอร์กับเสียงสะท้อนบนสายครึ่งดูเพล็กซ์ ที่บังเอิญมีไบต์แรกตรงกับที่อยู่ที่เรากำลังถาม

ตัวกวาดที่เชื่อได้ต้องตรวจสามชั้น ไม่ใช่แค่ดูว่ามีไบต์ตอบกลับมาไหม

ด่านตรวจของคำตอบหนึ่งเฟรมมีข้อมูลตอบยาวพอ->ไบต์แรก = ที่อยู่ที่เราถาม->ไบต์สอง = 0x03หรือ 0x83 ถ้า error->CRC ตรงคำนวณเทียบ
def valid(resp: bytes, slave: int) -> bool:
    if len(resp) < 5:
        return False
    if resp[0] != slave:              # กันเฟรมของตัวอื่นที่ค้างในบัฟเฟอร์
        return False
    if resp[1] not in (0x03, 0x83):   # 0x83 = ตอบว่า error ก็ยังนับว่ามีตัวตน
        return False
    body, got = resp[:-2], resp[-2:]
    return crc16(body) == got         # ด่านสุดท้ายที่กันของหลอนได้จริง
timeout สั้นเกินก็หาไม่เจอ

อุปกรณ์บางตัวตอบช้ามาก โดยเฉพาะคอนโทรลเลอร์ที่มีงานอื่นทำอยู่ ตอนกวาดหยาบผมตั้ง timeout ไว้ 0.35 วินาทีเพื่อความเร็ว แต่ตอนกวาดละเอียดผมขยายเป็น 5 วินาที แล้วเจออุปกรณ์เพิ่มที่รอบแรกไม่เจอ ถ้ากวาดรอบแรกแล้วเงียบ อย่าเพิ่งสรุปว่าไม่มีของ ให้ลองขยาย timeout อีกรอบก่อน

เจอแล้วหนึ่งตัว มี 74 register แต่ยังไม่รู้ว่ามันคืออะไร

พอกวาดสะอาดแล้วผลจริงคือบนบัสมีอุปกรณ์ตอบอยู่ตัวเดียว ที่ address 20 อ่านได้ประมาณ 74 register ค่าบางตัวขยับตลอดเวลา บางตัวนิ่งสนิท ถึงตรงนี้หลายคน (รวมผม) จะเริ่มเดาจากรูปแบบของตัวเลขทันที ซึ่งเป็นจุดที่ผมพลาด

ผมเห็นบล็อกหนึ่งที่มี 16 ค่าเรียงติดกัน หกถึงแปดตัวในนั้นนิ่งเป็นค่าเดียวตลอด ที่เหลือขยับ ผมสรุปเองเลยว่านี่คือช่องวัดอุณหภูมิ 16 ช่อง ที่นิ่งคือช่องที่ค่าค้างอยู่ในแคชของตัวคอนโทรลเลอร์ แล้วสร้างสมมุติฐานต่อยอดอีกสามรอบว่าจะปลุกค่าที่ค้างยังไง ลองรีสตาร์ทอุปกรณ์ ลองอ่านด้วยจังหวะอื่น ลองอ่านเป็นบล็อกใหญ่บ้างเล็กบ้าง เสียเวลาไปหลายสัปดาห์

ที่ผมคิดตอนนั้น

เป็นคอนโทรลเลอร์รวมศูนย์

16 ค่าเรียงกัน = ช่องอุณหภูมิ 16 ช่อง ที่นิ่งคือแคชค้าง ต้องหาวิธีปลุก สมมุติฐานทุกอันที่ต่อยอดจากตรงนี้ตั้งอยู่บนการเดาชนิดอุปกรณ์ล้วนๆ

ความจริงที่เจอทีหลัง

เป็นโมดูลวัดกระแส 16 ช่อง

16 ค่านั้นคือช่องวัดกระแสไฟ 16 ช่อง ที่นิ่งคือช่องที่ไม่ได้ต่อหัววัดเข้าไป มันอ่านได้ศูนย์ถูกต้องอยู่แล้ว ไม่มีอะไรเสีย ไม่มีอะไรต้องปลุก และอุปกรณ์ตัวนี้ไม่เคยมีค่าอุณหภูมิอยู่ในตัวเลย

พิสูจน์ว่า register ตัวไหนตายจริง ด้วยข้อมูลไม่ใช่ความรู้สึก

ก่อนจะไปถึงข้อสรุปข้างบน ผมเปลี่ยนวิธีจากการเดาเป็นการเก็บสถิติ ตัวอ่านของผมเก็บค่าดิบทุก register ลงฐานข้อมูลอยู่แล้วทุกวินาที พอสะสมได้หลายหมื่นแถวก็เอามาถามคำถามง่ายๆ ว่า "ตลอดช่วงเวลาที่ผ่านมา register ตัวนี้เคยมีค่ากี่ค่าที่ต่างกัน"

-- ตัวไหน distinct = 1 คือไม่เคยเปลี่ยนเลยตลอด 57,000 ตัวอย่าง
SELECT reg_index,
       COUNT(*)                 AS samples,
       COUNT(DISTINCT reg_value) AS distinct_values,
       MIN(reg_value)           AS min_v,
       MAX(reg_value)           AS max_v
FROM   raw_register_samples
WHERE  slave = 20
  AND  ts_unix >= UNIX_TIMESTAMP() - 86400 * 7
GROUP  BY reg_index
ORDER  BY distinct_values ASC, reg_index;

ผลที่ได้ตัดข้อถกเถียงจบเลย register หกตัวในบล็อกนั้นมี distinct_values = 1 จากตัวอย่าง 57,000 ครั้ง ตลอดเจ็ดวัน คือตลอดทั้งสัปดาห์ ผ่านทั้งช่วงเครื่องเดิน เครื่องหยุด ทั้งกลางวันกลางคืน มันไม่เคยขยับแม้แต่หน่วยเดียว ค่าที่นิ่งขนาดนั้นไม่ใช่ "แคชค้าง" เพราะแคชค้างจะค้างที่ค่าสุดท้ายที่เคยมีค่า ซึ่งควรเป็นตัวเลขมั่วๆ สักค่า แต่นี่มันนิ่งที่ศูนย์เป๊ะ แปลว่าช่องนั้นไม่มีอะไรต่ออยู่ต่างหาก

ตัวช่วยที่ผมเขียนไว้ใช้ซ้ำคือสรุปโปรไฟล์ของ register ทั้งชุดออกมาเป็นตารางเดียว ดูรอบเดียวรู้เลยว่าตัวไหนน่าสนใจ ตัวไหนตัดทิ้งได้

def profile(rows_by_reg: dict[int, list[int]]):
    """rows_by_reg = {หมายเลข register: [ค่าที่อ่านได้ตามเวลา]}"""
    print(f"{'reg':>4} {'n':>7} {'distinct':>9} {'min':>8} {'max':>8}  หมายเหตุ")
    for reg, vals in sorted(rows_by_reg.items()):
        d = len(set(vals))
        note = ("ไม่เคยเปลี่ยน - ตายหรือไม่ได้ต่อ" if d == 1 else
                "สองสถานะ - น่าจะเป็นสถานะเปิดปิด" if d == 2 else
                "ค่าต่อเนื่อง - น่าจะเป็นค่าวัด")
        print(f"{reg:>4} {len(vals):>7} {d:>9} {min(vals):>8} {max(vals):>8}  {note}")
สถิติง่ายๆ ที่ควรทำก่อนตีความ register

เก็บค่าดิบสักสองสามวันแล้วนับสามตัวเลขต่อ register คือ จำนวนค่าที่ต่างกัน (distinct=1 คือตายหรือไม่ได้ต่อ), ช่วงต่ำสุดถึงสูงสุด (บอกสเกลว่าน่าจะหารสิบหรือหารร้อย) และ ความถี่ในการเปลี่ยน (ค่าที่ขยับทุกวินาทีกับค่าที่ขยับวันละครั้งคนละประเภทกัน) สามตัวนี้ตัดสมมุติฐานผิดๆ ออกได้เกินครึ่งโดยไม่ต้องเดาเลย

สุดท้ายคำตอบอยู่ที่ป้ายบนตัวเครื่อง

สิ่งที่ปิดเคสนี้ไม่ใช่สคริปต์ที่ผมเขียน แต่เป็นการเดินไปเปิดตู้แล้วถ่ายรูปป้ายบนตัวโมดูลมาดู ตรงนั้นเขียนสเปกไว้ครบว่ามันคือโมดูลเก็บค่ากระแสไฟ 16 ช่อง กินไฟ DC ช่วงหนึ่ง สื่อสารด้วย RS485 พอได้ชื่อรุ่นแล้วไปค้นต่อ เจอโครงการโอเพนซอร์สที่คนอื่นเขียนตัวอ่านของตระกูลนี้ไว้แล้ว มี register map ให้เทียบ ทุกอย่างลงล็อกภายในชั่วโมงเดียว

ผลพวงของการรู้ตัวจริงคือสมมุติฐานเก่าล้มทั้งชุด ค่าอุณหภูมิที่ผมตามหาอยู่ ไม่เคยอยู่บนอุปกรณ์ตัวนี้ มันมาจากคอนโทรลเลอร์คนละตัวที่อยู่บนบัสเดียวกัน แต่สาย A/B ของมันหลุดออกไปตั้งแต่ก่อนผมมารับงาน พอต่อกลับเข้าไปแล้วกวาดใหม่ที่ 19200 ก็เจออุปกรณ์เพิ่มอีกสองตัวที่ address 1 กับ 2 ทันที แต่ละตัวมีค่าอุณหภูมิสองจุด รวมเป็นสี่จุดพอดีกับที่ระบบเดิมเคยแสดง

โครงบัสจริงหลังต่อสายกลับเกตเวย์RS485 เป็น TCP->addr 20วัดกระแส 16 ช่อง->addr 1อุณหภูมิ 2 จุด->addr 2อุณหภูมิ 2 จุด
# ตัวอ่านหลังรู้ตัวจริงแล้ว: แยกจังหวะการอ่านตามชนิดอุปกรณ์
SLAVES = [
    # (ที่อยู่, ช่วง register ที่ต้องอ่าน, อ่านทุกกี่วินาที)
    (20, [(0, 56), (109, 18)], 1),   # กระแส: ต้องทุก 1 วิ เพราะเอาไปคิดพลังงาน
    (1,  [(0, 2)],             5),   # อุณหภูมิ: ตอบช้าและเปลี่ยนช้า อ่านถี่ไม่มีประโยชน์
    (2,  [(0, 2)],             5),
]

for cycle in itertools.count(1):
    for slave, ranges, every in SLAVES:
        if (cycle - 1) % every:
            continue                  # ยังไม่ถึงรอบของตัวนี้
        for start, count in ranges:
            regs = read_holding(slave, start, count)   # FC03 เท่านั้น
            store(slave, start, regs)
    time.sleep(1)
ยังไม่รู้ว่าเซ็นเซอร์ตัวไหนอยู่ตำแหน่งไหน ก็อย่าเพิ่งตั้งชื่อ

ตอนเจออุปกรณ์วัดอุณหภูมิสองตัวใหม่ๆ ผมยังไม่รู้ว่าหัววัดแต่ละเส้นไปฝังอยู่จุดไหนในห้อง ผมเลยตั้งชื่อบนหน้าจอเป็นเลขกลางๆ ว่าจุดที่ 1 ถึง 4 พร้อมกำกับที่มาแบบ addr·reg ไว้ให้ไล่ย้อนได้ ไม่ตั้งชื่อว่า "กลางห้อง" หรือ "ที่คอยล์" จนกว่าจะเดินไปจับสายยืนยันจริง เพราะป้ายชื่อที่เดาเอาจะกลายเป็นความจริงในหัวคนอ่านทันทีที่ขึ้นจอ แล้วไม่มีใครกลับมาตรวจอีกเลย

เช็กลิสต์ที่ผมใช้กับอุปกรณ์ไม่รู้จักตัวถัดไป

  1. ตั้งกติกา read-only ก่อนเขียนโค้ดบรรทัดแรก ใส่แบนเนอร์ในสคริปต์ แล้ว grep หาคำสั่งเขียนก่อนรันทุกครั้ง
  2. กวาดหยาบหาชุด baud/parity/databits ที่มีคนตอบก่อน แล้วค่อยกวาด address ให้ครบบนชุดนั้น
  3. ตัวกวาดต้องตรวจไบต์ที่อยู่ ไบต์ฟังก์ชัน และ CRC ครบสามชั้น ไม่งั้นได้ที่อยู่ปลอมมาเป็นพวง
  4. กวาดรอบสองด้วย timeout ยาวขึ้น เผื่ออุปกรณ์ที่ตอบช้า
  5. เก็บค่าดิบทุก register ลงฐานข้อมูลสักสองสามวันก่อนตีความอะไรทั้งนั้น
  6. นับ distinct, ช่วงค่า, และความถี่การเปลี่ยน เพื่อคัดตัวที่ตายออกด้วยข้อมูล
  7. เดินไปถ่ายรูปป้ายที่ตัวเครื่อง อันนี้ควรทำเป็นข้อแรกด้วยซ้ำถ้าเข้าถึงตู้ได้
  8. ได้ชื่อรุ่นแล้วค้นหาตัวอ่านโอเพนซอร์สของตระกูลเดียวกัน มักมีคนถอด map ไว้แล้ว

บทเรียนจริงของงานนี้สำหรับผมคือ ข้อมูลที่ได้จากบัสบอกได้แค่ว่า รูปแบบของตัวเลขเป็นยังไง มันไม่มีวันบอกว่าตัวเลขนั้นหมายถึงอะไร การเดาชนิดอุปกรณ์จากรูปแบบตัวเลขเป็นสมมุติฐานที่ฟังดูสมเหตุสมผลมากจนเราลืมว่ามันเป็นแค่สมมุติฐาน แล้วต่อยอดไปอีกสามชั้นโดยไม่กลับมาตรวจฐาน ส่วนตัวผมตอนนี้ถือว่าถ้ายังไม่ได้เห็นป้ายที่ตัวเครื่องหรือเอกสารจากผู้ผลิต ทุกการตีความ register ให้ติดป้ายว่า "ยังไม่ยืนยัน" ไว้ก่อนทั้งหมด ใครเจอเคสที่บัสมีของตอบเยอะผิดปกติ ลองไปเช็กเรื่อง CRC ในตัวกวาดก่อนเลยครับ ผมว่าเจอเหมือนกัน ตรงไหนผมเล่าข้ามหรือมีอุปกรณ์ที่พฤติกรรมไม่เหมือนนี้ เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย