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

Choonewza
6 min readJan 5, 2020

จากบทความที่แล้วเราได้ลองสร้าง 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 ได้มีการใส่เซ็นเซอร์ตรวจวัดอุณหภูมิมาให้ในตัวแล้วครับ ผมก็ขอจบเพียงเท่านี้ครับ สวัสดีครับ

--

--