Seluruh kebenaran tentang RTOS. Artikel # 21. Kotak Surat: Pengantar dan Layanan Dasar



Kotak surat disebutkan di salah satu artikel sebelumnya (# 5). Mereka adalah metode komunikasi antar-tugas sinyal-ke-sinyal termudah kedua yang didukung oleh Nucleus SE dan menyediakan cara yang murah dan fleksibel untuk mentransfer pesan-pesan sederhana antar tugas.

Artikel sebelumnya dalam seri:
Artikel # 20. Semaphores: Layanan Tambahan dan Struktur Data
Artikel # 19. Semaphores: pengantar dan layanan dasar
Artikel # 18. Grup Bendera Acara: Layanan Pembantu dan Struktur Data
Artikel # 17. Grup Bendera Acara: Pengantar dan Layanan Dasar
Artikel # 16. Sinyal
Artikel # 15. Partisi Memori: Layanan dan Struktur Data
Artikel # 14. Bagian memori: pengantar dan layanan dasar
Artikel # 13. Struktur data tugas dan panggilan API yang tidak didukung
Artikel # 12. Layanan untuk bekerja dengan tugas
Artikel # 11. Tugas: konfigurasi dan pengantar API
Artikel # 10. Penjadwal: fitur canggih dan pelestarian konteks
Artikel # 9. Penjadwal: implementasi
Artikel # 8. Nucleus SE: Desain dan Penyebaran Internal
Artikel # 7. Nucleus SE: Pendahuluan
Artikel # 6. Layanan RTOS lainnya
Artikel # 5. Interaksi tugas dan sinkronisasi
Artikel # 4. Tugas, pengalihan konteks, dan interupsi
Artikel # 3. Tugas dan Perencanaan
Artikel # 2. RTOS: Struktur dan mode waktu-nyata
Artikel # 1. RTOS: pengantar.

Menggunakan Kotak Surat


Dalam Nucleus SE, kotak surat didefinisikan selama fase pembuatan. Aplikasi dapat memiliki hingga 16 kotak surat. Jika aplikasi tidak memiliki kotak surat, kode panggilan layanan dan struktur data yang terkait dengan kotak surat tidak akan dimasukkan dalam aplikasi.

Kotak surat hanyalah tempat untuk menyimpan data, yang ukurannya cukup untuk menyimpan variabel jenis ADDR dan akses aman yang dikontrol sedemikian rupa sehingga beberapa tugas dapat menggunakannya. Suatu tugas dapat mengirim data ke kotak surat. Akibatnya, kotak surat akan penuh, dan tidak ada tugas yang dapat mengirim data ke sana sampai tugas melakukan operasi membaca kotak surat atau sampai kotak surat kosong. Mencoba mengirim data ke kotak surat lengkap atau mencoba membaca kotak surat kosong akan menghasilkan kesalahan atau jeda tugas, tergantung pada pengaturan panggilan API yang dipilih dan konfigurasi Nucleus SE.

Kotak surat dan Antrian


Dalam beberapa implementasi OS, kotak surat tidak diimplementasikan, tetapi sebagai alternatif, diusulkan untuk menggunakan antrian. Ini terdengar logis, karena antrian seperti itu akan menyediakan fungsi yang sama dengan kotak surat. Namun, antrian adalah struktur data yang lebih kompleks dan membawa lebih banyak data tambahan, kode dan memiliki waktu layanan yang lebih lama.

Dalam Nucleus SE, seperti pada Nucleus RTOS, Anda dapat memilih salah satu dari jenis objek ini.
Jika aplikasi Anda memiliki beberapa antrian dan satu kotak surat, maka masuk akal untuk mempertimbangkan mengganti kotak surat dengan antrian. Ini akan sedikit meningkatkan jumlah overhead, tetapi akan menghilangkan semua kode API yang terkait dengan kotak surat. Atau, Anda dapat mengkonfigurasi aplikasi dengan kedua metode dan membandingkan jumlah data dan kinerja.

Antrian akan dibahas dalam artikel mendatang.

Konfigurasikan Kotak Surat


Jumlah Kotak Surat


Seperti kebanyakan objek Nucleus SE, konfigurasi kotak surat terutama ditentukan oleh arahan #define dalam file nuse_config.h . Parameter utama adalah NUSE_MAILBOX_NUMBER , yang menentukan jumlah kotak surat dalam aplikasi. Nilai default adalah nol (yaitu, tidak ada kotak surat) dan dapat mengambil nilai hingga 16. Nilai yang salah akan menyebabkan kesalahan selama kompilasi, yang akan dihasilkan dengan memeriksa nuse_config_check.h (ini termasuk dalam file nuse_config.c dan dikompilasi dengan itu ), yang akan memicu arahan #error .

Memilih nilai bukan nol adalah aktivator utama untuk kotak surat. Parameter ini digunakan ketika mendefinisikan struktur data dan ukurannya tergantung pada nilainya (lebih lanjut tentang ini di artikel berikutnya). Selain itu, nilai bukan nol mengaktifkan pengaturan API.

Aktifkan Panggilan API


Setiap fungsi API (panggilan utilitas) di Nucleus SE diaktifkan oleh arahan #define dalam file nuse_config.h . Untuk kotak surat, arahan ini adalah:

NUSE_MAILBOX_SEND NUSE_MAILBOX_RECEIVE NUSE_MAILBOX_RESET NUSE_MAILBOX_INFORMATION NUSE_MAILBOX_COUNT 

Secara default, mereka diatur ke FALSE , sehingga menonaktifkan semua panggilan layanan dan memblokir masuknya kode yang mengimplementasikannya. Untuk mengonfigurasi kotak surat di aplikasi, Anda harus memilih panggilan API yang diperlukan dan mengaturnya ke TRUE .

Berikut ini adalah bagian kode dari file nuse_config.h .

 /* Number of mailboxes in the system - 0-16 */ #define NUSE_MAILBOX_NUMBER 0 /* Service call enablers: */ #define NUSE_MAILBOX_SEND FALSE #define NUSE_MAILBOX_RECEIVE FALSE #define NUSE_MAILBOX_RESET FALSE #define NUSE_MAILBOX_INFORMATION FALSE #define NUSE_MAILBOX_COUNT FALSE 

Jika fungsi API kotak surat diaktifkan dan tidak ada kotak surat di aplikasi (kecuali untuk NUSE_Mailbox_Count () , yang selalu diaktifkan), kesalahan kompilasi terjadi. Jika kode Anda menggunakan panggilan API yang belum diaktifkan, kesalahan tata letak akan terjadi karena kode implementasi tidak termasuk dalam aplikasi.

Panggilan layanan kotak surat


Nucleus RTOS mendukung sembilan panggilan layanan yang dikaitkan dengan kotak surat dan menyediakan fungsionalitas berikut:

  • Mengirim pesan ke kotak surat. Nucleus SE diimplementasikan dalam fungsi NUSE_Mailbox_Send () .
  • Membaca pesan dari kotak surat. Nucleus SE mengimplementasikan fungsi NUSE_Mailbox_Receive () .
  • Mengembalikan kotak surat ke status yang tidak digunakan dengan melepaskan semua tugas yang ditangguhkan (reset). Di Nucleus SE, diterapkan di NUSE_Mailbox_Reset () .
  • Memberikan informasi tentang kotak surat tertentu. Nucleus SE diimplementasikan dalam NUSE_Mailbox_Information () .
  • Mengembalikan jumlah kotak surat yang saat ini dikonfigurasi dalam aplikasi. Di Nucleus SE, diterapkan di NUSE_Mailbox_Count () .
  • Menambahkan kotak surat baru (pembuatan). Nucleus SE tidak diimplementasikan.
  • Hapus kotak surat. Nucleus SE tidak diimplementasikan.
  • Kembalikan pointer ke semua kotak surat di aplikasi. Nucleus SE tidak diimplementasikan.
  • Mengirim pesan ke semua tugas yang ditangguhkan di kotak surat (disiarkan). Nucleus SE tidak diimplementasikan.

Pertimbangkan secara rinci implementasi dari setiap panggilan layanan.

Kotak Surat Baca dan Tulis Panggilan Layanan


Operasi dasar yang dapat dilakukan pada kotak surat adalah menulis dan membaca data (mengirim dan menerima). Nucleus RTOS dan Nucleus SE menyediakan dua panggilan API dasar untuk operasi ini, yang akan dijelaskan di bawah ini.

Menulis ke Kotak Surat


Memanggil Nucleus RTOS API untuk menulis ke kotak surat sangat fleksibel, yang memungkinkan Anda untuk menjeda tugas secara implisit atau dengan batas waktu jika operasi tidak dapat diselesaikan dengan segera (misalnya, ketika mencoba menulis ke kotak surat lengkap). Nucleus SE menyediakan panggilan layanan serupa, hanya jeda tugas yang opsional, dan batas waktu tidak diterapkan.

Nucleus RTOS juga menawarkan panggilan layanan untuk menyiarkan data ke kotak surat, panggilan ini tidak didukung di Nucleus SE dan akan dijelaskan di bagian "Panggilan API yang belum direalisasi" di artikel berikutnya.

Panggilan untuk menulis ke kotak surat di Nucleus RTOS
Prototipe panggilan layanan:
STATUS NU_Send_To_Mailbox (NU_MAILBOX * kotak surat, pesan VOID *, penangguhan yang tidak ditandatangani);

Parameter:
kotak surat - penunjuk ke kotak surat;
message - sebuah pointer ke pesan yang akan dikirim, terdiri dari empat elemen bertipe unsigned ;
menangguhkan - spesifikasi penangguhan tugas, dapat mengambil nilai NU_NO_SUSPEND , NU_SUSPEND atau nilai batas waktu.

Nilai pengembalian:
NU_SUCCESS - panggilan berhasil diselesaikan;
NU_INVALID_MAILBOX - pointer kotak surat tidak valid;
NU_INVALID_POINTER - null pointer ke pesan ( NULL );
NU_INVALID_SUSPEND - upaya untuk menangguhkan dari utas yang tidak terkait tugas;
NU_MAILBOX_FULL - kotak surat penuh, tetapi jenis penangguhan tidak ditentukan;
NU_TIMEOUT - kotak surat masih penuh, bahkan setelah penangguhan untuk periode yang ditentukan;
NU_MAILBOX_DELETED - kotak surat dihapus saat tugas ditangguhkan;
NU_MAILBOX_WAS_RESET - kotak surat diatur ulang saat tugas ditangguhkan.

Panggilan untuk menulis ke kotak surat di Nucleus SE
Panggilan API ini mendukung fungsionalitas inti API Nucleus RTOS.

Prototipe panggilan layanan:
STATUS NUSE_Mailbox_Send (NUSE_MAILBOX kotak surat, pesan ADDR *, U8 ditangguhkan);

Parameter:
kotak surat - indeks kotak surat (ID);
message - pointer ke pesan yang akan dikirim; itu adalah salah satu variabel dari jenis ADDR ;
menangguhkan - spesifikasi penangguhan tugas, dapat mengambil nilai NUSE_NO_SUSPEND atau NUSE_SUSPEND .

Nilai pengembalian:
NUSE_SUCCESS - panggilan berhasil diselesaikan;
NUSE_INVALID_MAILBOX - indeks kotak surat tidak valid;
NUSE_INVALID_POINTER - null pointer ke pesan ( NULL );
NUSE_INVALID_SUSPEND - upaya untuk menangguhkan dari utas yang tidak terkait atau ketika fungsionalitas pemblokiran panggilan API dinonaktifkan;
NUSE_MAILBOX_FULL - kotak surat penuh, tetapi jenis penangguhan tidak ditentukan;
NUSE_MAILBOX_WAS_RESET - kotak surat direset saat tugas ditangguhkan.

Menerapkan Entri Kotak Pesan di Nucleus SE
Versi kode fungsi API NUSE_Mailbox_Send () (setelah memeriksa parameter) dipilih menggunakan kompilasi bersyarat, tergantung pada apakah dukungan untuk panggilan API diaktifkan untuk memblokir (menangguhkan tugas) atau tidak. Pertimbangkan kedua opsi tersebut.

Jika penguncian tugas dinonaktifkan, logika untuk panggilan API ini cukup sederhana, dan kode tidak memerlukan penjelasan:

 if (NUSE_Mailbox_Status[mailbox]) /* mailbox full */ { return_value = NUSE_MAILBOX_FULL; } else /* mailbox empty */ { NUSE_Mailbox_Data[mailbox] = *message; NUSE_Mailbox_Status[mailbox] = TRUE; return_value = NUSE_SUCCESS; } 

Pesan disimpan dalam elemen yang sesuai NUSE_Mailbox_Data [] , dan kotak surat ditandai sebagai digunakan.

Jika penguncian tugas diaktifkan, kode menjadi lebih kompleks:

 do { if (!NUSE_Mailbox_Status[mailbox]) /* mailbox empty */ { NUSE_Mailbox_Data[mailbox] = *message; NUSE_Mailbox_Status[mailbox] = TRUE; if (NUSE_Mailbox_Blocking_Count[mailbox] != 0) { U8 index; /* check whether a task is blocked */ /* on this mailbox */ NUSE_Mailbox_Blocking_Count[mailbox]--; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == mailbox)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* mailbox full */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_MAILBOX_FULL; } else { /* block task */ NUSE_Mailbox_Blocking_Count[mailbox]++; NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND); 

Beberapa penjelasan mungkin bermanfaat.

Kode terlampir dalam loop do ... while , yang berjalan saat parameter menangguhkan adalah NUSE_SUSPEND .

Jika kotak surat kosong, pesan dicatat, dan status kotak surat berubah untuk menunjukkan bahwa sudah penuh. Memeriksa tugas yang dijeda (yang menunggu untuk dibaca) di kotak surat ini. Jika ada tugas seperti itu, yang pertama dilanjutkan. Variabel penangguhan diatur ke NUSE_NO_SUSPEND , dan panggilan API berakhir dan mengembalikan NUSE_SUCCESS .

Jika kotak surat penuh dan ditangguhkan adalah NUSE_NO_SUSPEND , panggilan API akan mengembalikan NUSE_MAILBOX_FULL . Jika penangguhan adalah NUSE_SUSPEND , tugas akan dijeda. Setelah fungsi selesai (misalnya, ketika tugas dilanjutkan), jika nilai kembali NUSE_SUCCESS (yang menunjukkan bahwa tugas dilanjutkan karena pesan sudah dibaca, dan bukan bahwa kotak surat diatur ulang), siklus dimulai dari awal.

Baca kotak surat


Panggilan utilitas Nucleus RTOS API untuk membaca kotak surat sangat fleksibel dan memungkinkan Anda untuk menjeda tugas secara implisit atau dengan batas waktu jika operasi tidak dapat diselesaikan segera (misalnya, ketika membaca dari kotak surat kosong). Nucleus SE menyediakan layanan serupa, hanya penangguhan tugas opsional, dan batas waktu tidak diterapkan.

Panggilan untuk membaca kotak surat di Nucleus RTOS
Prototipe panggilan layanan:
STATUS NU_Receive_From_Mailbox (NU_MAILBOX * kotak surat, pesan VOID *, penangguhan yang tidak ditandatangani);

Parameter:
kotak surat - penunjuk ke unit kontrol kotak surat yang disediakan oleh pengguna;
message - pointer ke penyimpanan untuk pesan yang diterima, yang memiliki ukuran sama dengan empat variabel tipe unsigned ;
menangguhkan - spesifikasi penangguhan tugas, dapat mengambil nilai NUSE_NO_SUSPEND , NUSE_SUSPEND atau nilai batas waktu.

Nilai pengembalian:
NU_SUCCESS - panggilan berhasil diselesaikan;
NU_INVALID_MAILBOX - pointer kotak surat tidak valid;
NU_INVALID_POINTER - null pointer ke pesan ( NULL );
NU_INVALID_SUSPEND - upaya untuk menangguhkan dari aliran yang salah (tidak terkait dengan tugas aliran);
NU_MAILBOX_EMPTY - kotak surat kosong, dan jenis penangguhan tidak ditentukan;
NU_TIMEOUT - kotak surat masih kosong, bahkan setelah tugas dijeda untuk nilai batas waktu yang ditentukan;
NU_MAILBOX_DELETED - kotak surat dihapus saat tugas ditangguhkan;
NU_MAILBOX_WAS_RESET - kotak surat diatur ulang saat tugas ditangguhkan.

Panggilan untuk membaca kotak surat di Nucleus SE
Panggilan API ini mendukung fungsionalitas inti API Nucleus RTOS.

Prototipe panggilan layanan:
STATUS NUSE_Mailbox_Receive (NUSE_MAILBOX kotak surat, pesan ADDR *, U8 ditangguhkan);

Parameter:
kotak surat - indeks kotak surat (ID);
message - pointer ke penyimpanan pesan yang diterima, adalah salah satu variabel dari tipe ADDR ;
menangguhkan - spesifikasi penangguhan tugas, dapat mengambil nilai NUSE_NO_SUSPEND atau NUSE_SUSPEND .

Nilai pengembalian:
NUSE_SUCCESS - panggilan berhasil diselesaikan;
NUSE_INVALID_MAILBOX - indeks kotak surat tidak valid;
NUSE_INDALID_POINTER - null pointer ke pesan ( NULL );
NUSE_INVALID_SUSPEND - upaya untuk menangguhkan dari aliran yang salah atau ketika panggilan API dinonaktifkan untuk memblokir tugas;
NUSE_MAILBOX_EMPTY - kotak surat kosong, dan jenis penangguhan tugas tidak ditentukan;
NUSE_MAILBOX_WAS_RESET - kotak surat direset saat tugas ditangguhkan.

Menerapkan Pembaca Kotak Pesan di Nucleus SE
Versi kode fungsi API NUSE_Mailbox_Receive () (setelah memeriksa parameter) dipilih menggunakan kompilasi bersyarat, tergantung pada apakah panggilan API diaktifkan untuk memblokir (menunda tugas) atau tidak. Kami akan mempertimbangkan kedua opsi tersebut.

Jika penguncian tugas dinonaktifkan, logika untuk panggilan API ini cukup sederhana, dan kode tidak memerlukan penjelasan:

 if (!NUSE_Mailbox_Status[mailbox]) /* mailbox empty */ { return_value = NUSE_MAILBOX_EMPTY; } else { /* mailbox full */ *message = NUSE_Mailbox_Data[mailbox]; NUSE_Mailbox_Status[mailbox] = FALSE; return_value = NUSE_SUCCESS; } 

Pesan dibaca dari elemen NUSE_Mailbox_Data [] yang sesuai, dan kotak surat ditandai sebagai kosong.

Jika penguncian tugas diaktifkan, kode menjadi lebih kompleks:

 do { if (NUSE_Mailbox_Status[mailbox]) /* mailbox full */ { *message = NUSE_Mailbox_Data[mailbox]; NUSE_Mailbox_Status[mailbox] = FALSE; if (NUSE_Mailbox_Blocking_Count[mailbox] != 0) { U8 index; /* check whether a task is blocked */ /* on this mailbox */ NUSE_Mailbox_Blocking_Count[mailbox]--; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == mailbox)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* mailbox empty */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_MAILBOX_EMPTY; } else { /* block task */ NUSE_Mailbox_Blocking_Count[mailbox]++; NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND); 

Beberapa klarifikasi mungkin bermanfaat.

Kode terlampir dalam loop do ... while , yang berjalan saat parameter menangguhkan adalah NUSE_SUSPEND .

Jika kotak surat penuh, pesan yang disimpan dikembalikan, dan status kotak surat berubah untuk menunjukkan bahwa itu kosong. Memeriksa tugas yang dijeda (yang menunggu untuk direkam) di kotak surat ini. Jika ada tugas seperti itu, yang pertama dilanjutkan. Variabel penangguhan diatur ke NUSE_NO_SUSPEND , dan panggilan API berakhir dan mengembalikan NUSE_SUCCESS .

Jika kotak surat kosong dan parameter penangguhan adalah NUSE_NO_SUSPEND , panggilan API mengembalikan NUSE_MAILBOX_EMPTY . Jika penangguhan adalah NUSE_SUSPEND , tugas akan dijeda. Jika, pada akhir panggilan, nilai kembali adalah NUSE_SUCCESS , yang menunjukkan bahwa tugas dilanjutkan karena pesan dikirim (dan bukan bahwa kotak surat diatur ulang), siklus dimulai dari awal.

Artikel berikut akan melihat panggilan API tambahan yang terkait dengan kotak surat, serta struktur data yang sesuai.

Tentang Pengarang: Colin Walls telah bekerja di industri elektronik selama lebih dari tiga puluh tahun, mencurahkan sebagian besar waktunya untuk firmware. Dia sekarang adalah seorang insinyur firmware di Mentor Embedded (sebuah divisi dari Mentor Graphics). Colin Walls sering berbicara di konferensi dan seminar, penulis berbagai artikel teknis dan dua buku tentang firmware. Tinggal di Inggris. Blog profesional Colin , email: colin_walls@mentor.com.

Source: https://habr.com/ru/post/id430856/


All Articles