CAT LoRa Starter Kit ตอนที่ 4 สร้าง CAT Lora Library

Choonewza
Choonewza
Jan 5 · 6 min read

จากบทความที่แล้วเราได้ลองสร้าง Library ง่าย ๆ กันไปแล้ว มาในบทความนี้จะเป็นการนำเอาโค๊ดจากบทความใน ตอนที่ 2 มาแปลงให้เป็น Library กันครับ


ออกแบบ

จากโค๊ดโปรแกรมเดิมจาก ตอนที่ 2 จะพบว่าส่วนหลัก ๆ ของการทำงานจะประกอบด้วย 5 ส่วนที่สำคัญคือ

  1. การกำหนดค่าตั้งต้นเช่น DEV_EUI, DEV_ADDR, NWKS_KEY, APPS_KEY และ LoRa Class
  2. ฟังก์ชั่นในการตั้งค่าความถี่สำหรับใช้ในการเชื่อมต่อกับเครื่อข่ายฯ
    ( void Set_LoraConfig(void) )
  3. ฟังก์ชั่นสำหรับการกำหนดค่าพื้นฐาน และการเชื่อมต่อกับเครือข่ายฯ
    ( void Set_LoraConfigABP_A(void) )
  4. ฟังก์ชั่นสำหรับส่งข้อมูลไปยัง Network Server ผ่านเครือข่ายฯ
  5. ฟังก์ชั่นสำหรับรับข้อมูลจาก Network Server ผ่านเครือข่ายฯ

ดังนั้นเราสามารถออกแบบ Class Diagram ของ Library นี้ได้เป็นดังนี้

CatLoRa Class//Attributes
-devEui:String
-devAddr:String
-nwksKey:String
-appsKey:String
//Methods
+begin(baudRate: int):void
-freqLoraConfig():void
+joinABP(loraClass:String, devEui:String, devADDR:String, nwksKey:String, appsKey:String):void
+transmit(port:int, payload:String):void
+receive():String
+getPortReceive(dataFromReceive:String):int
+getPayloadReceive(dataFromReceive:String):String

แต่เนื่องจากเราต้องใช้งานชิบ AcSIP S76S เพื่อใช้งานเครือข่าย LoRa ดังนั้นเราจึงต้องเพิ่ม Attribute และ Method ที่จำเป็นในการเรียกใช้ชิบตัวนี้ด้วย

SERCOM5_Handler()

CatLoRa//Attributes
Uart Serial2(&sercom1, PIN_SERIAL_RX, PIN_SERIAL_TX, SERCOM_RX_PAD_0, UART_TX_PAD_2)
.....

PIN_SERIAL_RX คือ pin ที่ใช้สำหรับ Receive (RX) จากชิบของ AcSIP S76S ในที่นี้คือขาที่ 11

PIN_SERIAL_TX คือ pin ที่ใช้สำหรับ Transmit (TX) จากชิบของ AcSIP S76S ในที่นี้คือ pin ที่ 10

SERCOM1_Handler() เป็นฟังชันก์ที่ต้องสร้างไว้ทุกครั้งที่มีการเรียกใช้ &sercom1


เขียนโปรแกรม

ดังนั้นเมื่อเรานำ Class Diagram มาใส่ Code จะได้ดังนี้

CatLora.h

#ifndef catLoRaS76S1_h
#define catLoRaS76S1_h
#include "Arduino.h"
#include <Wire.h>
#include "wiring_private.h" // pinPeripheral() function
class catLoRaS76S1
{
private:
String devEui;
String devAddr;
String nwksKey;
String appsKey;
void SERCOM1_Handler(void);
void freqLoraConfig(void);
public:
~catLoRaS76S();
catLoRaS76S();
void begin(uint32_t bundRate);
void joinABP(String loraClass, String devEui, String devAddr, String nwksKey, String appsKey);
void transmit(uint8_t port, String payLoad);
String receive(void);
String getPortReceive(String dataFromReceive);
String getPayloadReceive(String dataFromReceive);
};
#endif

CatLora.cpp

#include "catLoRaS76S1.h"Uart Serial2(&sercom1, 11, 10, SERCOM_RX_PAD_0, UART_TX_PAD_2);catLoRaS76S1::~catLoRaS76S1() {}catLoRaS76S1::catLoRaS76S1() {}void SERCOM1_Handler(void)
{
Serial2.IrqHandler();
}
void catLoRaS76S1::freqLoraConfig(void)
{
String str1 = "";
//********************
Serial2.print("mac set_ch_freq 0 923200000"); //0
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 0");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 1 923400000"); //1
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 1");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 2 922000000"); //2
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 2");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 3 922200000"); //3
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 3");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 4 922400000"); //4
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 4");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 5 922600000"); //5
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 5");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 6 922800000"); //6
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 6");
Serial.println(str1);
//********************
Serial2.print("mac set_ch_freq 7 923000000"); //7
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 7");
Serial.println(str1);
//********************
Serial2.print("mac set_rx2 2 923200000"); //8
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_rx2 2");
Serial.println(str1);
//********************
Serial2.print("mac save"); //8
str1 = "";
delay(3000);
str1 = Serial2.readString();
Serial.print("mac save");
Serial.println(str1);
}
void catLoRaS76S1::begin(uint32_t bundRate)
{
Wire.begin();
Serial2.begin(bundRate);
pinPeripheral(10, PIO_SERCOM);
pinPeripheral(11, PIO_SERCOM);
delay(500);
freqLoraConfig();
}
void catLoRaS76S1::joinABP(String loraClass, String devEUI, String devAddr, String nwksKey, String appsKey)
{
String str1 = "";
String cmdTemp = "";
//********************
cmdTemp = String("mac set_class ") + loraClass;
Serial2.print(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_class A");
Serial.println(str1);
//********************
cmdTemp = String("mac set_deveui ") + devEUI;
Serial2.print(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_deveui");
Serial.println(str1);
//********************
cmdTemp = String("mac set_devaddr ") + devAddr;
Serial2.print(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_devaddr");
Serial.println(str1);
//********************
cmdTemp = String("mac set_nwkskey ") + nwksKey;
Serial2.print(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_nwkskey");
Serial.println(str1);
//********************
cmdTemp = String("mac set_appskey ") + appsKey;
Serial2.print(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_appskey");
Serial.println(str1);
//********************
Serial2.print("mac save");
str1 = "";
delay(3000);
str1 = Serial2.readString();
Serial.print("mac save");
Serial.println(str1);
//********************
Serial2.print("mac join abp");
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("mac join abp");
Serial.println(str1);
}
void catLoRaS76S1::transmit(uint8_t port, String payLoad)
{
Serial2.print(String(_MAC_TX_UCNF) + " " + String(port) + " " + payLoad);
Serial.println("########### Send Payload");
}
String catLoRaS76S1::receive(void)
{
String msg = Serial2.readString();
String rawData = "";String checkDL = ">> mac rx ";
int checkStart = msg.indexOf(checkDL);
if (checkStart != -1)
{
int checkEND = msg.indexOf("\n", checkStart + 1);
rawData = msg.substring(checkStart + 10, checkEND);
}
return rawData;
}
String catLoRaS76S1::getPortReceive(String dataFromReceive)
{
String macComm = "";if (dataFromReceive != "")
{
int checkStart = dataFromReceive.indexOf(' ');
if (checkStart > -1)
{
macComm = dataFromReceive.substring(0, checkStart);
}
}
else
{
macComm = "NO PORT DL";
}
return macComm;
}
String catLoRaS76S1::getPayloadReceive(String dataFromReceive)
{
String macComm = "";
if (dataFromReceive != "")
{
int checkStart = dataFromReceive.indexOf(' ');
if (checkStart > -1)
{
int checkEND = dataFromReceive.indexOf("\n", checkStart + 1);
macComm = dataFromReceive.substring(checkStart + 1, checkEND);
}
}
return macComm;
}

Refactoring

ทำการ Refactoring เพื่อให้เข้าใจง่ายและลดโค๊ดที่ซ้ำกันออกไป จะได้ดังนี้

CatLora.h

#ifndef catLoRaS76S_h
#define catLoRaS76S_h
#include "Arduino.h"
#include <Wire.h>
#include "wiring_private.h" // pinPeripheral() function
class catLoRaS76S
{
private:
void SERCOM1_Handler(void);
void macCommand(String comm);
void freqLoraConfig(void);
public:
~catLoRaS76S();
catLoRaS76S();
void begin(uint32_t bundRate);
void joinABP(String loraClass, String devEUI, String devAddr, String nwksKey, String appsKey);
void transmit(uint8_t port, String payLoad);
String receive(void);
String getPortReceive(String dataFromReceive);
String getPayloadReceive(String dataFromReceive);
};
#endif

CatLora.cpp

#include "catLoRaS76S.h"#define _DEBUG 1#define _PIN_RX 11
#define _PIN_TX 10
#define _LED_BUIDIN 13
#define _MAC_SIP_RESET "sip reset"#define _MAC_SET_CH_FREQ "mac set_ch_freq"
#define _MAC_SET_RX2 "mac set_rx2"
#define _MAC_SAVE "mac save"
#define _MAC_SET_CLASS "mac set_class"
#define _MAC_SET_DEVEUI "mac set_deveui"
#define _MAC_SET_DEVADDR "mac set_devaddr"
#define _MAC_SET_NWKSKEY "mac set_nwkskey"
#define _MAC_SET_APPSKEY "mac set_appskey"
#define _MAC_JOIN_ABP "mac join abp"
#define _MAC_TX_UCNF "mac tx ucnf"
#define _MAC_SET_appEUI "mac set_appeui"
#define _MAC_SET_APPKEY "mac set_appkey"
#define _MAC_JOIN_OTAA "mac join otaa"
Uart Serial2(&sercom1, _PIN_RX, _PIN_TX, SERCOM_RX_PAD_0, UART_TX_PAD_2);catLoRaS76S::~catLoRaS76S() {}catLoRaS76S::catLoRaS76S()
{
pinMode(_LED_BUIDIN, OUTPUT);
}
void SERCOM1_Handler(void)
{
Serial2.IrqHandler();
}
void catLoRaS76S::macCommand(String comm)
{
Serial2.print(comm);
delay(250);

String msg = Serial2.readString();
#ifdef _DEBUG
Serial.print("_DEBUG: ");
Serial.print(comm);
Serial.println(msg);
#endif
delay(100);
}
void catLoRaS76S::begin(uint32_t bundRate)
{
Wire.begin();
Serial2.begin(bundRate);
pinPeripheral(_PIN_TX, PIO_SERCOM);
pinPeripheral(_PIN_RX, PIO_SERCOM);
delay(500);
freqLoraConfig();
}
void catLoRaS76S::freqLoraConfig(void)
{
int freq[] = {923200000, 923400000, 922000000, 922200000, 922400000, 922600000, 922800000, 923000000};
macCommand(String(_MAC_SIP_RESET));
delay(1000);
//chanel 0 to 7
for (int i = 0; i < sizeof freq / sizeof freq[0]; i++)
{
macCommand(String(_MAC_SET_CH_FREQ) + " " + i + " " + freq[i]);
}
macCommand(String(_MAC_SET_RX2) + " 2 923200000");
macCommand(String(_MAC_SAVE));
}
void catLoRaS76S::joinABP(String loraClass, String devEui, String devAddr, String nwksKey, String appsKey)
{
macCommand(String(_MAC_SET_CLASS) + " " + loraClass);
macCommand(String(_MAC_SET_DEVEUI) + " " + devEui);
macCommand(String(_MAC_SET_DEVADDR) + " " + devAddr);
macCommand(String(_MAC_SET_NWKSKEY) + " " + nwksKey);
macCommand(String(_MAC_SET_APPSKEY) + " " + appsKey);
macCommand(String(_MAC_JOIN_ABP));
macCommand(String(_MAC_SAVE));
}
void catLoRaS76S::transmit(uint8_t port, String payLoad)
{
String comm = String(_MAC_TX_UCNF) + String(" ") + String(port) + String(" ") + payLoad;
Serial2.print(comm);
#ifdef _DEBUG
Serial.print("_DEBUG_TX: ");
Serial.println(comm);
#endif
delay(250);
}
String catLoRaS76S::receive(void)
{
String msg = Serial2.readString();
if (msg == "")
{
return "";
}
#ifdef _DEBUG
Serial.print("_DEBUG_RX: ");
Serial.println(msg);
#endif
String rawData = "";String checkDL = ">> mac rx ";
int checkStart = msg.indexOf(checkDL);
if (checkStart != -1)
{
int checkEND = msg.indexOf("\n", checkStart + 1);
rawData = msg.substring(checkStart + 10, checkEND);
}
return rawData;
}
unsigned int catLoRaS76S::getPortReceive(String dataFromReceive)
{
String macComm = "";if (dataFromReceive != "")
{
int checkStart = dataFromReceive.indexOf(' ');
if (checkStart > -1)
{
macComm = dataFromReceive.substring(0, checkStart);
}
}
return (unsigned int) macComm.toInt();
}
String catLoRaS76S::getPayloadReceive(String dataFromReceive)
{
String macComm = "";
if (dataFromReceive != "")
{
int checkStart = dataFromReceive.indexOf(' ');
if (checkStart > -1)
{
int checkEND = dataFromReceive.indexOf("\n", checkStart + 1);
macComm = dataFromReceive.substring(checkStart + 1, checkEND);
}
}
return macComm;
}

วิธีใช้งาน

ให้เราทำการ include ไฟล์ที่ชื่อ catLoRaS76S.h เข้ามาไว้ในไฟล์ catLoraTest.ino
แล้วทำการกำหนดรอบการส่งโดยเราจะส่ง payload = 010203 และ port = 5 ผ่าน lorawan ทุก ๆ 20 วินาที และทำการวนรับค่าที่ระบบตอบกลับมาทุก ๆ 250 มิลิวินาที โดยมีโค๊ดทั้งหมดดังนี้

catLoraTest.ino

#include "catLoRaS76S.h"#define _ABP_CLASS "C"
#define _DEV_EUI "????????????????"
#define _DEV_ADDR "????????"
#define _NWKS_KEY "????????????????????????????????"
#define _APPS_KEY "????????????????????????????????"
catLoRaS76S lora;unsigned long startMillisTX;
unsigned long currentMillisTX;
const unsigned long periodTX = 20000;
unsigned long startMillisRX;
unsigned long currentMillisRX;
const unsigned long periodRX = 250;
uint8_t _port = 5;
String _payload = "010203";
void setup() {
Serial.begin(115200);
delay(1000);
lora.begin(115200);
lora.joinABP(_ABP_CLASS, _DEV_EUI, _DEV_ADDR, _NWKS_KEY, _APPS_KEY);
startMillisTX = millis();
}
void loop() {//-----TX START-----
currentMillisTX = millis();
if (currentMillisTX - startMillisTX >= periodTX) {
lora.transmit(_port, _payload);
startMillisTX = currentMillisTX;
}
//-----TX END-----
//-----RX START-----
currentMillisRX = millis();
if (currentMillisRX - startMillisRX >= periodRX) {
String rawDL = lora.receive();
if (rawDL != "") {
uint16_t rPort = (uint16_t) lora.getPortReceive(rawDL);
String rPayload = lora.getPayloadReceive(rawDL);
Serial.print("Port = ");
Serial.println(rPort);
Serial.print("Payload = ");
Serial.println(rPayload);
}
startMillisRX = currentMillisRX;
}
//-----RX END-----
}

โดยในหน้า Monitor ของโปรแกรม Arduino IDE เราจะเห็นสถานะการส่งข้อมูล

และเมื่อเราตรวจสอบกับหน้า Logger Data จะพบข้อความที่ส่งขึ้นไป

สำหรับการทำ Downlink ก็สามารถรับข้อมูลได้เช่นเดียวกัน


ในบทความนี้ผมได้สอนแนวทางในการประยุกต์การพัฒนา CAT LoRa Library ของ Arduino IDE ขึ้นมาใช้เองแบบง่าย ๆ ซึ่งในบทความหน้าจะเป็นการเพิ่มความสามารถให้ Library ที่เราสร้างขึ้นนี้สามารถตรวจวัดค่าอุณหภูมิได้ เพราะบอร์ด CAT LoRa Starter Kit ได้มีการใส่เซ็นเซอร์ตรวจวัดอุณหภูมิมาให้ในตัวแล้วครับ ผมก็ขอจบเพียงเท่านี้ครับ สวัสดีครับ

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade