diff --git a/src/DidacticNet.cpp b/src/DidacticNet.cpp index 361ab839dbadd3c73b0d91c79884ec550914a451..fed141f8ed3b7f38c048226a31234e2558cd2c32 100644 --- a/src/DidacticNet.cpp +++ b/src/DidacticNet.cpp @@ -9,508 +9,696 @@ #include "DidacticNet.h" //************************************************************************** -//ROOT +// ROOT //************************************************************************** -DidacticPSNet::DidacticPSNet(){} +DidacticPSNet::DidacticPSNet() {} -DidacticPSNet::~DidacticPSNet(){} +DidacticPSNet::~DidacticPSNet() {} -void DidacticPSNet::begin(Stream& _port){ +void DidacticPSNet::begin(Stream &_port) +{ setStream(_port); } -void DidacticPSNet::begin(Stream& _port, PSNET_CALLBACK_SIGNATURE){ +void DidacticPSNet::begin(Stream &_port, PSNET_CALLBACK_SIGNATURE) +{ setStream(_port); setCallback(callback); } -DidacticPSNet& DidacticPSNet::setCallback(PSNET_CALLBACK_SIGNATURE){ - this->callback = callback; - return *this; -} - -void DidacticPSNet::setStream(Stream& stream){ - _port = &stream; -} - -bool DidacticPSNet::handleNetwork(){ - //if(_waitingTime <= millis()){ - if(checkData()){ - if(recieveData()){ - //Serial.print("Message filter: ");Serial.println(_readBufferMessage[1]); - //Serial.print("Check Message filter: ");Serial.println(getMessageFilter(_readBufferMessage[1])); - if(getMessageFilter(_readBufferMessage[1])){ - handleData(); - } - } - _waitingTimeCSMA = millis()+ random(CSMA_MIN_DELAY_MS, CSMA_MAX_DELAY_MS); - } - //else if(_dataToSend){ - if(_dataToSend && _waitingTimeSend <= millis() && _waitingTimeCSMA <= millis()){ - //send data to network - //TODO: test added CSMA_CHECKDELAY + 2nd checkData() - unsigned long delayStartTime = micros(); - while(micros() < delayStartTime + CSMA_CHECK_DELAY_US); - //delayMicroseconds(CSMA_CHECK_DELAY_US); //removed: blocking SoftSerial-interrupts - if(!checkData()){ - if(!sendData()){ - return false; - } - else{ - _dataToSend = false; - //_waitingTime = millis()+ random(CSMA_MID_DELAY_MS, CSMA_MAX_DELAY_MS); - _waitingTimeSend = millis() + _intervalTime;//random(CSMA_MID_DELAY_MS, CSMA_MAX_DELAY_MS); - } +DidacticPSNet &DidacticPSNet::setCallback(PSNET_CALLBACK_SIGNATURE) +{ + this->callback = callback; + return *this; +} + +void DidacticPSNet::setStream(Stream &stream) +{ + _port = &stream; +} + +bool DidacticPSNet::handleNetwork() +{ + if (checkData()) + { + if (recieveData()) + { + // Serial.print("Message filter: ");Serial.println(_readBufferMessage[1]); + // Serial.print("Check Message filter: ");Serial.println(getMessageFilter(_readBufferMessage[1])); + if (getMessageFilter(_readBufferMessage[1])) + { + handleData(); + } + } + _waitingTimeCSMA = millis() + random(CSMA_MIN_DELAY_MS, CSMA_MAX_DELAY_MS); + } + if (_dataToSend && _waitingTimeSend <= millis() && _waitingTimeCSMA <= millis()) + { + // send data to network + unsigned long delayStartTime = micros(); + while (micros() < delayStartTime + CSMA_CHECK_DELAY_US) + ; + if (!checkData()) + { + if (!sendData()) + { + return false; + } + else + { + _dataToSend = false; + //_waitingTime = millis()+ random(CSMA_MID_DELAY_MS, CSMA_MAX_DELAY_MS); + _waitingTimeSend = millis() + _intervalTime; // random(CSMA_MID_DELAY_MS, CSMA_MAX_DELAY_MS); } } + } //} - return true; + return true; } -bool DidacticPSNet::isDataToSend(){ +bool DidacticPSNet::isDataToSend() +{ return _dataToSend; } -bool DidacticPSNet::sendData(){ - int counter = 0; +bool DidacticPSNet::sendData() +{ + int counter = 0; bool messageSent = false; - while(!messageSent){ - if(counter >= MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD - 1){ - //TODO: check!!! - _sendBufferMessage[counter] = MSG_DELIMITER; //cut message and stop sending + while (!messageSent) + { + if (counter >= MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD - 1) + { + _sendBufferMessage[counter] = MSG_DELIMITER; // cut message and stop sending messageSent = true; - } - else if(_sendBufferMessage[counter] == MSG_DELIMITER){ + } + else if (_sendBufferMessage[counter] == MSG_DELIMITER) + { messageSent = true; } - _port->write(_sendBufferMessage[counter]); - counter++; - } - return true; + _port->write(_sendBufferMessage[counter]); + counter++; + } + return true; } -int DidacticPSNet::extractData(int startCounter, int maxLength, char* buffer, char limiter){ - int counter = startCounter; - while(_readBufferMessage[counter]!= limiter){ - buffer[counter-startCounter] = _readBufferMessage[counter]; - counter++; - if((counter-startCounter) > maxLength){ +int DidacticPSNet::extractData(int startCounter, int maxLength, char *buffer, char limiter) +{ + int counter = startCounter; + while (_readBufferMessage[counter] != limiter) + { + buffer[counter - startCounter] = _readBufferMessage[counter]; + counter++; + if ((counter - startCounter) > maxLength) + { counter--; - break; //if > maxLenght -> leave while and return - } - } - buffer[counter-startCounter] = '\0'; - return counter-startCounter; //length -} - -int DidacticPSNet::checkData(){ - return (int)_port->available(); -} - -bool DidacticPSNet::recieveData() { - static int msgCounter = 0; - static int topicCounter = 0; - static int payloadCounter = 0; - //if(msgCounter == NULL){ msgCounter = 0; } - //if(topicCounter == NULL){ topicCounter = 0; } - //if(dataCounter == NULL){ dataCounter = 0; } - while (checkData()) { - char localBuffer = _port->read(); - if (localBuffer == MSG_PRELIMITER) { - msgCounter = 0; - topicCounter = 0; - payloadCounter = 0; - _readBufferMessage[msgCounter] = localBuffer; + break; // if > maxLenght -> leave while and return + } + } + buffer[counter - startCounter] = '\0'; + return counter - startCounter; // length +} + +int DidacticPSNet::checkData() +{ + return (int)_port->available(); +} + +bool DidacticPSNet::recieveData() +{ + static int msgCounter = 0; + static int topicCounter = 0; + static int payloadCounter = 0; + // if(msgCounter == NULL){ msgCounter = 0; } + // if(topicCounter == NULL){ topicCounter = 0; } + // if(dataCounter == NULL){ dataCounter = 0; } + while (checkData()) + { + char localBuffer = _port->read(); + if (localBuffer == MSG_PRELIMITER) + { + msgCounter = 0; + topicCounter = 0; + payloadCounter = 0; + _readBufferMessage[msgCounter] = localBuffer; } - else if (localBuffer == MSG_DELIMITER && _readBufferMessage[0] == MSG_PRELIMITER) { - msgCounter++; - _readBufferMessage[msgCounter] = localBuffer; - _readBufferMessage[msgCounter+1] = '0'; + else if (localBuffer == MSG_DELIMITER && _readBufferMessage[0] == MSG_PRELIMITER) + { + msgCounter++; + _readBufferMessage[msgCounter] = localBuffer; + _readBufferMessage[msgCounter + 1] = '0'; msgCounter = 0; - return true; - } - else if (localBuffer == MSG_SEPARATOR && _readBufferMessage[0] == MSG_PRELIMITER) { - topicCounter = msgCounter -2; - msgCounter++; - _readBufferMessage[msgCounter] = localBuffer; + return true; } - else if (_readBufferMessage[0] == MSG_PRELIMITER && localBuffer != MSG_DELIMITER) { - msgCounter++; - _readBufferMessage[msgCounter] = localBuffer; + else if (localBuffer == MSG_SEPARATOR && _readBufferMessage[0] == MSG_PRELIMITER) + { + topicCounter = msgCounter - 2; + msgCounter++; + _readBufferMessage[msgCounter] = localBuffer; } - } - return false; -} - - void DidacticPSNet::setInterval(long intervalTime){ - _intervalTime = intervalTime; + else if (_readBufferMessage[0] == MSG_PRELIMITER && localBuffer != MSG_DELIMITER) + { + msgCounter++; + _readBufferMessage[msgCounter] = localBuffer; } + } + return false; +} +void DidacticPSNet::setInterval(long intervalTime) +{ + _intervalTime = intervalTime; +} //************************************************************************** // CLIENT //************************************************************************** -DidacticPSNetClient::DidacticPSNetClient(){ - _intervalTime = INTERVAL_CLIENT; +DidacticPSNetClient::~DidacticPSNetClient() {} + +// NEW easy interface for non advanced users +// ########################################## +void DidacticPSNetClient::begin(Stream &_port) // TODO: check if CLientMode is necessary or an unset callback ist not a problem +{ + DidacticPSNet::begin(_port); + _clientMode = CLIENT_MODE_BASIC; } -DidacticPSNetClient::~DidacticPSNetClient(){} +bool DidacticPSNetClient::available() +{ + return _newMessageAvailable; +} -int DidacticPSNetClient::publish(char* topic, char* payload){ - return publish(topic, strlen(topic), payload, strlen(payload)); +int DidacticPSNetClient::readLatestTopicNr() +{ + return _newMessageTopicNr; } -int DidacticPSNetClient::publish(char* topic, int topicLength, char* payload , int payloadLength){ - int error = DN_PUBLISH_SUCCESSULL; - - _sendBufferMessage[0] = MSG_PRELIMITER; - _sendBufferMessage[1] = MSG_PUBLISH; - _sendBufferMessage[2+topicLength] = MSG_SEPARATOR; - _sendBufferMessage[2+topicLength+1+payloadLength] = MSG_DELIMITER; - _sendBufferMessage[2+topicLength+1+payloadLength+1] = '\0'; +void DidacticPSNetClient::readTopic(int topicNr, char *topic) +{ + strcpy(topic, _topic[topicNr]); +} + +void DidacticPSNetClient::readTopic(char *topic) +{ + readTopic(_newMessageTopicNr, topic); +} + +void DidacticPSNetClient::readPayload(int topicNr, char *payload) +{ + strcpy(payload, _payload[topicNr]); + + if (topicNr == _newMessageTopicNr) + { + _newMessageAvailable = false; + } +} + +void DidacticPSNetClient::readPayload(char *payload) +{ + readPayload(_newMessageTopicNr, payload); +} + +void DidacticPSNetClient::readPayload(char *topic, char *payload) +{ + int topicNr = getTopicNr(topic); + readPayload(topicNr, payload); +} +// ########################################## + +DidacticPSNetClient::DidacticPSNetClient() +{ + _intervalTime = INTERVAL_CLIENT; +} - //TODO: check - if(topicLength > MAX_LEN_TOPICS){ +int DidacticPSNetClient::publish(char *topic, char *payload) +{ + return publish(topic, strlen(topic), payload, strlen(payload)); +} + +int DidacticPSNetClient::publish(char *topic, int topicLength, char *payload, int payloadLength) +{ + int error = DN_PUBLISH_SUCCESSULL; + + _sendBufferMessage[0] = MSG_PRELIMITER; + _sendBufferMessage[1] = MSG_PUBLISH; + _sendBufferMessage[2 + topicLength] = MSG_SEPARATOR; + _sendBufferMessage[2 + topicLength + 1 + payloadLength] = MSG_DELIMITER; + _sendBufferMessage[2 + topicLength + 1 + payloadLength + 1] = '\0'; + + // TODO: check + if (topicLength > MAX_LEN_TOPICS) + { topicLength = MAX_LEN_TOPICS; error += DN_ERROR_TOPIC_LEN; } - if(payloadLength > MAX_LEN_PAYLOAD){ + if (payloadLength > MAX_LEN_PAYLOAD) + { payloadLength = MAX_LEN_PAYLOAD; error += DN_ERROR_PAYLOAD_LEN; } - for(int i = 0; i < topicLength; i++){ - _sendBufferMessage[2+i] = topic[i]; - } - for(int i = 0; i < payloadLength; i++){ - _sendBufferMessage[2+topicLength+1+i] = payload[i]; - } + for (int i = 0; i < topicLength; i++) + { + _sendBufferMessage[2 + i] = topic[i]; + } + for (int i = 0; i < payloadLength; i++) + { + _sendBufferMessage[2 + topicLength + 1 + i] = payload[i]; + } _dataToSend = true; - return error; + return error; } -//TODO: TEST TEST TEST -int DidacticPSNetClient::publish(char* topic, int data){ +int DidacticPSNetClient::publish(char *topic, int data) +{ char sendPayload[MAX_LEN_PAYLOAD]; itoa(data, sendPayload, 10); - return publish(topic, sendPayload); + return publish(topic, sendPayload); } -int DidacticPSNetClient::publish(char* topic, bool data){ +int DidacticPSNetClient::publish(char *topic, bool data) +{ char sendPayload[2]; itoa(data, sendPayload, 10); - return publish(topic, sendPayload); + return publish(topic, sendPayload); } -int DidacticPSNetClient::publishOnChange(char* topic, bool input){ - if(!_dataToSend){ - if(eDetector.edgeDetected(input)){ +int DidacticPSNetClient::publishOnChange(char *topic, bool input) +{ + if (!_dataToSend) + { + if (eDetector.edgeDetected(input)) + { return publish(topic, input); } } return DN_ERROR_NO_ERROR; } -int DidacticPSNetClient::publishOnChange(char* topic, int input, int threshold){ - if(!_dataToSend){ - if(cDetector.valueChanged(input, threshold)){ +int DidacticPSNetClient::publishOnChange(char *topic, int input, int threshold) +{ + if (!_dataToSend) + { + if (cDetector.valueChanged(input, threshold)) + { return publish(topic, input); } } return DN_ERROR_NO_ERROR; } -int DidacticPSNetClient::subscribe(char* topic){ - return subscribe(topic, strlen(topic)); +int DidacticPSNetClient::subscribe(char *topic) +{ + return subscribe(topic, strlen(topic)); } -int DidacticPSNetClient::subscribe(char* topic, int topicLength){ - int error = DN_ERROR_NO_ERROR; +int DidacticPSNetClient::subscribe(char *topic, int topicLength) +{ + int error = DN_ERROR_NO_ERROR; - if( topicLength > MAX_LEN_TOPICS){ + if (topicLength > MAX_LEN_TOPICS) + { topicLength = MAX_LEN_TOPICS; error = DN_ERROR_TOPIC_LEN; - } + } _sendBufferMessage[0] = MSG_PRELIMITER; - _sendBufferMessage[1] = MSG_SUBSCRIBE; - _sendBufferMessage[2+topicLength] = MSG_DELIMITER; + _sendBufferMessage[1] = MSG_SUBSCRIBE; + _sendBufferMessage[2 + topicLength] = MSG_DELIMITER; int topicNumber = getTopicNr(topic); - if(topicNumber < 0){ + if (topicNumber < 0) + { topicNumber = getFreeTopicNr(); - if(topicNumber < 0){ + if (topicNumber < 0) + { topicNumber = 0; } - for(int i = 0; i < topicLength; i++){ - _topic[topicNumber][i] = topic[i]; - _sendBufferMessage[2+i]= topic[i]; - } - _topic[topicNumber][topicLength] = '\0'; - _sendBufferMessage[2+topicLength+1]= '\0'; - _dataToSend = true; - } - else{ - for(int i = 0; i < topicLength; i++){ - _sendBufferMessage[2+i]= topic[i]; - } - _sendBufferMessage[2+topicLength+1]= '\0'; - _dataToSend = true; - } - while(_dataToSend){ + for (int i = 0; i < topicLength; i++) + { + _topic[topicNumber][i] = topic[i]; + _sendBufferMessage[2 + i] = topic[i]; + } + _topic[topicNumber][topicLength] = '\0'; + _sendBufferMessage[2 + topicLength + 1] = '\0'; + _dataToSend = true; + } + else + { + for (int i = 0; i < topicLength; i++) + { + _sendBufferMessage[2 + i] = topic[i]; + } + _sendBufferMessage[2 + topicLength + 1] = '\0'; + _dataToSend = true; + } + while (_dataToSend) + { handleNetwork(); } - return error; + return error; } -bool DidacticPSNetClient::unsubscribe(char* topic){ +bool DidacticPSNetClient::unsubscribe(char *topic) +{ return unsubscribe(topic, strlen(topic)); } -bool DidacticPSNetClient::unsubscribe(char* topic, int topicLength){ +bool DidacticPSNetClient::unsubscribe(char *topic, int topicLength) +{ int topicNumber = getTopicNr(topic); - if(topicNumber >= 0){ - _topic[topicNumber][0]='\0'; + if (topicNumber >= 0) + { + _topic[topicNumber][0] = '\0'; return true; } return false; } -bool DidacticPSNetClient::getMessageFilter(char messageType){ +bool DidacticPSNetClient::getMessageFilter(char messageType) +{ return messageType == MSG_UPDATE; } -bool DidacticPSNetClient::savePayload(char* buffer, int position){ +bool DidacticPSNetClient::savePayload(char *buffer, int position) +{ strcpy(_payload[position], buffer); return true; } -bool DidacticPSNetClient::handleData(){ +bool DidacticPSNetClient::handleData() +{ int currentTopicNr = 0; int topicLength = 0; int payloadLength = 0; topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_SEPARATOR); - if(topicLength > 0){ + if (topicLength > 0) + { currentTopicNr = getTopicNr(_bufferTopic); - payloadLength = extractData(topicLength+3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER); - if( currentTopicNr >= 0){ - savePayload( _bufferPayload, currentTopicNr); - //callback(_topic[currentTopicNr], topicLength, _payload[currentTopicNr], payloadLength); - #ifdef CALLBACK_W_LENGTH + payloadLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER); + if (currentTopicNr >= 0) + { + savePayload(_bufferPayload, currentTopicNr); + _newMessageAvailable = true; // new + _newMessageTopicNr = currentTopicNr; // new + + if (_clientMode == CLIENT_MODE_ADVANCED) // new -> client with callback + { +#ifdef CALLBACK_W_LENGTH callback(_bufferTopic, topicLength, _bufferPayload, payloadLength); - #else +#else callback(_bufferTopic, _bufferPayload); - #endif - +#endif + } } } return true; } -int DidacticPSNetClient::getTopicNr(char* topic){ - for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++) { - if (strcmp(_topic[i], topic) == 0 || _topic[i][0] == MSG_TOPIC_MULTI) { //TODO: check ... or equal MSG_TOPIC_MULTI +int DidacticPSNetClient::getTopicNr(char *topic) +{ + for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++) + { + if (strcmp(_topic[i], topic) == 0 || _topic[i][0] == MSG_TOPIC_MULTI) + { return i; - } - } - return -1; + } + } + return -1; } -int DidacticPSNetClient::getFreeTopicNr() { - for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++) { - if (strcmp(_topic[i], "") == 0) { +int DidacticPSNetClient::getFreeTopicNr() +{ + for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++) + { + if (strcmp(_topic[i], "") == 0) + { return i; } } return -1; } -int DidacticPSNetClient::getSubscribedTopic(char* topic, int number){ - if(number > 0 && number < getMaxNrTopics()){ +int DidacticPSNetClient::getSubscribedTopic(char *topic, int number) +{ + if (number > 0 && number < getMaxNrTopics()) + { strcpy(topic, _topic[number]); return DN_ERROR_NO_ERROR; } return DN_ERROR_NO_TOPIC; } -int DidacticPSNetClient::getMaxNrTopics(){ +int DidacticPSNetClient::getMaxNrTopics() +{ return getFreeTopicNr(); } - //************************************************************************** -//Broker +// Broker //************************************************************************** -DidacticPSNetBroker::DidacticPSNetBroker(){ - _intervalTime = INTERVAL_BROKER; +DidacticPSNetBroker::DidacticPSNetBroker() +{ + _intervalTime = INTERVAL_BROKER; } -DidacticPSNetBroker::~DidacticPSNetBroker(){} +DidacticPSNetBroker::~DidacticPSNetBroker() {} - -bool DidacticPSNetBroker::getMessageFilter(char messageType){ +bool DidacticPSNetBroker::getMessageFilter(char messageType) +{ return (messageType == MSG_PUBLISH || messageType == MSG_SUBSCRIBE); } -bool DidacticPSNetBroker::savePayload(char* buffer, int position){ +bool DidacticPSNetBroker::savePayload(char *buffer, int position) +{ strcpy(_data[position], buffer); return true; } -void DidacticPSNetBroker::writeDataToTopic(int topicNumber, char* usedTopic, char* newData) { - if(strcmp(_topic[topicNumber], "") == 0){ - strcpy(_topic[topicNumber], usedTopic); - } - strcpy(_data[topicNumber], newData); +void DidacticPSNetBroker::writeDataToTopic(int topicNumber, char *usedTopic, char *newData) +{ + if (strcmp(_topic[topicNumber], "") == 0) + { + strcpy(_topic[topicNumber], usedTopic); + } + strcpy(_data[topicNumber], newData); } -bool DidacticPSNetBroker::handleData(){ +bool DidacticPSNetBroker::handleData() +{ int currentTopicNr = 0; int topicLength = 0; int dataLength = 0; - if(_readBufferMessage[1] == MSG_PUBLISH){ + if (_readBufferMessage[1] == MSG_PUBLISH) + { topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_SEPARATOR); - if(topicLength > 0){ + if (topicLength > 0) + { currentTopicNr = getTopicNr(_bufferTopic); - dataLength = extractData(topicLength+3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER); - if( currentTopicNr >= 0){ + dataLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER); + if (currentTopicNr >= 0) + { writeDataToTopic(currentTopicNr, _bufferTopic, _bufferPayload); update(_topic[currentTopicNr], topicLength, _data[currentTopicNr], dataLength); } } } - else if(_readBufferMessage[1] == MSG_SUBSCRIBE){ + else if (_readBufferMessage[1] == MSG_SUBSCRIBE) + { topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_DELIMITER); - if(topicLength > 0){ + if (topicLength > 0) + { currentTopicNr = getTopicNr(_bufferTopic); - if(currentTopicNr >= 0){ + if (currentTopicNr >= 0) + { update(_topic[currentTopicNr], strlen(_topic[currentTopicNr]), _data[currentTopicNr], strlen(_data[currentTopicNr])); } } } -return true; + return true; } -bool DidacticPSNetBroker::update(char* topic, int topicLength, char* data , int dataLength){ - _sendBufferMessage[0] = MSG_PRELIMITER; - _sendBufferMessage[1] = MSG_UPDATE; - _sendBufferMessage[2+topicLength] = MSG_SEPARATOR; - _sendBufferMessage[2+topicLength+1+dataLength] = MSG_DELIMITER; - _sendBufferMessage[2+topicLength+1+dataLength+1] = '\0'; - - if(topicLength <= MAX_LEN_TOPICS){ - for(int i = 0; i < topicLength; i++){ - _sendBufferMessage[2+i] = topic[i]; - } - }else { +bool DidacticPSNetBroker::update(char *topic, int topicLength, char *data, int dataLength) +{ + _sendBufferMessage[0] = MSG_PRELIMITER; + _sendBufferMessage[1] = MSG_UPDATE; + _sendBufferMessage[2 + topicLength] = MSG_SEPARATOR; + _sendBufferMessage[2 + topicLength + 1 + dataLength] = MSG_DELIMITER; + _sendBufferMessage[2 + topicLength + 1 + dataLength + 1] = '\0'; + + if (topicLength <= MAX_LEN_TOPICS) + { + for (int i = 0; i < topicLength; i++) + { + _sendBufferMessage[2 + i] = topic[i]; + } + } + else + { _dataToSend = false; - return false; - } - if(dataLength <= MAX_LEN_PAYLOAD){ - for(int i = 0; i < dataLength; i++){ - _sendBufferMessage[2+topicLength+1+i] = data[i]; - } - }else { + return false; + } + if (dataLength <= MAX_LEN_PAYLOAD) + { + for (int i = 0; i < dataLength; i++) + { + _sendBufferMessage[2 + topicLength + 1 + i] = data[i]; + } + } + else + { _dataToSend = false; - return false; - } + return false; + } _dataToSend = true; - return true; + return true; } -int DidacticPSNetBroker::getTopicNr(char* topic){ - for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++) { - if (strcmp(_topic[i], topic) == 0) { +int DidacticPSNetBroker::getTopicNr(char *topic) +{ + for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++) + { + if (strcmp(_topic[i], topic) == 0) + { return i; - } - } - return getFreeTopicNr(); + } + } + return getFreeTopicNr(); } -int DidacticPSNetBroker::getFreeTopicNr() { - for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++) { - if (strcmp(_topic[i], "") == 0) { +int DidacticPSNetBroker::getFreeTopicNr() +{ + for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++) + { + if (strcmp(_topic[i], "") == 0) + { return i; } } return -1; } - //************************************************************************** -//LITTLE HELPERS FOR CLIENTS ;-) +// LITTLE HELPERS FOR CLIENTS ;-) //************************************************************************* EdgeDetector::EdgeDetector(){}; EdgeDetector::~EdgeDetector(){}; -int EdgeDetector::edgeDetected(bool currentState){ +int EdgeDetector::edgeDetected(bool currentState) +{ static bool lastState = false; int edEdge = 0; - if(currentState && !lastState){ + if (currentState && !lastState) + { edEdge = RISING; } - else if(!currentState && lastState){ + else if (!currentState && lastState) + { edEdge = FALLING; } lastState = currentState; return edEdge; } -ChangeDetector::ChangeDetector(){} -ChangeDetector::~ChangeDetector(){} +ChangeDetector::ChangeDetector() {} +ChangeDetector::~ChangeDetector() {} -bool ChangeDetector::valueChanged(int value, int threshold){ +bool ChangeDetector::valueChanged(int value, int threshold) +{ static int lastValue = 0; - if(abs(value-lastValue) > threshold){ + if (abs(value - lastValue) > threshold) + { lastValue = value; return true; } return false; } +UnblockingTimer::UnblockingTimer() {} +UnblockingTimer::~UnblockingTimer() {} -UnblockingTimer::UnblockingTimer(){} -UnblockingTimer::~UnblockingTimer(){} - -bool UnblockingTimer::timeElapsed(long delayTime){ +bool UnblockingTimer::timeElapsed(long delayTime) +{ long currentTime = millis(); - if(lastTime + (delayTime-1) < currentTime){ + if (lastTime + (delayTime - 1) < currentTime) + { lastTime = currentTime; return true; } return false; } -SerialReader::SerialReader(){} -SerialReader::~SerialReader(){} +SerialReader::SerialReader() {} +SerialReader::~SerialReader() {} -void SerialReader::begin(Stream& rsStream){ +void SerialReader::begin(Stream &rsStream) +{ _port = &rsStream; } -int SerialReader::readSerialData(char* rsDataArray, char rsEndSign) { +int SerialReader::readSerialData(char *rsDataArray, char rsEndSign) +{ - if (_port->available()) { + if (_port->available()) + { char charBuffer = _port->read(); rsDataArray[charCounter] = charBuffer; - if (charBuffer == rsEndSign) { + if (charBuffer == rsEndSign) + { rsDataArray[charCounter] = '\0'; int nrOfChars = charCounter; charCounter = 0; - return nrOfChars; - } else { + return nrOfChars; + } + else + { charCounter++; } } return 0; +} + +serialMonitorUI::serialMonitorUI() {} +serialMonitorUI::~serialMonitorUI() {} + +char serialMonitorUI::extractCommand(char *userInput) +{ + if ((userInput[0] >= 33 && userInput[0] <= 47) || ((userInput[0] >= 58 && userInput[0] <= 64))) // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ + { + char command = userInput[0]; + strcpy(userInput, &userInput[1]); + return command; + } + return DN_ASCII_EOS; +} + +bool serialMonitorUI::available() +{ + if (SerialReader::readSerialData(_currentInput, DN_ASCII_CR) > 0) + { + _currentCommand = extractCommand(_currentInput); + return true; + } + + return false; +} + +char serialMonitorUI::readCommand() +{ + return _currentCommand; +} + +void serialMonitorUI::readUserInput(char *inputData) +{ + strcpy(inputData, _currentInput); } \ No newline at end of file diff --git a/src/DidacticNet.h b/src/DidacticNet.h index 3480fe81241491c7548a2aa2e4f9c43c95488e80..08c21c69262088ce44d9c28b59d73c325e73d3e0 100644 --- a/src/DidacticNet.h +++ b/src/DidacticNet.h @@ -1,217 +1,240 @@ /************************************************************************** - @file DidacticNet.h - @author anian buehler @ letsgoING + @file DidacticNet.h + @author anian buehler @ letsgoING **************************************************************************/ - #ifndef _DIDACTICNET_ #define _DIDACTICNET_ #include "Arduino.h" -#ifdef CALLBACK_W_LENGTH - //callback(topic, topicLength, payload, payloadLength) - #define PSNET_CALLBACK_SIGNATURE void (*callback)(char*, int, char*, int) +#ifdef CALLBACK_W_LENGTH +// callback(topic, topicLength, payload, payloadLength) +#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, int, char *, int) #else - //callback(topic, payload) - #define PSNET_CALLBACK_SIGNATURE void (*callback)(char*, char*) +// callback(topic, payload) +#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, char *) #endif +#define CLIENT_MODE_BASIC false +#define CLIENT_MODE_ADVANCED true + #define MSG_PRELIMITER '<' -#define MSG_DELIMITER '>' -#define MSG_SEPARATOR '|' +#define MSG_DELIMITER '>' +#define MSG_SEPARATOR '|' //@ publish → on publish check topic, then send topic-update //? subscribe → subscribe starts update, topic filter @client -//# update → update to specific topic Broker to client -#define MSG_PUBLISH '@' -#define MSG_SUBSCRIBE '?' -#define MSG_UPDATE '#' +// # update → update to specific topic Broker to client +#define MSG_PUBLISH '@' +#define MSG_SUBSCRIBE '?' +#define MSG_UPDATE '#' #define MSG_TOPIC_MULTI '*' //<@topic|payload> -#define LEN_OVERHEAD 4 +#define LEN_OVERHEAD 4 #define CSMA_CHECK_DELAY_US 400 -#define CSMA_MIN_DELAY_MS 10 -#define CSMA_MID_DELAY_MS 20 -#define CSMA_MAX_DELAY_MS 30 +#define CSMA_MIN_DELAY_MS 10 +#define CSMA_MID_DELAY_MS 20 +#define CSMA_MAX_DELAY_MS 30 -#define INTERVAL_CLIENT 500L -#define INTERVAL_BROKER 0L +#define INTERVAL_CLIENT 500L +#define INTERVAL_BROKER 0L -#define MAX_NR_TOPICS_CLIENT 10 -#define MAX_NR_TOPICS_BROKER 20 -#define MAX_LEN_TOPICS 10 -#define MAX_LEN_PAYLOAD 20 +#define MAX_NR_TOPICS_CLIENT 10 +#define MAX_NR_TOPICS_BROKER 20 +#define MAX_LEN_TOPICS 10 +#define MAX_LEN_PAYLOAD 20 +#define MAX_LEN_USERINPUT 41 #define DN_PUBLISH_SUCCESSULL 1 -#define DN_ERROR_NO_ERROR 0 -#define DN_ERROR_TOPIC_LEN -1 +#define DN_ERROR_NO_ERROR 0 +#define DN_ERROR_TOPIC_LEN -1 #define DN_ERROR_PAYLOAD_LEN -2 -#define DN_ERROR_NO_TOPIC -3 - +#define DN_ERROR_NO_TOPIC -3 -//little helpers +// little helpers +#define DN_ASCII_EOS 0 #define DN_ASCII_CR 13 #define DN_ASCII_NL 10 - +#define DN_ASCII_DEL 127 class EdgeDetector { - private: - - public: - EdgeDetector(); - ~EdgeDetector(); - int edgeDetected(bool); - +private: +public: + EdgeDetector(); + ~EdgeDetector(); + int edgeDetected(bool); }; class ChangeDetector { - private: - - public: - ChangeDetector(); - ~ChangeDetector(); - bool valueChanged(int, int); - +private: +public: + ChangeDetector(); + ~ChangeDetector(); + bool valueChanged(int, int); }; class UnblockingTimer { - private: - long lastTime = 0L; - - public: - UnblockingTimer(); - ~UnblockingTimer(); - bool timeElapsed(long); +private: + long lastTime = 0L; +public: + UnblockingTimer(); + ~UnblockingTimer(); + bool timeElapsed(long); }; class SerialReader { - private: - Stream* _port; - int charCounter = 0; - - public: - SerialReader(); - ~SerialReader(); - void begin(Stream&); - int readSerialData(char*, char); +protected: + Stream *_port; + int charCounter = 0; + +public: + SerialReader(); + ~SerialReader(); + void begin(Stream &); + int readSerialData(char *, char); +}; +class serialMonitorUI : public SerialReader +{ +protected: + char _currentCommand = '\0'; + char _currentInput[MAX_LEN_USERINPUT + 1] = {'\0'}; + + char extractCommand(char *); + +public: + serialMonitorUI(); + ~serialMonitorUI(); + bool available(); + char readCommand(); + void readUserInput(char *); }; class DidacticPSNet { - protected: - Stream* _port; +protected: + Stream *_port; - PSNET_CALLBACK_SIGNATURE; + PSNET_CALLBACK_SIGNATURE; - char _bufferTopic[MAX_LEN_TOPICS +1] = {0}; - char _bufferPayload[MAX_LEN_PAYLOAD +1] = {0}; - char _readBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD +1]; - char _sendBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD +1]; + char _bufferTopic[MAX_LEN_TOPICS + 1] = {0}; + char _bufferPayload[MAX_LEN_PAYLOAD + 1] = {0}; + char _readBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD + 1]; + char _sendBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD + 1]; - bool _dataToSend = false; // int Data to send for queue? - unsigned long _waitingTimeSend = 0L; - unsigned long _waitingTimeCSMA = 0L; - unsigned long _intervalTime = 0L; - int _currentTopicLength = 0; - int _currentPayloadLength = 0; + bool _dataToSend = false; // int Data to send for queue? + unsigned long _waitingTimeSend = 0L; + unsigned long _waitingTimeCSMA = 0L; + unsigned long _intervalTime = 0L; + int _currentTopicLength = 0; + int _currentPayloadLength = 0; - DidacticPSNet& setCallback(PSNET_CALLBACK_SIGNATURE); + DidacticPSNet &setCallback(PSNET_CALLBACK_SIGNATURE); - void setStream(Stream& _port); + void setStream(Stream &_port); - int checkData(); - bool recieveData(); - bool sendData(); - int extractData(int, int, char*, char); - void writeDataToTopic(char*, char*); - virtual int getTopicNr(char*)=0; - virtual int getFreeTopicNr()=0; - virtual bool getMessageFilter(char)=0; - virtual bool savePayload(char*, int)=0; - virtual bool handleData()=0; + int checkData(); + bool recieveData(); + bool sendData(); + int extractData(int, int, char *, char); + void writeDataToTopic(char *, char *); + virtual int getTopicNr(char *) = 0; + virtual int getFreeTopicNr() = 0; + virtual bool getMessageFilter(char) = 0; + virtual bool savePayload(char *, int) = 0; + virtual bool handleData() = 0; - public: - DidacticPSNet(); - ~DidacticPSNet(); +public: + DidacticPSNet(); + ~DidacticPSNet(); - void begin(Stream& _port); - void begin(Stream& _port, PSNET_CALLBACK_SIGNATURE); + void begin(Stream &_port); + void begin(Stream &_port, PSNET_CALLBACK_SIGNATURE); - bool handleNetwork(); - bool isDataToSend(); - - void setInterval(long); + bool handleNetwork(); + bool isDataToSend(); + void setInterval(long); }; -class DidacticPSNetClient : public DidacticPSNet +class DidacticPSNetClient : public DidacticPSNet { - private: - EdgeDetector eDetector; - ChangeDetector cDetector; +private: + EdgeDetector eDetector; + ChangeDetector cDetector; + + char _topic[MAX_NR_TOPICS_CLIENT][MAX_LEN_TOPICS + 1] = {{0}}; + char _payload[MAX_NR_TOPICS_CLIENT][MAX_LEN_PAYLOAD + 1] = {{0}}; - char _topic[MAX_NR_TOPICS_CLIENT][MAX_LEN_TOPICS+1] = { { 0 } }; - char _payload[MAX_NR_TOPICS_CLIENT][MAX_LEN_PAYLOAD+1] = { { 0 } }; + bool _clientMode = CLIENT_MODE_ADVANCED; // new + bool _newMessageAvailable = false; + int _newMessageTopicNr = 0; // new + char _currentTopic[MAX_LEN_TOPICS + 1] = {0}; // new + char _currentPayload[MAX_LEN_PAYLOAD + 1] = {0}; // new - bool savePayload(char*, int); + bool savePayload(char *, int); bool getMessageFilter(char); bool handleData(); - int getTopicNr(char*); + int getTopicNr(char *); int getFreeTopicNr(); int edgeDetected(bool); bool valueChanged(int, int); - public: +public: DidacticPSNetClient(); ~DidacticPSNetClient(); + void begin(Stream &_port); // new + + bool available(); // new + int readLatestTopicNr(); // new + void readTopic(char *); // new + void readTopic(int, char *); // new + void readPayload(char *); // new + void readPayload(int, char *); // new + void readPayload(char *, char *); // new + int getMaxNrTopics(); - int getSubscribedTopic(char*, int); - - - int publish(char*, char*); - int publish(char*, int, char*, int); - int publish(char*, int); - int publish(char*, bool); - int publishOnChange(char*, bool); - int publishOnChange(char*, int, int); - int subscribe(char*); - int subscribe(char*, int); - bool unsubscribe(char*); - bool unsubscribe(char*, int); + int getSubscribedTopic(char *, int); + + int publish(char *, char *); + int publish(char *, int, char *, int); + int publish(char *, int); + int publish(char *, bool); + int publishOnChange(char *, bool); + int publishOnChange(char *, int, int); + int subscribe(char *); + int subscribe(char *, int); + bool unsubscribe(char *); + bool unsubscribe(char *, int); }; - -class DidacticPSNetBroker: public DidacticPSNet +class DidacticPSNetBroker : public DidacticPSNet { - private: - char _topic[MAX_NR_TOPICS_BROKER][MAX_LEN_TOPICS+1] = { { 0 } }; - char _data[MAX_NR_TOPICS_BROKER][MAX_LEN_PAYLOAD+1] = { { 0 } }; +private: + char _topic[MAX_NR_TOPICS_BROKER][MAX_LEN_TOPICS + 1] = {{0}}; + char _data[MAX_NR_TOPICS_BROKER][MAX_LEN_PAYLOAD + 1] = {{0}}; - bool savePayload(char*, int); + bool savePayload(char *, int); bool getMessageFilter(char); - void writeDataToTopic(int, char*, char*); + void writeDataToTopic(int, char *, char *); bool handleData(); - int getTopicNr(char*); + int getTopicNr(char *); int getFreeTopicNr(); - public: +public: DidacticPSNetBroker(); ~DidacticPSNetBroker(); - bool update(char*, int, char*, int); - - + bool update(char *, int, char *, int); }; - #endif