3. Khung ứng dụng libmain và thư viện timer
3.2. Thư viện Timer
Theo [4], đối với một số lượng lớn các timer có độ phân giải cao và độ phân giải thấp cùng tồn tại, Phương pháp hiệu quả nhất là sử dụng thuật toán băm sau đó chia nhóm và xếp các timer vào khung chia độ phù hợp theo chu kỳ của timer (khoảng thời gian expire của timer).
Theo như phân tích ở mục 1.5, để có được độ phân giải timer lên đến 0,5 ms và chấp nhận mức sai số ± 10% thì nấc thang chia độ của timer phải được thiết lập ở mức ngưỡng 50 micro giây. Để thuận tiện cho việc chia độ và nâng cao độ chính xác của các timer, nhóm thực hiện đề tài không thực hiện chia độ trực tiếp từ giá trị expire của timer mà sử dụng một thuật toán chuyển đổi từ thời gian tính theo mili giây ra nano giây sau đó tiến hành phép chia lấy phần nguyên cho giá trị 50000 nano giây (tương ứng với 50 micro giây). Kết quả của phép chia lấy phần nguyên sẽ được băm và xếp vào các nấc thang chia
35
độ theo [4]. Hình 13 bên dưới mô tả cách thức sử dụng giá trị của kết quả phép chia được lưu trong một biến có độ dài 24 bit và được băm theo các nấc thang 4 bit dành cho các bit từ 1 đến 16 và 8 bit dành cho các bit từ 16 đến 24. Nguyên nhân của việc băm theo cách thức như vậy là căn cứ vào nhu cầu sử dụng của các ứng dụng (phần lớn là các timer nhỏ hơn 4 ms).
Trong hình 13, Ticks chính là giá trị kết quả của phép chia giá trị quy đổi của timer ra nano giây cho 50000 (50 micro giây), Time là cột chỉ ra thời gian quy đổi lớn nhất sẽ được chứa trong Group. Mỗi Group từ tv1 đến tv4 sẽ là một mảng có 16 giá trị tương ứng với 4 bit băm (từ bit 1 đến bit 16) và tv5 là mảng có số phần tử
Hình 13. Module xử lý timer trong Libmain
Trong vòng lặp của Libmain trước khi gọi hàm đợi sự kiện, Libmain sẽ gọi hàm TimerControl để tính toán thời gian cho phép đợi bao lâu để đảm bảo timer gần timeout nhất không bị bỏ qua (duyệt trong danh sách 16 phần tử của tv1 và tìm giá trị nhỏ nhất, nếu có thì dung việc tìm kiếm, nếu tv1 không có thì tìm trong tv2 và thực hiện tương tự cho đến tv5).
Thư viện timer sử dụng 02 khái niệm là nhóm timer (timer group id) và các timer id trong group, timer group được sử dụng cho mục đích phân nhóm các ứng dụng và các
36
module chức năng, mỗi group có một cấu trúc dữ liệu điều khiển và bảng băm lập lịch riêng như mô tả trong hình 13.
Một timer được xác định bằng một giá trị ID 32-bit và một handle nhóm (timer group id) các thông tin chi tiết về dữ liệu của một timer như sau:
- idtm: id của timer,
- milisec: chu kỳ expire - tính theo mili giây. - số chu kỳ expire,
- con trỏ hàm sẽ được gọi mỗi khi timer expire.
Có thể tạo ra bao nhiêu nhóm timer tùy thích nhưng nên tránh tạo quá nhiều (16 trở lại) để tối ưu việc tìm kiếm. Sử dụng hàm sau để tạo nhóm timer:
int tgCreate(int param);
tmCreate trả ra một giá trị handle nếu thành công, hoặc -1 nếu lỗi.
Để tạo một timer, sử dụng hàm tmStart cho các timer mili giây và tmStartMs cho các timer micro giây:
int tmStart(int hTimerGrp, int idtm, int milisec, int count, void (* tmProc)(int id, int hGrp)); int tmStartMs(int hTimerGrp, int idtm, int milisec, int count, void (* tmProc)(int id, int hGrp));
Tham số thứ nhất là handle của nhóm timer, lấy từ kết quả trả về của tgCreate.
Tham số cuối cùng là địa chỉ hàm callback, sẽ được gọi mỗi khi timer expire gọi với tham số là ID và handle nhóm của timer.
Tham số count cho biết số lần expire dự kiến của timer. Giá trị này sẽ được lưu trữ trong cấu trúc nội bộ của timer và giảm dần mỗi khi timer expire. Tại thời điểm bất kỳ có thể lấy giá trị này bằng hàm tmGetCount. Nếu timer được tạo với count = -1 (lặp vô tận), tmGetCount luôn trả ra giá trị này.
int tmGetCount(int hTimerGrp, int idtm);
Để dừng và giải phóng một timer, sử dụng hàm tmClose: int tmClose(int hTimerGrp, int idtm);
Để giải phóng một nhóm timer, sử dụng hàm tgFree. Các timer trong nhóm sẽ tự động giải phóng.
Dựa trên khung ứng dụng libmain và thư viện timer, phần sau đây của luận văn sẽ trình bày khung kiến trúc của phần mềm xử lý giao thức LTE lớp 2, lớp 3 trên UE.
37