2 điểm bởi GN⁺ 2024-11-12 | 1 bình luận | Chia sẻ qua WhatsApp
  • Là bước đầu tiên để tự xây dựng trực tiếp một TCP/IP stack trên vi điều khiển, tác giả đã thử truyền Ethernet frame bằng cách kết nối STM32F401 Nucleo với shield Wiznet W5100
  • Không dùng chức năng TCP/IP phần cứng của W5100 mà chỉ dùng chế độ MAC Raw, giao cho chip chỉ phần xử lý mức thấp cần thiết cho việc truyền frame
  • Trục trặc đầu tiên bắt đầu từ việc dây SPI của Arduino Ethernet shield không khớp với Nucleo, và đã được giải quyết bằng cách kiểm tra routing của header ICSP rồi chỉnh lại dây trên bo mạch
  • Sau đó, trong quá trình xử lý phản hồi MISO bất thường có vẻ liên quan đến vấn đề timing của chip select và các gói rác xuất hiện trên Wireshark, logic analyser cùng việc đối chiếu với implementation chuẩn trở thành công cụ debug then chốt
  • Nguyên nhân cuối cùng là bug trong w5100_write16() khi ghi lại byte thứ hai vào cùng một địa chỉ, và nhờ tạo công cụ phân tích CSV capture SPI mà tác giả đã truyền được gói tin bình thường

Điểm khởi đầu để tự xây dựng TCP/IP stack

  • Mục tiêu là bắt đầu series “Networking from scratch”, tức triển khai TCP/IP stack từ nền tảng thấp nhất trên vi điều khiển
  • Kết quả bề ngoài ở bước này là truyền được gói Ethernet đầu tiên, nhưng trọng tâm thực sự nằm ở quá trình lần theo các bug phát sinh giữa phần cứng và driver
  • Bo mạch được dùng là board phát triển Nucleo dựa trên STM32F401
    • ARM Cortex-M4
    • chạy tối đa 84MHz
    • 96KiB RAM
    • được đánh giá là đủ bộ nhớ để giữ nhiều gói tin

Vai trò của Ethernet và W5100

  • Ethernet không chỉ là một cổng hay định dạng frame đơn giản, mà là một hệ công nghệ và tiêu chuẩn bao gồm phần cứng tầng vật lý, cách phát tín hiệu, xử lý xung đột trên bus và cả cách bố trí frame
  • Việc xử lý tín hiệu Ethernet khá phức tạp, nên thường có ASIC chuyên dụng nhận dữ liệu ở mức frame và đảm nhiệm xử lý tín hiệu điện trên cáp
  • Dự án dùng Arduino Ethernet shield chứa chip Wiznet W5100
    • Bo mạch được dùng là bản clone giá rẻ nên cần chỉnh sửa để hoạt động bình thường
  • W5100 là chip Ethernet ASIC có tích hợp TCP/IP stack phần cứng
    • cung cấp 4 “socket”
    • có thể cấu hình ở mức TCP, UDP, IP và “MAC Raw”
  • Vì mục tiêu là tự triển khai TCP/IP stack, tác giả không dùng chức năng TCP/IP của W5100 mà chỉ dùng một socket ở chế độ MAC Raw
    • người dùng đưa vào Ethernet frame
    • W5100 thực hiện việc truyền thực tế
    • preamble và start-of-frame marker là thành phần ở mức điện nên chip xử lý
    • CRC 32-bit cũng do W5100 tính

Vấn đề 1: Tín hiệu SPI không tới được W5100

  • Trao đổi dữ liệu với W5100 diễn ra qua SPI
    • MOSI: đầu ra từ vi điều khiển là chip chính
    • MISO: đầu ra từ W5100
    • clock: xung nhịp tham chiếu cho dữ liệu
    • chip select: tín hiệu báo đang giao tiếp với chip phụ thuộc
  • Datasheet của W5100 định nghĩa một giao thức lệnh 4 byte chạy trên SPI
    • 1 byte operation
    • 2 byte địa chỉ 16-bit big-endian
    • 1 byte value
  • operation là ghi 0xf0 hoặc đọc 0x0f
    • các giá trị khác không hợp lệ và phải bị bỏ qua
  • W5100 trả lại các giá trị đã biết qua MISO mỗi khi clock out một byte, nên khá dễ phát hiện giao tiếp bất thường
    • với lệnh đọc, byte thứ 4 sẽ là giá trị đọc từ địa chỉ được chỉ định
  • Ban đầu, dù gửi lệnh qua MOSI thì trên MISO chỉ thấy các giá trị rác
  • Nguyên nhân là Arduino Ethernet shield được thiết kế route tín hiệu SPI không qua header chuẩn của Arduino mà qua header 6 chân ICSP
    • bo Arduino chính thức nối sẵn tín hiệu SPI giữa ICSP và header chuẩn nên không có vấn đề
    • Nucleo không có header ICSP, nên tín hiệu SPI gửi đi không tới được W5100
  • Tác giả dùng đồng hồ đo để đo điện trở giữa rail nguồn và các tín hiệu SPI, từ đó xác nhận vấn đề kết nối
    • điện trở vô hạn cho thấy đường dây đang bị đứt
  • Sau đó hàn trực tiếp tín hiệu giữa Nucleo và W5100 bằng thiếc và dây đồng bọc men

Vấn đề 2: Timing chip select và phản hồi MISO bất thường

  • Sau khi tín hiệu SPI thực sự được nối đúng, việc giao tiếp với W5100 đã hoạt động và tác giả triển khai tiếp đến các bước sau
    • cấu hình W5100 cho truyền Ethernet thô
    • cấu hình MAC address
    • cấu hình các segment bộ nhớ TX/RX
    • ghi Ethernet frame thử nghiệm vào bộ nhớ TX và kích hoạt truyền
  • Tác giả nối Nucleo và shield với laptop bằng cáp CAT5 rồi chạy Wireshark, nhưng không thấy gói nào
  • Các vấn đề mức thấp rất khó lần theo vì không có thông báo lỗi hay stack trace, mà chỉ là kiểu “đã làm rung các electron nhưng điều mong đợi không xảy ra”
  • Công cụ dùng để debug là logic analyser
    • nó lấy mẫu các chuyển đổi high/low của tín hiệu số trên nhiều kênh
    • phần mềm có thể diễn giải các nhóm tín hiệu như SPI bus và hiển thị byte của transaction
    • cũng có thể xuất ra định dạng có cấu trúc như CSV
  • Thiết bị được dùng là Saleae Logic 8
    • các analyser giá rẻ cỡ khoảng €10 cũng có thể dùng với Saleae Logic2, nhưng có đánh đổi về độ ổn định và tính nhất quán khi hoạt động
  • Lệnh SPI đầu tiên trông có vẻ bình thường
    • 0xf0 0x00 0x00 0x80
    • đặt bit cao nhất trong Mode Register ở địa chỉ 0x0000 để kích hoạt software reset
    • MISO phản hồi bình thường từ 0x00 đến 0x03
  • Ở lệnh đọc tiếp theo thì xuất hiện phản hồi bất thường
    • MOSI: 0x0f 0x00 0x00 0x00
    • MISO: 0x03 0xff 0xff 0xff
  • 0x03 là giá trị cuối của transaction trước đó, tác giả nghi ngờ có vấn đề với trạng thái nội bộ hoặc timing của W5100
  • Xung SPI đang chạy thấp hơn rất nhiều so với mức tối đa khoảng 14MHz trong datasheet, nên không được xem là nguyên nhân
  • Thay vào đó, tác giả cho rằng chip select bị kéo lên high quá nhanh khiến chip rơi vào trạng thái xấu, nên thêm độ trễ vài micro giây trước khi đổi trạng thái
    • sau đó phản hồi MISO trở lại bình thường
    • đọc lại các giá trị cấu hình cũng cho kết quả hợp lý
  • Nguyên nhân chính xác của vấn đề này vẫn chưa được làm rõ hoàn toàn
    • ràng buộc liên quan đến chip select trong sơ đồ timing SPI ở trang 66 của datasheet vẫn được đáp ứng
    • có thể sẽ điều tra lại điều kiện biên chính xác sau, nhưng hiện tại ưu tiên là tiếp tục dự án

Vấn đề 3: Gói rác xuất hiện trên Wireshark

  • Khi chạy lại Wireshark, gói tin đã xuất hiện nhưng không phải gói mong muốn
  • Đúng lúc vi điều khiển phát lệnh truyền, một gói Ethernet thô lớn hơn nhiều so với dữ liệu ban đầu xuất hiện và chứa đầy dữ liệu rác
  • Tác giả bỏ kế hoạch chỉ dựa vào datasheet và spec để tự triển khai, và ở giai đoạn này quyết định so sánh với một implementation đã được xác nhận hoạt động
  • Arduino rất hữu ích để nhanh chóng tạo ra implementation chuẩn đối chiếu
    • chỉ với Arduino, thư viện và khoảng 5 dòng code là có thể xác minh những hành vi phức tạp
  • Việc tìm thư viện truyền raw Ethernet packet lại tốn nhiều thời gian hơn
    • đa số người dùng Arduino không cố gắng tự triển khai chức năng mạng từ đầu
    • thư viện chính thức đã bỏ hỗ trợ truyền raw packet khỏi public API
  • Cuối cùng tác giả tìm được dự án GitHub W5100MacRaw có thể gửi nhận packet ở mức tối thiểu
  • Sau khi so sánh source đó với implementation của mình, các khác biệt nhìn thấy ngay vẫn chưa mang tính quyết định
    • thứ tự register read/write khác nhau
    • có các thao tác read/write chỉ xuất hiện ở một phía
    • thông thường nếu thứ tự là yếu tố phụ thuộc thì datasheet sẽ nêu rõ
  • Ngay cả khi chỉnh thứ tự read/write cho giống implementation chuẩn, Wireshark vẫn tiếp tục hiển thị gói rác

Bug thực sự lộ ra nhờ một công cụ nhỏ

  • Chiến lược tiếp theo là viết công cụ parse CSV capture SPI từ Saleae Logic2 rồi hiển thị lại dưới dạng danh sách register read/write
  • Công cụ được viết bằng Python và dài hơn 200 dòng một chút
    • phần lớn là tên register và địa chỉ được chép từ datasheet
    • mất khoảng 1 giờ để viết
    • tác giả cũng thêm phần argument parsing để đầu vào và đầu ra rõ ràng hơn
  • Sau đó tác giả lấy SPI capture từ implementation chuẩn trên Arduino và từ implementation của mình, xuất cả hai ra CSV, xử lý bằng công cụ rồi chạy diff
  • Vấn đề nằm ở hàm tiện ích w5100_write16(u16 address, u16 value)
    • nhiều register của W5100 là giá trị 16-bit
    • định dạng lệnh mỗi lần chỉ ghi được 8-bit, nên phải tách thành high byte và low byte
    • hàm này đã không ghi byte thứ hai vào address + 1 mà lại ghi đè vào chính địa chỉ cũ
  • Log từ implementation chuẩn trên Arduino ghi lần lượt vào S0_TX_WR0S0_TX_WR1
    • S0_TX_WR0 [0x0424] 0x00
    • S0_TX_WR1 [0x0425] 0x3c
  • Còn log của tác giả thì cả hai lần đều ghi vào S0_TX_WR0 [0x0424]
    • S0_TX_WR0 [0x0424] 0x00
    • S0_TX_WR0 [0x0424] 0x3c
  • Register này chính là con trỏ ghi truyền của Socket 0
    • W5100 được kỳ vọng sẽ đọc register 16-bit này theo thứ tự
    • ghi các byte vào bộ nhớ TX
    • ghi lại write pointer mới
    • rồi nhận lệnh gửi của socket
  • Khi lệnh send được thực thi mà byte thứ hai chưa từng được ghi, chip rơi vào trạng thái bất thường không xác định, và trên Wireshark hiện ra các gói trông như kết quả ngẫu nhiên
  • Sau khi sửa hàm, gói thử nghiệm đã hiển thị bình thường trên Wireshark

Giá trị của việc dành thời gian làm công cụ debug

  • Bản thân việc truyền được gói Ethernet đầu tiên không phải là thành tựu khổng lồ, nhưng trong dự án đây là một cột mốc thành công rõ ràng
  • Việc lần lại bug là phần thú vị của dự án cá nhân, và dành thời gian cho viết công cụ và khám phá không gian debug gần như luôn có giá trị
  • Trong một số môi trường chuyên nghiệp, các công việc không trực tiếp tạo ra deliverable đôi khi bị xem là lãng phí
    • khi quy trình phát triển bị chia nhỏ kiểu JIRA, những việc không trực tiếp đánh dấu hoàn thành checkbox thường bị đánh giá thấp
    • khi hệ thống vẫn chưa được hiểu đủ sâu, việc viết công cụ có thể quan trọng ngang, thậm chí hơn cả viết test
  • Debug gần giống với việc áp dụng phương pháp khoa học
    • thu thập dữ liệu
    • đưa ra dự đoán
    • kiểm chứng dự đoán bằng thí nghiệm
    • cập nhật dự đoán bằng dữ liệu mới
  • Từ đây dự án sẽ chuyển sang các vấn đề ở mức trừu tượng cao hơn
    • hiểu sai RFC
    • viết multitasking code
    • và tiếp tục gặp các bug mới

1 bình luận

 
GN⁺ 2024-11-12
Ý kiến trên Hacker News
  • Khả năng tự tay tạo ra những công cụ nhỏ là một siêu năng lực, và thường nằm ở cốt lõi của cái gọi là lập trình viên 10x
    Đáng tiếc là kỹ năng này thường được thể hiện âm thầm ở những nơi không mấy ai chú ý

    • Tôi cũng từng gặp tình huống như vậy. Tổ chức cũng cần những lập trình viên như bánh răng trong cỗ máy, và ở nhiều tổ chức, chỉ có cách đó mới thực sự vận hành được
      Nhưng với những người có tính tò mò, biết nghĩ đến hiệu ứng bậc hai hoặc những chức năng sắp cần đến, làm việc với các lập trình viên không làm như vậy khá là đau khổ
      Gần đây tôi đang dọn dẹp một dự án do một người từng làm cùng thực hiện; anh ta không phải người xấu, nhưng đã triển khai đúng 100% những gì ticket yêu cầu. Dự án mới vốn định thay thế các vấn đề của phần mềm cũ, nhưng vì cùng lý do đó mà toàn bộ vấn đề cũ vẫn còn nguyên
      Dù vậy, cụm lập trình viên 10x nghe hơi có mùi buzzword. Nó khiến tôi nghĩ đến kiểu lập trình viên liều lĩnh, không cần giám sát vẫn “xong việc” nhưng để lại chi phí rất lớn; mọi thứ bị silo hóa, để rồi sau này khi ai đó đụng vào hoặc người đó rời đi thì sụp như nhà bằng bài
    • Nhìn ngược lại, trong lúc Frank gửi các gói Ethernet, những người khác phải xử lý thay các công việc vốn cần thiết cho toàn tổ chức. Backlog các vấn đề thực tế cần giải quyết gần như vô hạn, vậy cũng có thể phản biện rằng tại sao không đổi mới ngay ở đó
      Lý tưởng nhất là mọi người đều được có thời gian khám phá, nhưng cần có quản lý kiên quyết bảo vệ điều đó ngay cả khi lãnh đạo cấp trên nói “phải làm xong nhanh hơn”. Mọi chuyện còn khó hơn nếu quản lý của đội khác nói: “Đội đó có được tuyển thêm người để bù cho thời gian đã mất không? Chúng tôi cũng cần nhân lực đó”
      Cuối cùng cần có cơ chế ở cấp tổ chức, và ngay cả Google cũng đã từ bỏ 20% thời gian
      Giải pháp “phi đạo đức” là đưa sẵn một chút thời gian như vậy vào ước lượng phát triển
    • Lập trình viên 10x thường không phải là người bị ràng buộc vào ưu tiên cao nhất do quản lý hay người phụ trách sản phẩm đặt ra. Không rõ là vì họ từ chối nhận chỉ thị, vì chính họ là quản lý, hay vì ngay từ đầu đã không có quản lý
      Tự tạo công cụ cho mình trong những tình huống phù hợp là hữu ích, nhưng tôi cũng cho rằng lập trình viên năng suất là người viết ít code nhất và tận dụng những gì đã có. Nói theo ví dụ trong bài này, không ai cần tự viết lại TCP stack, vì đã có những triển khai rất tốt rồi
      Dù vậy, tự làm có thể là cách tốt nhất để đạt được hiểu biết sâu, và hiểu biết sâu là một thành phần của lập trình viên 10x huyền thoại. Chỉ là tôi không kỳ vọng nhà tuyển dụng sẽ trả tiền cho quá trình đó
    • Tôi cũng từng gặp phản ứng ở cả hai thái cực. Có người nói “Ồ, hữu ích thật. Công cụ này đã kiểm tra giúp mô hình của chúng ta”, và cũng có người nói “Bạn đã hỏi PM trước chưa? Cẩn thận đừng sa vào hang thỏ nhé”
      Thường nếu việc đó có thể xong trong vòng một ngày thì tôi cứ làm. Chưa lần nào sai hay bị lãng phí. Trường hợp tệ nhất là sau này tôi sẽ copy-paste đoạn code đó sang chỗ khác
    • Gần đây ở chỗ làm, tôi đã tạo một bộ công cụ nhỏ chạy trên WSL, kết hợp Python và shell, và sếp khá ấn tượng khi thấy tôi dùng nó để debug hệ thống IoT của khách hàng
      Rồi ông ấy bắt đầu muốn người không biết lập trình cũng dùng được, và đột nhiên những công cụ đó trở thành một việc lớn hơn nhiều so với dự kiến
  • Tiêu đề khá mơ hồ; bài này là phần mở đầu của một loạt bài tự xây dựng từ đầu TCP/IP và Ethernet framing stack cho vi điều khiển
    Tác giả dùng chip W5100 có thể tự xử lý TCP/IP, nhưng cũng hỗ trợ cách đưa vào các Ethernet frame đã tạo sẵn. Tuy nhiên phần preamble và tính CRC thì chip xử lý
    Phần lớn bài viết nói về việc giao tiếp với chính con chip và gửi gói thử nghiệm. Có vẻ đó là gói được hard-code, nhưng bài không nói rõ
    Cá nhân tôi đã hy vọng đây là nội dung về bit-banging Ethernet trên một phần cứng vô lý nào đó

    • RP2040 có thể bit-bang Ethernet nếu có transceiver, và làm được cả 100Mb/s
      Một mẹo là chỉnh sửa một bo PHY + MagJack phổ biến để RP2040 tạo tín hiệu clock. Khi đó tín hiệu được đồng bộ và không cần oversampling RMII
      Nếu chỉ cần 10Mb/s thì cũng có thể làm bằng cách bẩn hơn. Tôi vẫn đang chờ một “glass terminal” hiện đại kết hợp xuất hình DVI/HDMI và Ethernet trên RP2040. Chỉ telnet thôi cũng đủ, còn SSH thì có lẽ quá sức
    • Trước đây đã có người làm chuyện đó bằng ATTiny85: https://hackaday.com/2014/08/29/bit-banging-ethernet-on-an-a...
  • Gần đây tôi đã chuyển hướng sự nghiệp hơi khác thường sang kỹ thuật FPGA xoay quanh Ethernet
    Đó là một hành trình thú vị, và cuối cùng tôi đã đi đến chỗ tự thiết kế Hard MAC IP và gửi gói qua PHY IP tùy chỉnh
    Tôi rất khuyến nghị thử thách này cho ai muốn chơi ở “hard mode”. Networking đã được trừu tượng hóa quá nhiều đối với người dùng, nên việc hiểu card Ethernet, modem, switch lắp ráp và tháo rời từng phần của gói như thế nào, cũng như PHY/PCS khôi phục tín hiệu trên link ra sao, thật sự rất đáng giá

    • Khoảng 10 năm trước, tôi từng tham gia một dự án xử lý TCP trực tiếp trên FPGA
      Để debug và kiểm chứng, chúng tôi cho phép kết nối phiên bản mô phỏng tạo bằng Verilator với thiết bị TUN/TAP trên Linux, nhờ đó có thể kết nối trực tiếp từ máy của lập trình viên mà không chiếm dụng phần cứng vật lý. Điều này đặc biệt hữu ích vì chỉ có một bộ phần cứng
    • Tôi tò mò lúc bắt đầu bạn đã quen với networking hay Ethernet chưa. Nếu chưa, tôi cũng muốn biết bạn đã dùng tài liệu nào để nắm được bức tranh tổng thể
      Kiến thức networking của tôi chỉ dừng ở mức hiểu rất cơ bản về mô hình OSI, nhưng tôi muốn đào sâu vào thế giới networking
  • Đây là lần đầu tôi thấy cách diễn giải lại MOSI/MISO: thay vì master out/slave in thì gọi là main out/subordinate in
    Như vậy vẫn có thể tiếp tục gọi tên chân là MOSI/MISO, nên có lẽ tôi cũng sẽ dùng cách này. Phương án COPI/CIPO (controller out/peripheral in) thì tôi không thấy dễ nhớ

  • Tôi thấy khó hiểu vì sao tác giả dùng shield Ethernet W5100 và STM32F401. Nếu dùng một bo mạch STM32F407 cũng dễ tương tự thì sẽ có Ethernet MAC tích hợp, và có thể phát triển kèm với một bo mạch Ethernet PHY giá rẻ
    Cũng có nhiều dự án Ethernet mẫu, và việc phát triển cũng dễ như STM32F401
    Ngoài ra, tôi nghĩ lời giải thích rằng “vì độ phức tạp của xử lý tín hiệu Ethernet nên thường dùng ASIC chuyên dụng” nhìn chung không đúng lắm trong bối cảnh vi điều khiển. Trong nhiều trường hợp, chức năng Ethernet nằm trong vi điều khiển dưới dạng ngoại vi tích hợp, như STM32F407 hay ESP32

    • Tôi là tác giả. Lý do khá mất hứng: khi quyết định bắt đầu dự án, tôi chỉ có sẵn những linh kiện này trong tay
      Dùng chip có ngoại vi Ethernet tích hợp chắc chắn hợp lý hơn. Tuy vậy, cũng là đánh đổi độ phức tạp khi cấu hình W5100 lấy độ phức tạp khi cấu hình ngoại vi của ST
      Mã mạng đã trừu tượng hóa chip thực tế phía sau một giao diện driver (kiểu như read/write/ioctl), nên việc port có lẽ sẽ khá đơn giản
      Trong loạt bài này tôi sẽ xem xét STM32F407
    • Với một số người, bản thân quá trình học mới là điều thú vị, hơn là làm theo cách hiện đại nhất
    • Hôm nay tôi xem qua các bo mạch ESP32 có Ethernet, thì có vẻ phần lớn hoặc khá nhiều trong số đó dùng Ethernet như một thiết bị nối tiếp
  • Ethernet xử lý frame, không phải packet
    Packet là khái niệm của IP

    • RFC 791 định nghĩa IP có nói cả packet lẫn datagram. IP gửi datagram, và mỗi IP datagram được phân mảnh thành một hoặc nhiều packet tùy theo mạng L2 bên dưới
      Tuy nhiên RFC 791 là tài liệu từ thời mà mạng L2 bên dưới nhiều khả năng là ARPAnet dùng packet 128 byte
      Ngày nay sự phân biệt này về cơ bản nên là vô nghĩa. Nếu bạn đang dựa vào phân mảnh IP để gửi một IP datagram lớn thành nhiều packet L2 thì có gì đó sai rồi. IPv6 thậm chí không hỗ trợ phân mảnh bên trong mạng
      Trong thực tế, theo thời gian ranh giới phân biệt gần như đã biến mất. Vì thường một frame Ethernet chứa một IP datagram, và mọi người cứ gọi tất cả là packet
    • Chỉ trên HN mới có chuyện này. Có người tự triển khai mạng từ đầu, còn phần bình luận thì hạ thấp họ như thể họ không biết mình đang làm gì chỉ vì một thuật ngữ
    • Trong Ethernet, packet là khái niệm ở tầng vật lý, và nó đóng gói frame, vốn là khái niệm ở tầng liên kết dữ liệu
      https://en.wikipedia.org/wiki/Ethernet_frame
    • Packet là khái niệm của TCP, còn IP gửi datagram
  • Nếu muốn thử dùng Ethernet có dây trên vi điều khiển, một số bo STM32 Nucleo cỡ lớn hơn có tích hợp Ethernet 100Mbps và giá khoảng 25 đô la, khá rẻ
    Đánh giá về phần mềm STM32Cube thì trái chiều, nhưng nó tạo được ví dụ giao tiếp Ethernet chạy được
    https://www.st.com/en/evaluation-tools/nucleo-f439zi.html

    • Nếu muốn nền tảng ESP32 thì WT32-ETH01 có giá khoảng 7 đô la trên Aliexpress. Cá nhân tôi thấy bắt đầu với nó dễ ngang hoặc hơn linh kiện STM
      Có sẵn MQTT, HTTP client và server, v.v.
      Lần cuối tôi dùng Cube-MX là một trải nghiệm nhìn chung rất khó chịu. Nếu dùng lại STM32, có lẽ tôi sẽ thích stm32-hal hoặc libopencm3 hơn. Bản thân công cụ và mã sinh ra có đủ loại bug tệ hại và các trường hợp biên khiến tôi mất vài ngày để debug. Có thể bây giờ đã khá hơn
      https://github.com/egnor/wt32-eth01
    • Bo RISC-V ESP32-P4 có Ethernet giá khoảng 20 đô la, khá thú vị
      https://liliputing.com/waveshare-esp32-p4-nano-is-a-tiny-ris...
      Tôi vừa thấy còn có module rẻ hơn nữa. Những thứ như WT32-ETH01 có thể kém hiệu năng hơn
    • STM32Cube có thể tạo ví dụ giao tiếp Ethernet chạy được, nhưng trên một số phần cứng thì nó bị hỏng
    • May là trên GitHub có vài dự án CMake thay thế
    • STM32Cube có cảm giác “thập niên 90” rất rõ
  • Nếu muốn tự viết network stack trên Linux, bạn có thể dùng socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) để làm việc ở mức trừu tượng không khác bài viết này nhiều
    Packet SOCK_RAW được trao đổi với driver thiết bị mà không thay đổi dữ liệu packet. Khi nhận, địa chỉ được phân tích và truyền vào cấu trúc địa chỉ chuẩn sockaddr_ll
    Khi gửi, buffer do người dùng cung cấp phải chứa header tầng vật lý, và packet đó sẽ được đưa nguyên vẹn vào hàng đợi driver mạng của interface do địa chỉ đích chỉ định
    https://man7.org/linux/man-pages/man7/packet.7.html

    • Nếu muốn làm theo hướng ngược lại, có thể dễ dàng mở interface tun (IP ảo) hoặc tap (Ethernet ảo)
      Nó thêm một interface ảo vào network stack, giống như interface VPN. Trong khi đó, packet socket thì ngược lại, cho phép giao tiếp trực tiếp với interface thật
  • Chính xác thì có lẽ nên gọi là Ethernet frame

  • Làm tốt lắm. Tôi vừa dành 16 giờ làm việc vừa qua cho việc ngược lại: một triển khai phân tích Ethernet II (bao gồm VLAN), IPv4+6, UDP cho tới giao thức IP dùng trong ô tô
    Mục đích là để hiểu một luồng capture bus độc quyền, trong đó luồng này truyền các Ethernet frame lồng trong Ethernet frame, v.v., và tôi nhận chúng bằng raw socket
    Với loại công việc này, Wireshark và ChatGPT thực sự vô giá