software-defined

Software-Defined Test là gì? Kiến trúc 4 tầng HAL và MAL

By maianh@tecotec.com.vn

Key Summary

  • Software-Defined Test (SDT) là mô hình đo kiểm trong đó chức năng đo, quy tắc đánh giá và logic xử lý tín hiệu nằm trong phần mềm, còn phần cứng chủ yếu thu nhận tín hiệu thô.
  • Hai lớp trừu tượng, HAL (phần cứng) và MAL (phép đo), cách ly kịch bản kiểm thử khỏi lệnh điều khiển của từng thiết bị, nên đổi thiết bị đo ít phải sửa mã nghiệp vụ.
  • Chuẩn mở VISA, IVI, SCPI cùng Python giúp giảm chi phí bản quyền và sự phụ thuộc vào một nhà cung cấp.

Một máy hiện sóng chạy suốt mười năm trên dây chuyền bỗng hỏng nguồn. Hãng đã ngừng sản xuất, nhà máy mua model mới, và chương trình kiểm tra tự động ngừng chạy vì không hiểu lệnh của máy mới. Kịch bản kiểm tra gắn chặt vào tập lệnh của một hãng, nên đổi thiết bị đồng nghĩa với viết lại phần mềm. Tình trạng này gọi là Vendor Lock-in.

Để khắc phục vendor lock in trong hệ thống đo, câu hỏi đầu tiên là software-defined test là gì: đó là kiến trúc kiểm thử mà chức năng đo được định nghĩa bằng phần mềm (Software-Defined Test, SDT) thay vì bị gắn vào phần cứng chuyên dụng. Bài này của TECOTEC Technologies giải thích mô hình 4 tầng tham chiếu kèm mã Python mẫu cho tầng HAL.

Software-Defined Test là gì? Khác biệt với thiết bị đo truyền thống

SDT là cách thiết kế trạm đo trong đó phép tính đo lường và quy tắc đánh giá chất lượng chạy trên phần mềm của máy tính chủ. Phần cứng chủ yếu thu nhận và số hóa tín hiệu thô tốc độ cao. Trạm có thể đổi bài đo bằng cập nhật phần mềm hoặc tệp cấu hình, trong giới hạn năng lực của các mô-đun đã lắp.

Không nhầm SDT với kiểm thử phần mềm (Software Testing) trong công nghệ thông tin: SDT dùng phần mềm để điều khiển thiết bị vật lý, thu tín hiệu thực và quyết định Đạt hoặc Hỏng (Pass/Fail) theo ngưỡng đo.

Tiêu chí Thiết bị độc lập (truyền thống) Software-Defined Test
Bản chất Màn hình, phím bấm và vi xử lý nhúng đóng kín trong một vỏ máy. Khung máy mô-đun hoặc tủ thiết bị chuẩn, điều phối bằng phần mềm trên máy tính chủ.
Tính linh hoạt Chức năng đo cố định theo thông số xuất xưởng. Đổi bài đo bằng cập nhật kịch bản và thuật toán.
Lỗi thời và phụ thuộc Rủi ro cao khi hãng ngừng hỗ trợ (End-of-Life); bị trói vào phần mềm và driver của một hãng. Rủi ro lỗi thời thấp hơn đáng kể nhờ hoán đổi mô-đun tương đương; giảm phụ thuộc nhờ chuẩn mở VISA, IVI, SCPI.

Khắc phục Vendor Lock-in trong hệ thống đo: ba cái bẫy của hệ sinh thái đóng

Khi phần cứng, driver và môi trường phát triển đều thuộc một hãng, chi phí mở rộng trạm đo khó kiểm soát. Có ba cái bẫy thường gặp.

Chi phí bản quyền định kỳ. Một số nền tảng phần mềm độc quyền có thể tính phí giấy phép hoặc phí duy trì cho máy tính phát triển và, tùy chính sách của hãng, cả máy tính vận hành. Với hàng chục trạm kiểm tra chức năng (FCT), khoản phí này đáng kể.

Thiết bị ngừng sản xuất. Hãng thiết bị thương mại thường khai tử sản phẩm (End-of-Life) sau vài năm. Nếu mã nguồn đã hard-coded vào thư viện của hãng, thay bằng thiết bị hãng khác buộc phải viết lại.

Dữ liệu đo bị đóng kín. Nhiều phần mềm đóng lưu kết quả trong tệp nhị phân kín, khiến dữ liệu khó nối sang hệ thống điều hành sản xuất (MES) hay phần mềm SPC.

Kiến trúc software-defined test 4 tầng: tách logic khỏi phần cứng

Nguyên lý cốt lõi là tách quy trình kiểm tra khỏi lệnh điều khiển phần cứng cụ thể. Mô hình tham chiếu gồm 4 tầng độc lập; yêu cầu đo đi từ trên xuống, kết quả đi ngược lên:

Sơ đồ 4 tầng Software-Defined Test: Sequencer, MAL, HAL và driver vật lý. Tệp cấu hình JSON hoặc YAML chọn driver, nên đổi thiết bị đo chỉ sửa ở tầng 4.

Hình 1. Kiến trúc 4 tầng Software-Defined Test: yêu cầu đo đi xuống, kết quả đi lên, và tệp cấu hình chọn driver ở tầng HAL.

Tầng 1: Quản lý kịch bản kiểm thử (Test Management / Sequencer)

Tầng này điều phối trình tự các bước kiểm tra, giao diện vận hành, phân quyền người dùng và báo cáo kết quả. Vì độc lập với phần cứng, một kịch bản có thể dùng lại trên nhiều tủ rack đo kiểm tự động ATE khác nhau.

Tầng 2: Trừu tượng hóa phép đo (Measurement Abstraction Layer – MAL)

MAL chuyển bước kiểm tra nghiệp vụ thành phép đo vật lý cụ thể, ví dụ đo điện áp một chiều, thời gian tăng của xung hoặc độ méo hài tổng. Thuật toán xử lý được đóng gói thành hàm giao diện chuẩn, nên khi chỉnh giải thuật hay bộ lọc số, chỉ tầng MAL thay đổi.

Tầng 3: Trừu tượng hóa phần cứng (Hardware Abstraction Layer – HAL)

HAL là mắt xích quyết định khả năng hoán đổi thiết bị. Tầng này định nghĩa một giao diện lập trình (API) thống nhất cho từng nhóm thiết bị như bộ nguồn DC, đồng hồ vạn năng (DMM) hay máy hiện sóng. Kết hợp mô hình Factory Pattern, khi thay máy hiện sóng của hãng này bằng máy hãng khác, kỹ sư chỉ cần đổi tên driver và chuỗi tài nguyên VISA trong tệp cấu hình JSON hoặc YAML. Với các phép đo mà HAL đã định nghĩa, kịch bản và thuật toán MAL ở tầng trên không phải sửa.

Tầng 4: Giao tiếp vật lý và Instrument Driver (Physical Drivers Layer)

Tầng này dịch yêu cầu từ HAL thành chuỗi lệnh đúng với từng model thiết bị, rồi truyền qua các bus như LAN/LXI, USBTMC, GPIB hoặc PXIe. Nó dựa trên kiến trúc phần mềm đo lường ảo VISA (Virtual Instrument Software Architecture) [4], chuẩn driver hoán đổi IVI (Interchangeable Virtual Instruments) [1] và tập lệnh SCPI (Standard Commands for Programmable Instruments). SCPI là đặc tả SCPI-99 do IVI Foundation duy trì, xây dựng trên cú pháp của IEEE 488.2 [3].

Tại hiện trường, driver còn phải xử lý các chi tiết truyền thông. Với kết nối nối tiếp (ASRL), cần cấu hình đúng ký tự kết thúc dòng (ví dụ CRLF, \r\n), nếu không thao tác đọc thường hết thời gian chờ (timeout). Driver cũng giữ nhịp đọc ghi để tránh lỗi -410 (Query INTERRUPTED) và đóng phiên VISA sau khi dùng.

Lập trình điều khiển thiết bị đo Python, LabVIEW: mã mẫu cho Tầng HAL

Các môi trường lập trình đồ họa như LabVIEW rất trực quan, nhưng chương trình thường lưu dạng tệp nhị phân nên việc so sánh thay đổi (diff) trên Git khó hơn mã văn bản. Python kết hợp thư viện mã nguồn mở PyVISA là một lựa chọn phổ biến của các kỹ sư kiến trúc kiểm thử [2], và hợp với mô hình lập trình hướng đối tượng của HAL.

Đoạn mã dưới đây minh họa Tầng HAL với Factory Pattern và một thiết bị giả lập (Mock Instrument):

# Tầng Trừu Tượng Phần Cứng (HAL) bằng Python với Factory Pattern
from abc import ABC, abstractmethod
import pyvisa

class OscilloscopeHAL(ABC):
    """Giao diện cơ sở cho mọi máy hiện sóng trong hệ thống"""
    @abstractmethod
    def connect(self) -> None: ...
    @abstractmethod
    def measure_peak_to_peak(self, channel: int = 1) -> float: ...
    @abstractmethod
    def close(self) -> None: ...

class VisaScope(OscilloscopeHAL):
    """Phần dùng chung cho máy hiện sóng điều khiển qua VISA"""
    def __init__(self, resource_string: str):
        self.resource_string = resource_string
        self.inst = None

    def connect(self) -> None:
        self.inst = pyvisa.ResourceManager().open_resource(self.resource_string)
        self.inst.timeout = 5000
        self.inst.read_termination = '\n'
        self.inst.write_termination = '\n'

    def close(self) -> None:
        if self.inst:
            self.inst.close()

class VendorAScopeDriver(VisaScope):
    """Driver minh họa cho dòng máy hiện sóng của hãng A"""
    def measure_peak_to_peak(self, channel: int = 1) -> float:
        return float(self.inst.query(f":MEASure:VPP? CHANnel{channel}"))

class VendorBScopeDriver(VisaScope):
    """Driver minh họa cho dòng máy hiện sóng của hãng B"""
    def measure_peak_to_peak(self, channel: int = 1) -> float:
        self.inst.write(f"MEASU:IMM:SOURCE CH{channel}")
        self.inst.write("MEASU:IMM:TYPE PK2PK")
        return float(self.inst.query("MEASU:IMM:VAL?"))

class MockScopeDriver(OscilloscopeHAL):
    """Thiết bị giả lập để chạy kịch bản không cần máy đo thật"""
    def __init__(self, resource_string: str = "MOCK::INSTR"):
        pass

    def connect(self) -> None: ...
    def close(self) -> None: ...

    def measure_peak_to_peak(self, channel: int = 1) -> float:
        return 0.035  # giá trị danh định cố định, 0.035 V

class ScopeFactory:
    """Nạp driver theo tệp cấu hình dây chuyền"""
    @staticmethod
    def create_scope(driver_type: str, resource_string: str) -> OscilloscopeHAL:
        drivers = {
            "vendor_a": VendorAScopeDriver,
            "vendor_b": VendorBScopeDriver,
            "mock": MockScopeDriver,
        }
        driver_cls = drivers.get(driver_type.lower())
        if not driver_cls:
            raise ValueError(f"Không hỗ trợ loại driver: {driver_type}")
        return driver_cls(resource_string)

# Tầng Sequencer, độc lập với phần cứng:
def test_power_ripple(scope: OscilloscopeHAL) -> None:
    """Kiểm tra độ gợn điện áp nguồn DC tại công đoạn FCT"""
    scope.connect()
    try:
        vpp = scope.measure_peak_to_peak(channel=1)
        limit_vpp = 0.050  # ngưỡng tối đa 50 mV
        assert vpp < limit_vpp, f"Độ gợn vượt ngưỡng: {vpp:.4f} V (giới hạn {limit_vpp} V)"
        print(f"Đạt: Vpp = {vpp:.4f} V")
    finally:
        scope.close()

Driver được nạp từ tệp cấu hình, ví dụ station.json chứa tên driver và chuỗi tài nguyên VISA:

import json

# station.json: {"driver_type": "vendor_a", "resource_string": "TCPIP0::192.168.1.20::INSTR"}
with open("station.json", encoding="utf-8") as f:
    cfg = json.load(f)

scope = ScopeFactory.create_scope(cfg["driver_type"], cfg["resource_string"])
test_power_ripple(scope)

Hàm test_power_ripple chỉ tương tác với giao diện OscilloscopeHAL, không biết thiết bị bên dưới của hãng nào. Lệnh assert ở đây chỉ để minh họa; trạm thực tế nên trả kết quả Đạt hoặc Hỏng thay vì dựa vào assert, vì Python bỏ qua assert khi chạy với tùy chọn -O. Khi đổi thiết bị, kỹ sư chỉ sửa cấu hình, còn logic kiểm tra và tiêu chuẩn đánh giá giữ nguyên. Chi phí viết driver cho thiết bị mới vẫn còn, nhưng gói gọn trong một lớp. Lớp MockScopeDriver còn cho phép chạy cả luồng kịch bản trên máy tính cá nhân, không cần chiếm tủ rack ngoài xưởng.

Câu hỏi thường gặp về Software-Defined Test

Lập trình hệ thống đo kiểm bằng Python có đủ nhanh và ổn định trong môi trường nhà máy không?

Python đáp ứng được khi dùng đúng vai trò điều phối ở tầng sequencer. VISA lo truyền nhận với thiết bị, phần sụn hoặc FPGA của thiết bị đo thu nhận tín hiệu thô, còn phép tính số nặng dùng thư viện đã biên dịch như NumPy.

Chuẩn lệnh SCPI có hoàn toàn đồng nhất giữa tất cả các hãng sản xuất thiết bị đo không?

Không hoàn toàn. Các lệnh chung bắt buộc của IEEE 488.2 như truy vấn danh tính thiết bị (*IDN?) hay đặt lại trạng thái (*RST) giống nhau giữa các hãng [3]. Với tính năng đo nâng cao, mỗi hãng có cú pháp mở rộng riêng, nên tầng HAL bọc chúng vào một giao diện duy nhất.

Làm thế nào để lưu trữ dữ liệu đo từ kiến trúc Software-Defined Test phục vụ phân tích SPC?

Dữ liệu đo nằm dưới dạng số trong bộ nhớ máy tính chủ, nên có thể ghi vào cơ sở dữ liệu SQL hoặc xuất ra JSON/CSV theo thời gian thực, rồi đưa thẳng vào phần mềm SPC. Giải pháp T3-Suite SPC của TECOTEC Technologies được thiết kế để khai thác nguồn dữ liệu này nhằm phát hiện sớm hiện tượng trôi dạt thông số.

Từ Software-Defined Test đến kiểm soát quá trình bằng thống kê (SPC)

Khi trạm SDT vận hành ổn định và thu dữ liệu liên tục, bước tiếp theo là Kiểm soát Quá trình bằng Thống kê (Statistical Process Control – SPC), dùng dữ liệu đo để phát hiện xu hướng lỗi trước khi khuyết tật xuất hiện. Nền tảng đo lường của bước này nằm ở việc bù sai số chuẩn đo lường bằng phần mềm.

Các tài liệu liên quan

Nguồn tham khảo

  1. IVI Foundation. IVI-3.1: Driver Architecture Specification (và các đặc tả IVI, VPP, SCPI-99 liệt kê tại trang đặc tả). https://www.ivifoundation.org/specifications/default.aspx/
  2. PyVISA Authors. PyVISA: Python Bindings for Virtual Instrument Software Architecture (VISA), Documentation Release 1.14. https://pyvisa.readthedocs.io/en/1.14.0/
  3. IEEE (1992). IEEE Std 488.2-1992: IEEE Standard Codes, Formats, Protocols, and Common Commands for Use with IEEE Std 488.1-1987. https://standards.ieee.org/ieee/488.2/718/
  4. VXIplug&play Systems Alliance. VPP-4.3: The VISA Library, do IVI Foundation lưu trữ. https://www.ivifoundation.org/specifications/default.aspx/