#ifndef __LORA_SOCKET_H__ #define __LORA_SOCKET_H__ #include #include "vector.h" #include "stringVec.h" #ifndef LORA_SOCKET_IP #define LORA_SOCKET_IP "0.0.0.0" #endif #ifndef MAX_RECEIVE_STACK_SIZE #define MAX_RECEIVE_STACK_SIZE 5 #endif #ifndef MAX_SEND_STACK_SIZE #define MAX_SEND_STACK_SIZE 5 #endif #ifndef MAX_TCP_TRY_TIMES #define MAX_TCP_TRY_TIMES 8 #endif class LoRaSocket { public: LoRaSocket(){} static void core(); static void ini(); static void udp(const String& msg, const String& to = "0.0.0.0"); static void tcp(const String& msg, const String& to); static void rtcp(const String& msg); inline static void onReceived(void (*f)(String, String, String, String)){ _f = f; }; inline bool isNewMsg(){ isLoopMode = true; return (newType == "") ? false : true; }; inline const String getNewMsg(){ String msg = newMsg; clearNewMsg(); return msg; }; inline void getNewMsg(String& msg, String& from, String& to, String& type){ msg = newMsg; from = newFrom; to = newTo; type = newType; clearNewMsg(); }; private: static StringVec tcp_sendingStack, tcp_receiveStack; static Vector tcp_sendingTryTimes; static void(*_f)(String, String, String, String); static String newMsg, newFrom, newTo, newType; static bool isLoopMode; inline void clearNewMsg(){ newMsg = ""; newFrom = ""; newTo = ""; newType = ""; }; inline static void _onReceived(const String& msg, const String& from, const String& to, const String& type){ newMsg = msg; newFrom = from; newTo = to; newType = type; if(!isLoopMode) (*_f)(msg, from, to, type); }; /* LoRa Functions */ static void LoRa_tx_mode(); static void LoRa_rx_mode(); static void send(const String& s); static void send(const char *s); static const String receiveMsg(); /* Package Functions */ inline static const String getIPHeader(const String& to = "0.0.0.0"){ return to + "|" + LORA_SOCKET_IP + "|"; }; inline static bool isGoodPackage(const String& s){ String body = s.substring(0, s.length() - 1); if(s.substring(s.length() - 1, s.length()) != hash(body)){ return false; } return true; }; inline static const String getToIP(const String& s){ unsigned short left = s.indexOf('|'); unsigned short right = s.indexOf('|', left + 1); return s.substring(left + 1, right); }; inline static const String getFromIP(const String& s){ unsigned short left = s.indexOf('|', s.indexOf('|') + 1); unsigned short right = s.indexOf('|', left + 1); return s.substring(left + 1, right); }; inline static const String getType(const String& s){ return s.substring(0, s.indexOf('|')); }; inline static const String getContent(const String& s){ unsigned short left = s.indexOf('|', s.indexOf('|', s.indexOf('|') + 1) + 1); unsigned short right = s.indexOf('|', left + 1); return decode(s.substring(left + 1, right)); }; inline static const String getTcpKey(const String& s){ int left = s.indexOf('|', s.indexOf('|', s.indexOf('|', s.indexOf('|') + 1) + 1) + 1); int right = s.indexOf('|', left + 1); return s.substring(left + 1, right); }; /* receive Functions */ static void getMsg(const String& msg); /* tcp stack functions */ static void checkSendStack(){ for(unsigned int i = 0; i < tcp_sendingStack.Size(); i ++){ send("tc"+tcp_sendingStack[i]); tcp_sendingTryTimes[i] += 1; if(tcp_sendingTryTimes[i] >= MAX_TCP_TRY_TIMES){ tcp_sendingStack.Erase(i); tcp_sendingTryTimes.Erase(i); } } }; inline static void receiveStackClassify(){ if(tcp_receiveStack.Size() > MAX_RECEIVE_STACK_SIZE) tcp_receiveStack.Erase(0); }; inline static void sendStackClassify(){ if(tcp_sendingStack.Size() > MAX_SEND_STACK_SIZE) { tcp_sendingStack.Erase(0); tcp_sendingTryTimes.Erase(0); } }; static void removeByKey(const String& key); /* tools */ static const String hash(const String& s); static const String encode(const String& s){ return s; }; static const String decode(const String& s){ return s; } static const String generateRandomKey(){ String o = ""; for(unsigned short i = 0; i < 4; i ++){ o += char(random(26) + 97); } return o; } /* timer */ static void setInterval(void (*function)(void), const int delay){ static unsigned long startTime = millis(); if(millis() - startTime > delay){ (*function)(); startTime = millis(); } } }; void LoRaSocket::getMsg(const String& msg){ if(!isGoodPackage(msg)) return; if(getToIP(msg) != LORA_SOCKET_IP && getToIP(msg) != "0.0.0.0") return; if(getType(msg) == "udp") _onReceived(getContent(msg), getFromIP(msg), getToIP(msg), "udp"); if(getType(msg) == "tcp"){ rtcp(msg); if(tcp_receiveStack.Find(msg) != -1) return; _onReceived(getContent(msg), getFromIP(msg), getToIP(msg), "tcp"); receiveStackClassify(); } if(getType(msg) == "rtcp"){ removeByKey(getContent(msg)); } } void LoRaSocket::udp(const String& msg, const String& to){ char *c; c = (char*)malloc((msg.length()+39)*sizeof(char)); sprintf(c, "udp|%s%s|", getIPHeader(to).c_str(), encode(msg).c_str()); sprintf(c, "%s%s", c, hash(c).c_str()); send(c); free(c); }; void LoRaSocket::tcp(const String& msg, const String& to){ String fin = "tcp|" + getIPHeader(to) + encode(msg) + "|" + generateRandomKey() + "|"; fin += hash(fin); tcp_sendingStack.PushBack(fin); tcp_sendingTryTimes.PushBack(0); sendStackClassify(); send(fin); }; void LoRaSocket::rtcp(const String& msg){ tcp_receiveStack.PushBack(msg); String fin = "rtcp|" + getIPHeader(getFromIP(msg)) + getTcpKey(msg) + "|"; fin += hash(fin); send(fin); } StringVec LoRaSocket::tcp_sendingStack, LoRaSocket::tcp_receiveStack; Vector LoRaSocket::tcp_sendingTryTimes; void (*LoRaSocket::_f)(String, String, String, String); String LoRaSocket::newMsg = "", LoRaSocket::newFrom = "", LoRaSocket::newTo = "", LoRaSocket::newType = ""; bool LoRaSocket::isLoopMode = false; void LoRaSocket::ini() { LoRa_rx_mode(); } void LoRaSocket::core() { /* Listen Msg */ if(LoRa.parsePacket()){ getMsg(receiveMsg()); } /* check tcp stack */ setInterval(checkSendStack, 1000); } void LoRaSocket::LoRa_tx_mode(){ LoRa.idle(); } void LoRaSocket::LoRa_rx_mode(){ LoRa.receive(); } void LoRaSocket::send(const char *s){ LoRa_tx_mode(); delay(200); LoRa.beginPacket();Serial.println(s); LoRa.print(s); LoRa.endPacket(); delay(200); LoRa_rx_mode(); } void LoRaSocket::send(const String& s){ LoRa_tx_mode(); delay(200); LoRa.beginPacket();Serial.println(s); LoRa.print(s); LoRa.endPacket(); delay(200); LoRa_rx_mode(); } const String LoRaSocket::receiveMsg(){ String s = ""; while (LoRa.available()) { s += (char)LoRa.read(); } return s; } const String LoRaSocket::hash(const String& s){ unsigned char hashVal = 'k'; for(unsigned short i = 0; i < s.length(); i ++){ hashVal ^= s.charAt(i); } hashVal = hashVal % 26 + 97; return String((char)hashVal); } void LoRaSocket::removeByKey(const String& key){ for(unsigned int i = 0; i < tcp_sendingStack.Size(); i++){ if(getTcpKey(tcp_sendingStack[i]) == key) { tcp_sendingStack.Erase(i); return; } } } #endif //__LORA_SOCKET_H__