Talaan ng mga Nilalaman:

LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32: 15 Hakbang
LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32: 15 Hakbang

Video: LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32: 15 Hakbang

Video: LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32: 15 Hakbang
Video: Lora cloud control system 2024, Hulyo
Anonim
LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32
LoRa 3Km hanggang 8Km Wireless Communication Na May Mababang Gastos E32 (sx1278 / sx1276) Device para sa Arduino, Esp8266 o Esp32

Lumilikha ako ng isang silid-aklatan upang pamahalaan ang EBYTE E32 batay sa serye ng Semtech ng aparato ng LoRa, napakalakas, simple at murang aparato.

Maaari mong makita ang bersyon ng 3Km dito, bersyon 8Km dito

Maaari silang gumana sa layo na 3000m hanggang 8000m, at mayroon silang maraming mga tampok at parameter. Kaya't nilikha ko ang library na ito upang gawing simple ang paggamit.

Ito ay isang solusyon para makuha ang data mula sa mga metropolitan sensor o upang makontrol ang drone.

Mga gamit

Arduino UNO

Wemos D1 mini

Bersyon ng LoRa E32 TTL 100 3Km

LoRa E32 TTL 1W 8Km bersyon

Hakbang 1: Library

Library
Library

Mahahanap mo rito ang aking silid aklatan.

Magdownload.

I-click ang button na DOWNLOADS sa kanang sulok sa itaas, palitan ang pangalan ng hindi naka-compress na folder na LoRa_E32.

Suriin na ang folder ng LoRa_E32 ay naglalaman ng LoRa_E32.cpp at LoRa_E32.h.

Ilagay ang folder ng library ng LoRa_E32 iyong / aklatan / folder. Maaaring kailanganin mong likhain ang mga library ng mga folder kung ito ang iyong unang silid-aklatan.

I-restart ang IDE.

Hakbang 2: Pinout

Pinout
Pinout
Pinout
Pinout
Pinout
Pinout

Tulad ng nakikita mo maaari mong itakda ang iba't ibang mga mode sa pamamagitan ng M0 at M1 pin.

Mayroong ilang mga pin na maaaring magamit sa isang static na paraan, ngunit Kung ikinonekta mo ito sa microcontroller at i-configure ang mga ito sa library na nakukuha mo sa pagganap at maaari mong kontrolin ang lahat ng mode sa pamamagitan ng software, ngunit ipapaliwanag namin nang mas mahusay sa susunod.

Hakbang 3: AUX Pin

AUX Pin
AUX Pin
AUX Pin
AUX Pin
AUX Pin
AUX Pin

Tulad ng nasabi ko na Hindi mahalaga na ikonekta ang lahat ng pin sa output ng microcontroller, maaari mong ilagay ang M0 at M1 na pin sa TAAS o LOW upang makakuha ng desidered na pagsasaayos, at kung hindi mo ikonekta ang AUX ang library ay magtakda ng isang makatuwirang pagkaantala upang matiyak na ang operasyon ay kumpleto na.

AUX pin

Kapag ang paglilipat ng data ay maaaring magamit upang gisingin ang panlabas na MCU at ibalik ang TAAS sa pagtatapos ng paglilipat ng data.

Kapag tumatanggap ng AUX pagpunta sa Mababa at ibalik ang TAAS kapag ang buffer ay walang laman.

Ginagamit din ito para sa pagsuri sa sarili upang maibalik ang normal na operasyon (sa power-on at mode ng pagtulog / programa).

Hakbang 4: Ganap na Nakakonektang Schema Esp8266

Ganap na Nakakonektang Schema Esp8266
Ganap na Nakakonektang Schema Esp8266
Ganap na Nakakonektang Schema Esp8266
Ganap na Nakakonektang Schema Esp8266

Ang iskema ng koneksyon ng esp8266 ay mas simple dahil Gumagana ito sa parehong boltahe ng mga lohikal na komunikasyon (3.3v).

Mahalagang magdagdag ng pull-up risistor (4, 7Kohm) upang makakuha ng mahusay na katatagan.

Hakbang 5: Ganap na Nakakonektang Schema Arduino

Ganap na Nakakonektang Schema Arduino
Ganap na Nakakonektang Schema Arduino
Ganap na Nakakonektang Schema Arduino
Ganap na Nakakonektang Schema Arduino

Ang boltahe na nagtatrabaho ng Arduino ay 5v, kaya kailangan naming magdagdag ng isang boltahe na divider sa RX pin M0 at M1 ng module ng LoRa upang maiwasan ang pinsala, maaari kang makakuha ng karagdagang impormasyon dito Voltage divider: calculator at application.

Maaari mong gamitin ang isang resistor ng 2Kohm sa GND at 1Kohm mula sa signal kaysa pagsamahin sa RX.

Hakbang 6: Library: Tagatayo

Gumawa ako ng isang hanay ng maraming mga konstruktor, dahil maaari kaming magkaroon ng maraming mga pagpipilian at sitwasyon upang pamahalaan.

LoRa_E32 (byte rxPin, byte txPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32 (byte rxPin, byte txPin, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); LoRa_E32 (byte rxPin, byte txPin, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Ang unang hanay ng mga tagapagbuo ay nilikha upang italaga ang pamamahala ng Serial at iba pang mga pin sa silid-aklatan.

Ang rxPin at txPin ay ang pin upang kumonekta sa UART at sila ay sapilitan.

Ang auxPin ay isang pin na suriin ang katayuan sa pagpapatakbo, paghahatid at pagtanggap (ipapaliwanag namin nang mas mabuti sa susunod), ang pin na iyon Hindi mandatory, kung hindi mo itinakda Ito ay naglalagay ako ng isang pagkaantala upang pahintulutan ang operasyon na makumpleto ang sarili (may latency).

Ang m0pin at m1Pin ay ang mga pin upang baguhin ang MODE ng operasyon (tingnan ang itaas na talahanayan), sa palagay ko ang mga pin na ito sa "produksyon" ay direktang kumonekta sa TAAS o Mababa, ngunit para sa pagsubok sila ay kapaki-pakinabang upang mapamahalaan ng silid-aklatan.

Ang bpsRate ay ang boudrate ng SoftwareSerial na normal ay 9600 (ang tanging baud rate sa programmin / mode na pagtulog)

Isang simpleng halimbawa ay

# isama ang "LoRa_E32.h" LoRa_E32 e32ttl100 (2, 3); // RX, TX // LoRa_E32 e32ttl100 (2, 3, 5, 6, 7); // RX, TX

Maaari naming direktang gamitin ang isang SoftwareSerial kasama ang isa pang tagapagbuo

LoRa_E32 (HardwareSerial * serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32 (HardwareSerial * serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32 (HardwareSerial * serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Ang halimbawang nasa itaas sa tagatayo na ito ay maaaring gawin tulad nito.

# isama ang # isama ang "LoRa_E32.h"

SoftwareSerial mySerial (2, 3); // RX, TX

LoRa_E32 e32ttl100 (& mySerial);

// LoRa_E32 e32ttl100 (& mySerial, 5, 7, 6);

Ang huling hanay ng tagapagbuo ay upang pahintulutang gumamit ng isang HardwareSerial sa halip na SoftwareSerial.

LoRa_E32 (SoftwareSerial * serial, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32 (SoftwareSerial * serial, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32 (SoftwareSerial * serial, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Hakbang 7: Magsimula

Ang panimulang utos ay ginagamit upang simulan ang Serial at mga pin sa input at output mode.

walang bisa magsimula ();

sa pagpapatupad ay

// Startup lahat ng mga pin at UART

e32ttl100.begin ();

Hakbang 8: Pamamaraan ng Pag-configure at Impormasyon

Mayroong isang hanay ng mga pamamaraan para sa pamamahala ng pagsasaayos at makakuha ng impormasyon ng aparato.

ResponseSonstrContainer getConfiguration ();

ResponseStatus setConfiguration (Configuration config, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

ResponseSonstrContainer getModuleInformation ();

walang bisa ang printParameter (pagsasaayos ng config Configuration);

ResponseStatus resetModule ();

Hakbang 9: Container Container

Upang gawing simple ang pamamahala ng tugon Lumilikha ako ng isang hanay ng lalagyan, para sa akin napaka kapaki-pakinabang upang pamahalaan ang mga error at ibalik ang pangkalahatang data.

ResponseStatus

Ito ay isang lalagyan ng katayuan at mayroong 2 simpleng entry point, kasama nito makukuha mo ang status code at ang paglalarawan ng status code

Serial.println (c.getResponseDescription ()); // Paglalarawan ng code

Serial.println (c.code); // 1 kung Tagumpay

Ang code ay

Tagumpay = 1, ERR_UNKNOWN, ERR_NOT_SUPPORT, ERR_NOT_IMPLEMENT, ERR_NOT_INITIAL, ERR_INVALID_PARAM, ERR_DATA_SIZE_NOT_MATCH, ERR_BUF_TOO_SMALL, ERR_TIMEOUT, ERR_HARDWARE, ERR_HEAD_NOT_RECOGNIZED

ResponseContainer

Ang lalagyan na ito ay nilikha upang pamahalaan ang tugon ng String at magkaroon ng 2 entry point.

ang data na may string ay bumalik mula sa mensahe at katayuan ng isang halimbawa ng RepsonseStatus.

ResponseContainer rs = e32ttl.receiveMessage ();

String message = rs.data;

Serial.println (rs.status.getResponseDescription ());

Serial.println (mensahe);

ResponseSonstrContainer

Ito ang mas "kumplikadong" lalagyan, ginagamit ko ito upang pamahalaan ang istraktura, Mayroon itong parehong entry point ng ResponseContainer ngunit ang data ay isang walang bisa na pointer upang pamahalaan ang kumplikadong istraktura.

ResponseSonstrContainer c;

c = e32ttl100.getConfiguration (); // Mahalagang makakuha ng config pointer bago ang lahat ng iba pang operasyon

Pagsasaayos ng pagsasaayos = * (Configuration *) c.data;

Serial.println (c.status.getResponseDescription ());

Serial.println (c.status.code);

getConfiguration at setConfiguration

Ang unang pamamaraan ay getConfiguration, maaari mo itong gamitin upang bawiin ang lahat ng data na nakaimbak sa aparato.

ResponseSonstrContainer getConfiguration ();

Narito ang isang halimbawa ng paggamit.

ResponseSonstrContainer c;

c = e32ttl100.getConfiguration (); // Mahalagang makakuha ng config pointer bago ang lahat ng iba pang operasyon

Pagsasaayos ng pagsasaayos = * (Pag-configure *) c.data;

Serial.println (c.status.getResponseDescription ());

Serial.println (c.status.code);

Serial.println (pagsasaayos. SPED.getUARTBaudRate ());

Ang istraktura ng pagsasaayos ay mayroong lahat ng mga data ng mga setting, at nagdaragdag ako ng isang serye ng pagpapaandar upang makuha ang lahat ng paglalarawan ng solong data.

pagsasaayos. ADDL = 0x0; // Unang bahagi ng addressconfiguration. ADDH = 0x1; // Pangalawang bahagi ng pagsasaayos ng address. CHAN = 0x19; // Channel config. OPTION.fec = FEC_0_OFF; // Forward error correction switch switch. OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; // Transmission mode config. OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; // Pull-up management config. OPTION.transmissionPower = POWER_17; // dBm transmission power config. OPTION.wirelessWakeupTime = WAKE_UP_1250; // Maghintay ng oras para sa pagsasaayos ng paggising. SPED.airDataRate = AIR_DATA_RATE_011_48; // Air data rate config. SPED.uartBaudRate = UART_BPS_115200; // Communication baud rate config. SPED.uartParity = MODE_00_8N1; // Parity bit

Mayroon kang katumbas na pagpapaandar para sa lahat ng katangian upang makuha ang lahat ng paglalarawan:

Serial.print (F ("Chan:")); Serial.print (pagsasaayos. CHAN, DEC); Serial.print ("->"); Serial.println (config.getChannelDescription ()); Serial.println (F ("")); Serial.print (F ("SpeedParityBit:")); Serial.print (pagsasaayos. SPED.uartParity, BIN); Serial.print ("->"); Serial.println (pagsasaayos. SPED.getUARTParityDescription ()); Serial.print (F ("SpeedUARTDatte:")); Serial.print (pagsasaayos. SPED.uartBaudRate, BIN); Serial.print ("->"); Serial.println (pagsasaayos. SPED.getUARTBaudRate ()); Serial.print (F ("SpeedAirDataRate:")); Serial.print (pagsasaayos. SPED.airDataRate, BIN); Serial.print ("->"); Serial.println (pagsasaayos. SPED.getAirDataRate ()); Serial.print (F ("OptionTrans:")); Serial.print (pagsasaayos. OPTION.fixedTransmission, BIN); Serial.print ("->"); Serial.println (pagsasaayos. OPTION.getFixedTransmissionDescription ()); Serial.print (F ("OptionPullup:")); Serial.print (pagsasaayos. OPTION.ioDriveMode, BIN); Serial.print ("->"); Serial.println (pagsasaayos. OPTION.getIODroveModeDescription ()); Serial.print (F ("OptionWakeup:")); Serial.print (pagsasaayos. OPTION.wirelessWakeupTime, BIN); Serial.print ("->"); Serial.println (pagsasaayos. OPTION.getWirelessWakeUPTimeDescription ()); Serial.print (F ("OptionFEC:")); Serial.print (pagsasaayos. OPTION.fec, BIN); Serial.print ("->"); Serial.println (pagsasaayos. OPTION.getFECDescription ()); Serial.print (F ("OptionPower:")); Serial.print (pagsasaayos. OPTION.transmissionPower, BIN); Serial.print ("->"); Serial.println (pagsasaayos. OPTION.getTransmissionPowerDescription ());

Sa parehong paraan ang setConfiguration ay nais ng isang strucutre ng pagsasaayos, kaya sa palagay ko ang mas mahusay na paraan upang pamahalaan ang pagsasaayos ay upang makuha ang kasalukuyang isa, ilapat ang tanging pagbabago na kailangan mo at itakda itong muli.

ResponseStatus setConfiguration (Configuration config, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

ang pagsasaayos ay ang strucutre previsiouly show, i-save ang pahintulot sa Type na pumili ka kung ang pagbabago ay magiging permanenteng para lamang sa kasalukuyang session.

ResponseSonstrContainer c; c = e32ttl100.getConfiguration (); // Mahalagang kumuha ng pointer ng pagsasaayos bago ang lahat ng iba pang pagpapatakbo Configuration config = * (Configuration *) c.data; Serial.println (c.status.getResponseDescription ()); Serial.println (c.status.code); printParameter (pagsasaayos); pagsasaayos. ADDL = 0x0; pagsasaayos. ADDH = 0x1; pagsasaayos. CHAN = 0x19; pagsasaayos. OPTION.fec = FEC_0_OFF; configure. OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; configure. OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; configure. OPTION.transmissionPower = POWER_17; pagsasaayos. OPTION.wirelessWakeupTime = WAKE_UP_1250; pagsasaayos. SPED.airDataRate = AIR_DATA_RATE_011_48; pagsasaayos. SPED.uartBaudRate = UART_BPS_115200; pagsasaayos. SPED.uartParity = MODE_00_8N1; // Set config binago at itinakda upang hindi hawakan ang configure ng ResponseStatus rs = e32ttl100.setConfiguration (pagsasaayos, WRITE_CFG_PWR_DWN_LOSE); Serial.println (rs.getResponseDescription ()); Serial.println (rs.code); printParameter (pagsasaayos);

Ang parameter ay pinamamahalaan bilang pare-pareho:

Hakbang 10: Pagpipilian sa Pangunahing Pag-configure

Pangunahing Pagpipilian sa Pang-configure
Pangunahing Pagpipilian sa Pang-configure

Hakbang 11: Magpadala ng Makatanggap ng Mensahe

Una dapat naming ipakilala ang isang simple ngunit kapaki-pakinabang na pamamaraan upang suriin kung mayroong isang bagay sa tumatanggap na buffer

int magagamit ();

Ibinabalik lamang nito kung gaano karaming mga byte ang mayroon ka sa kasalukuyang stream.

Hakbang 12: Karaniwang Mode ng Pagpapadala

Karaniwang Transmission Mode
Karaniwang Transmission Mode

Normal / Transparent transmission mode ay ginagamit upang magpadala ng mga mensahe sa lahat ng aparato na may parehong address at channel.

Mayroong maraming paraan upang magpadala / makatanggap ng mensahe, ipapaliwanag namin nang detalyado:

ResponseStatus sendMessage (Const String message);

ResponseContainer acceptMessage ();

Ang unang pamamaraan ay sendMessage at ginagamit upang magpadala ng isang String sa isang aparato sa Normal mode.

ResponseStatus rs = e32ttl.sendMessage ("Prova"); Serial.println (rs.getResponseDescription ());

Ang iba pang aparato ay ginagawa lamang sa loop

kung (e32ttl.available ()> 1) {ResponseContainer rs = e32ttl.receiveMessage (); String message = rs.data; // First ever get the data Serial.println (rs.status.getResponseDescription ()); Serial.println (mensahe); }

Hakbang 13: Pamahalaan ang Istraktura

Kung nais mong magpadala ng isang kumplikadong strucuture maaari mong gamitin ang pamamaraang ito

ResponseStatus sendMessage (const void * message, const uint8_t size); ResponseSonstrContainer acceptMessage (laki ng uint8_t);

Ginagamit ito upang magpadala ng strucutre, halimbawa:

struct Messaggione {uri ng char [5]; mensahe ng char [8]; bool mitico; }; struct Messaggione messaggione = {"TEMP", "Peple", totoo}; ResponseStatus rs = e32ttl.sendMessage (& messaggione, sizeof (Messaggione)); Serial.println (rs.getResponseDescription ());

at sa kabilang panig maaari kang makatanggap ng mensahe sa gayon

ResponseSonstrContainer rsc = e32ttl.receiveMessage (sizeof (Messaggione)); struct Messaggione messaggione = * (Messaggione *) rsc.data; Serial.println (messaggione.message); Serial.println (messaggione.mitico);

Basahin ang bahagyang pag-istraktura

Kung nais mong basahin ang unang bahagi ng mensahe upang pamahalaan ang higit pang uri ng strucutre maaari mong gamitin ang pamamaraang ito.

ResponseContainer acceptInitialMessage (const uint8_t laki);

Ginagawa Ko ito upang makatanggap ng isang string na may uri o iba pa upang makilala ang strucuture upang mai-load.

istr Messaggione {// Bahagyang strucutre nang walang typechar na mensahe [8]; bool mitico; }; uri ng char [5]; // unang bahagi ng istraktura ResponseContainer rs = e32ttl.receiveInitialMessage (sizeof (type)); // Ilagay ang string sa isang char array (hindi kinakailangan) memcpy (type, rs.data.c_str (), sizeof (type)); Serial.println ("READ TYPE:"); Serial.println (rs.status.getResponseDescription ()); Serial.println (uri); // Basahin ang natitirang istraktura ResponseSonstrContainer rsc = e32ttl.receiveMessage (sizeof (Messaggione)); struct Messaggione messaggione = * (Messaggione *) rsc.data;

Hakbang 14: Fixed Mode sa halip na Normal Mode

Sa parehong pamamaraan Lumilikha ako ng isang hanay ng paraan upang magamit sa naayos na paghahatid

Naayos na paghahatid

Kailangan mo lamang palitan ang paraan ng pagpapadala, dahil ang patutunguhang aparato ay hindi nakatanggap ng paunang salita sa Address at Channel quando settato il fix mode.

Kaya para sa mensahe ng String mayroon ka

ResponseStatus sendFixedMessage (byte ADDL, byte ADDH, byte CHAN, const String message); ResponseStatus sendBroadcastFixedMessage (byte CHAN, const String message);

at para sa istraktura na mayroon ka

ResponseStatus sendFixedMessage (byte ADDL, byte ADDH, byte CHAN, const void * message, const uint8_t size); ResponseStatus sendBroadcastFixedMessage (byte CHAN, const void * message, const uint8_t size);

Narito ang isang simpleng halimbawa

ResponseStatus rs = e32ttl.sendFixedMessage (0, 0, 0x17, & messaggione, sizeof (Messaggione)); // ResponseStatus rs = e32ttl.sendFixedMessage (0, 0, 0x17, "Ciao");

Ang naayos na paghahatid ay may higit pang mga sitwasyon

Kung magpapadala ka sa isang tukoy na aparato (pangalawang mga sitwasyon Nakatakdang pagpapadala) dapat kang magdagdag ng ADDL, ADDH at CHAN upang kilalanin Ito nang direkta.

ResponseStatus rs = e32ttl.sendFixedMessage (2, 2, 0x17, "Mensahe sa isang aparato");

Kung nais mong magpadala ng isang mensahe sa lahat ng aparato sa isang tinukoy na Channel maaari mong gamitin ang pamamaraang ito.

ResponseStatus rs = e32ttl.sendBroadcastFixedMessage (0x17, "Mensahe sa isang aparato ng isang channel");

Kung nais mong matanggap ang lahat ng mensahe sa broadcast sa network dapat mong itakda ang iyong ADDH at ADDL sa BROADCAST_ADDRESS.

ResponseSonstrContainer c; c = e32ttl100.getConfiguration (); // Mahalagang kumuha ng pointer ng pagsasaayos bago ang lahat ng iba pang pagpapatakbo Configuration config = * (Configuration *) c.data; Serial.println (c.status.getResponseDescription ()); Serial.println (c.status.code); printParameter (pagsasaayos); configure. ADDL = BROADCAST_ADDRESS; configure. ADDH = BROADCAST_ADDRESS; // Set config binago at itinakda upang hindi hawakan ang configure ng ResponseStatus rs = e32ttl100.setConfiguration (pagsasaayos, WRITE_CFG_PWR_DWN_LOSE); Serial.println (rs.getResponseDescription ()); Serial.println (rs.code); printParameter (pagsasaayos);

Hakbang 15: Salamat

Ngayon ay mayroon ka ng lahat ng impormasyon upang magawa ang iyong trabaho, ngunit sa palagay ko mahalaga na magpakita ng ilang mga makatotohanang halimbawa upang hindi maipadala nang mas mabuti ang lahat ng posibilidad.

  1. LoRa E32 aparato para sa Arduino, esp32 o esp8266: mga setting at pangunahing paggamit
  2. LoRa E32 aparato para sa Arduino, esp32 o esp8266: library
  3. LoRa E32 aparato para sa Arduino, esp32 o esp8266: pagsasaayos
  4. LoRa E32 aparato para sa Arduino, esp32 o esp8266: naayos na paghahatid
  5. LoRa E32 aparato para sa Arduino, esp32 o esp8266: pag-save ng kuryente at pagpapadala ng nakabalangkas na data

Inirerekumendang: