Untested port of the Ishtar protocol, actually not much of a port since there was really not much to change. http://kisvm2.epfl.ch/record/125676/files/emav08-ishtar-final.pdf
Revision 0:086ea145b6d7, committed 2011-05-12
- Comitter:
- ssozonoff
- Date:
- Thu May 12 08:30:17 2011 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 086ea145b6d7 ishtar.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ishtar.cpp Thu May 12 08:30:17 2011 +0000 @@ -0,0 +1,1601 @@ +/* + Ishtar Embedded + Copyright (C) 2008-2010: + + Alexandre Habersaat <alexandre dot habersaat at gmail dot com> + Antoine Beyeler <abeyeler at ab-ware dot com> + (http://www.ab-ware.com) + Stephane Magnenat <stephane at magnenat dot net> + (http://stephane.magnenat.net) + + All rights reserved. + + Ishtar Embedded is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Ishtar Embedded is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Ishtar Embedded. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*! +* \file ishtar.c +* \brief Main file of the Ishtar Embedded server +* +* \author Alexandre Habersaat, Antoine Beyeler +* +* This file contains the core of the Ishtar Embedded server +*/ + +#include "ishtar.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Macro for FAR directive +#if defined(__dsPIC33F__) || defined(__PIC24F__) + #define ISHTAR_ATTRIBUTE_FAR __attribute__((far)) +#else + #define ISHTAR_ATTRIBUTE_FAR +#endif + + +//! The reception buffer of the server +unsigned char ishtar_buffer[ISHTAR_BUFFER_SIZE] ISHTAR_ATTRIBUTE_FAR; + +// Statistics +//! The number of overflows that occured in the reception buffer +unsigned long ishtar_numberOfOverflows = 0; +//! The number of bytes dropped in the state Header1 +unsigned long ishtar_numberOfDropHeader1 = 0; +//! The number of bytes dropped in the state Header2 +unsigned long ishtar_numberOfDropHeader2 = 0; +//! The number of bytes dropped in the state Header3 +unsigned long ishtar_numberOfDropHeader3 = 0; +//! The number of bytes dropped in the state Header4 +unsigned long ishtar_numberOfDropHeader4 = 0; +//! The number of messages dropped after a size checksum error +unsigned long ishtar_numberOfDropSize = 0; +//! The number of messages dropped after a content checksum error +unsigned long ishtar_numberOfDropContent = 0; +//! The total number of bytes received +unsigned long ishtar_numberOfBytesReceived = 0; +//! The total number of bytes sent +unsigned long ishtar_numberOfBytesSent = 0; +//! The total number of bytes read from memory +unsigned long ishtar_numberOfBytesReadFromMemory = 0; +//! The total number of bytes written to memory +unsigned long ishtar_numberOfBytesWrittenToMemory = 0; +//! The number of messages that were valid +unsigned long ishtar_numberOfValidMessages = 0; +//! The number of messages that were valid but contained invalid data (client error or wrong checksum validated) +unsigned long ishtar_corruptedValidated = 0; +//! The snapshot size +unsigned long ishtar_snapshotSize = 0; +//! If an error occured with the non-volatile memory +unsigned char ishtar_memoryError = NO_ERROR; + +//! The number of services / variables registered +ishtar_ServiceId ishtar_numberOfVariables = 0; +//! The registry of the services / variables +ishtar_ServiceDescription ishtar_services[ISHTAR_MAX_NUMBER_OF_SERVICES] ISHTAR_ATTRIBUTE_FAR; + +//! The Id of the active snapshot (or the last one if none is active) +ishtar_RequestId ishtar_snapshotId = 0; +//! Snapshot active +unsigned char ishtar_snapshotActive = 0; + + +// read buffer +//! The start of the reception buffer +unsigned char * ishtar_bufBegin; +//! The end of the reception buffer +unsigned char * ishtar_bufEnd; +//! The position to write in the buffer for the next byte that is received +unsigned char * ishtar_bufPos; + +//! The position of the next char to be consumed. +unsigned char * ishtar_consumePos; +//! Begining of the data payload of the current packet +unsigned char* ishtar_dataStartMarker; +//! The start of the first packet waiting to be treated in the buffer +unsigned char * ishtar_packetBegin = 0; + +//! The state to read the first byte of message header +#define ISHTAR_STATE_HEADER1 1 +//! The state to read the second byte of message header +#define ISHTAR_STATE_HEADER2 2 +//! The state to read the third byte of message header +#define ISHTAR_STATE_HEADER3 3 +//! The state to read the fourth byte of message header +#define ISHTAR_STATE_HEADER4 4 +//! The state to read the size of message +#define ISHTAR_STATE_SIZE 5 +//! The state to read the checksum of the size of the message +#define ISHTAR_STATE_CHECKSUM_SIZE 6 +//! The state to read the content of the message +#define ISHTAR_STATE_CONTENT 7 +//! The state to read the checksum of the content of the message +#define ISHTAR_STATE_CHECKSUM_CONTENT 8 + +//! The current state of the state machine for reception +unsigned char ishtar_state = ISHTAR_STATE_HEADER1; +//! Detects overflows in the reception buffer +unsigned char ishtar_overFlow = 0; +//! The current byte of the size being read +unsigned char ishtar_sizeByteNum = 0; +//! The current bypte of the checksum being read +unsigned char ishtar_checksumByteNum = 0; + +// Checksum read +//! The checksum read for the size +unsigned short ishtar_sizeChecksumRead = 0; +//! The ckecksum read for the content +unsigned short ishtar_contentChecksumRead = 0; +// Checksum calculated +//! Temporary variables to calculate checksums +unsigned char ishtar_ckA, ishtar_ckB; +//! The total size of the current packet +unsigned long ishtar_curPacketSize = 0; +//! The number of bytes read for the current packet +unsigned long ishtar_curSize = 0; + +//! At least one client is connected to the server +unsigned char ishtar_connected = 0; + +// Non-volatile memory access +//! The lowest memory address that Ishtar is allowed to read/write +unsigned short ishtar_memoryMinAddress = 0; +//! The highest memory address that Ishtar is allowed to read/write +unsigned short ishtar_memoryMaxAddress = 0; +//! The external function to read the non-volatile memory +ishtar_MemoryReadFunc ishtar_memoryReadFunc = 0; +//! The external function to write the non-volatile memory +ishtar_MemoryWriteFunc ishtar_memoryWriteFunc = 0; +//! The checksum A for the non-volatile memory consistency +unsigned char ishtar_memoryChecksumA = 0; +//! The checksum B for the non-volatile memory consistency +unsigned char ishtar_memoryChecksumB = 0; + +// Send function +//! The external function to call to send data through communication +ishtar_ExternalSendFunc ishtar_externalSendFunc; +//! The external function to call to send the first heavy messages (blocking function) +ishtar_ExternalSendFunc ishtar_externalSendBlockingFunc; +//! The current function that is used to send data (blocking or non-blocking) +ishtar_ExternalSendFunc ishtar_currentSendFunc; +//! The external function to flush the content of the external output buffer (if used) +ishtar_ExternalFlushFunc ishtar_externalFlushFunc; + +//! The intermediate function to send data and calculate the checksum of the sent data +void ishtar_SendData(unsigned char * data, unsigned long len); +//! The function to send the message header +void ishtar_SendHeader(); +//! The function to reset the checksums +void ishtar_InitCk(); +//! The function to send the current checksum of the message +void ishtar_SendCk(); + +//! An empty function +void ishtar_DoNothing() { } + +//! This function inits the pointers to the reception buffer +void ishtar_InitBuffer(); +//! This function is used for debug, to register statistics variables into Ishtar +void ishtar_RegisterDebugVars(); + +// utils +//! This function is used to calculate the checksum of a size +unsigned short ishtar_CalculateSizeChecksum(unsigned long size); +//! This function normalizes an address (usually old address + offset) to stay inside the reception buffer +inline unsigned char * ishtar_WrapAddr(unsigned char * addr); +//! This function increments the address of the reception buffer +inline void ishtar_IncAddr(unsigned char ** addr, unsigned long size); + +//! This function reads the content of an address and copies it into a variable (target) +inline void ishtar_At(unsigned char ** addr, unsigned char * target, unsigned char size); +// This function reads the content of an address, copies it into a variable and increment the address to the next position +inline void ishtar_AtInc(unsigned char ** addr, unsigned char * target, unsigned char size); + +//! This function sends a zero-terminated string +void ishtar_SendString(const char * sz); +//! This function sends the value of a variable +void ishtar_SendValue(unsigned char * value, ishtar_ValueVectorType type, unsigned long index); +//! This function reads a value in a buffer, write it into the registry and increments the read buffer +void ishtar_SetValueInc(unsigned char * value, ishtar_ValueVectorType type, unsigned long index, unsigned char ** addr); + +//! This function returns the length of a zero-terminated string or ISHTAR_STRING_MAX_SIZE +unsigned long ishtar_Strlen(const char * addr); +//! This function returns the size of a type +unsigned long ishtar_TypeSize(ishtar_ValueVectorType type); + +// treat messages +//! This function decodes the type of a packet and call the corresponding dedicated function +void ishtar_HandlePacket(unsigned char * addr, unsigned long len); +//! This function decodes the content of a Hello packet and sends the answer +void ishtar_HandleHelloCall(unsigned char * addr, unsigned long len); +//! This function decodes the content of a GetServiceList packet and sends the answer +void ishtar_HandleGetServiceListCall(unsigned char * addr, unsigned long len); +//! This function decodes the content of a Get packet and sends the answer. It may also set up a snapshot. +void ishtar_HandleGetCall(unsigned char * addr, unsigned long len); +//! This function decodes the content of a Set packet and executes the modification on the local service registry +void ishtar_HandleSetCall(unsigned char * addr, unsigned long len); +//! This function decodes the content of a disconnection packet and stops the snapshot +void ishtar_HandleByeByeCall(unsigned char * addr, unsigned long len); + +/*! +* This function normalizes an address (usually old address + offset) to stay inside the reception buffer +*/ +inline unsigned char * ishtar_WrapAddr(unsigned char * addr) +{ + if (addr >= ishtar_bufEnd) + { + return (unsigned char*)((unsigned int)ishtar_bufBegin + (unsigned int)addr - (unsigned int)ishtar_bufEnd); + } + else + { + return addr; + } +} + +/*! +* This function increments the address of the reception buffer +*/ +inline void ishtar_IncAddr(unsigned char ** addr, unsigned long size) +{ + *addr += size; + *addr = ishtar_WrapAddr(*addr); +} + +/*! +* This function reads the content of an address and copies it into a variable (target) +*/ +inline void ishtar_At(unsigned char ** addr, unsigned char * target, unsigned char size) +{ + unsigned char i; + + for (i = 0; i < size; ++i) + { + target[i] = *ishtar_WrapAddr(*addr + i); + } +} + +/*! +* This function reads the content of an address, copies it into a variable and increment the address to the next position +*/ +inline void ishtar_AtInc(unsigned char ** addr, unsigned char * target, unsigned char size) +{ + ishtar_At(addr, target, size); + ishtar_IncAddr(addr, size); +} + + + +/*! +* This function sends a zero-terminated string +*/ +void ishtar_SendString(const char * sz) +{ + // 4 name.type + ishtar_ValueVectorSize nameSize; + unsigned long j; + + // 4 name.size + nameSize = ishtar_Strlen(sz); + ishtar_SendData((unsigned char*)(&nameSize), sizeof(ishtar_ValueVectorSize)); + // X name + for (j = 0; j < nameSize; ++j) + { + ishtar_SendData((unsigned char*)&(sz[j]), 1); + } +} + +/*! +* This function sends the value of an element of a local variable +* +* @param value The pointer to the variable to read +* @param type The type of the variable +* @param index The index of the element to read +*/ +void ishtar_SendValue(unsigned char * value, ishtar_ValueVectorType type, unsigned long index) +{ + unsigned long size; + unsigned char * val; + + size = ishtar_TypeSize(type); + val = (unsigned char*) value; + ishtar_SendData(&val[size * index], size); +} + +/*! +* This function modifies the value of one element of a local variable +* +* @param value The pointer to the variable to set +* @param type The type of the variable to set +* @param index The index of the element to set (or 0 for a normal variable) +* @param addr The address from which to read the value to set +*/ +void ishtar_SetValueInc(unsigned char * value, ishtar_ValueVectorType type, unsigned long index, unsigned char ** addr) +{ + unsigned long i; + unsigned long size; + + size = ishtar_TypeSize(type); + + for (i = 0; i < size; ++i) + { + value[size*index+i] = **addr; + *addr = ishtar_WrapAddr(*addr + 1); + } +} + +/*! +* This function calculates the checksum of a 4-bytes size +* +* @return The size on which the checksum is calculated +* @return The calculated checksum +*/ +unsigned short ishtar_CalculateSizeChecksum(unsigned long size) +{ + unsigned char i; + unsigned char * p; + unsigned char ckA, ckB; + + ckA = 0; + ckB = 0; + p = (unsigned char*)(&size); + for (i = 0; i < 4; ++i) + { + ckA += *(p + i); + ckB += ckA; + } + + return (ckA << 8 | ckB); +} + +/*! +* This function sends any data. The data sent are added to the current checksums +* +* @param data A pointer to the data to send +* @param len The number of bytes to send from the pointer +*/ +void ishtar_SendData(unsigned char * data, unsigned long len) +{ + // Add checksums + unsigned long i; + for (i = 0; i < len; ++i) + { + ishtar_ckA += data[i]; + ishtar_ckB += ishtar_ckA; + } + // send data + ishtar_currentSendFunc(data, len); + + ishtar_numberOfBytesSent += len; +} + +/*! +* This function sends the Ishtar headers +*/ +void ishtar_SendHeader() +{ + // unsigned long header; + unsigned char h1, h2, h3, h4; + h1 = ISHTAR_HEADER1; + h2 = ISHTAR_HEADER2; + h3 = ISHTAR_HEADER3; + h4 = ISHTAR_HEADER4; + + //header = (ISHTAR_HEADER1) | (ISHTAR_HEADER2 << 8) | (ISHTAR_HEADER3 << 16) | (ISHTAR_HEADER4 << 24); + ishtar_currentSendFunc(&h1, 1); + ishtar_currentSendFunc(&h2, 1); + ishtar_currentSendFunc(&h3, 1); + ishtar_currentSendFunc(&h4, 1); +} + +/*! +* This function resets the current checksum +*/ +void ishtar_InitCk() +{ + // initialise checksums to 0 + ishtar_ckA = 0; + ishtar_ckB = 0; +} + +/*! +* This function sends the current checksum +*/ +void ishtar_SendCk() +{ + // compile actual checksums + unsigned short checksum; + checksum = (ishtar_ckA << 8) | ishtar_ckB; + + // send the compiled checksum + ishtar_currentSendFunc((unsigned char*)(&checksum), 2); +} + +/*! +* This function is provided for convenience if multiple bytes are received at once. +* It will call ishtar_ReceiveDataByte() for each of these data bytes +*/ +void ishtar_ReceiveData(unsigned char * data, unsigned long len) +{ + unsigned long i; + for (i = 0; i < len; ++i) + { + ishtar_ReceiveDataByte(data[i]); + } +} + +/*! +* This function buffers all incoming bytes without processing them. It drop +* any byte in case of buffer overflow. +*/ +void ishtar_ReceiveDataByte(unsigned char c) +{ + ++ishtar_numberOfBytesReceived; + + unsigned char* nextAddr = ishtar_WrapAddr(ishtar_bufPos + 1); + if (nextAddr == ishtar_packetBegin) + { + // we have an overflow + ishtar_overFlow = 1; + ishtar_numberOfOverflows++; + } + else + { + *ishtar_bufPos = c; + ishtar_bufPos = nextAddr; + } +} + + +/*! +* This function process bytes from the buffer with a state machine. When a packet +* is completed, it calls #ishtar_HandlePacket(). +* +* @param addr The address of the byte to process. +*/ +void ishtar_ConsumeBufferedByte(unsigned char* addr) +{ + unsigned char * p; + unsigned long i; + unsigned char ckA, ckB; + + unsigned char c = *addr; + + + if (ishtar_state == ISHTAR_STATE_CONTENT) + { + if (ishtar_curSize == 0) + ishtar_dataStartMarker = addr; + + // Increase size + ++ishtar_curSize; + + // end of packet + if (ishtar_curSize == ishtar_curPacketSize) + { + ishtar_contentChecksumRead = 0; + ishtar_checksumByteNum = 0; + ishtar_state = ISHTAR_STATE_CHECKSUM_CONTENT; + } + } + else if (ishtar_state == ISHTAR_STATE_SIZE) + { + p = (unsigned char*)(&ishtar_curPacketSize); + *( p + ishtar_sizeByteNum++ ) = c; + + if (ishtar_sizeByteNum == ISHTAR_NUMBER_OF_SIZE_BYTES) + { + ishtar_sizeChecksumRead = 0; + ishtar_checksumByteNum = 0; + ishtar_state = ISHTAR_STATE_CHECKSUM_SIZE; + } + } + else if (ishtar_state == ISHTAR_STATE_HEADER1) + { + if (c == ISHTAR_HEADER1) + ishtar_state = ISHTAR_STATE_HEADER2; + else + ++ishtar_numberOfDropHeader1; + } + else if (ishtar_state == ISHTAR_STATE_CHECKSUM_SIZE) + { + p = (unsigned char*)(&ishtar_sizeChecksumRead); + *(p + ishtar_checksumByteNum++) = c; + + if (ishtar_checksumByteNum == ISHTAR_NUMBER_OF_CHECKSUM_BYTES) + { + p = (unsigned char*)(&ishtar_curPacketSize); + + // calculate checksum of size + ckA = 0; + ckB = 0; + for (i = 0; i < ISHTAR_NUMBER_OF_SIZE_BYTES; ++i) + { + ckA += (ishtar_curPacketSize >> (8 * i)) & 0xFF; + ckB += ckA; + } + + if (ishtar_sizeChecksumRead == (ckA << 8 | ckB)) + { + ishtar_curSize = 0; + ishtar_state = ISHTAR_STATE_CONTENT; + } + else + { + ++ishtar_numberOfDropSize; + ishtar_state = ISHTAR_STATE_HEADER1; + } + } + } + else if (ishtar_state == ISHTAR_STATE_CHECKSUM_CONTENT) + { + p = (unsigned char*)(&ishtar_contentChecksumRead); + *(p + ishtar_checksumByteNum++) = c; + + if (ishtar_checksumByteNum == ISHTAR_NUMBER_OF_CHECKSUM_BYTES) + { + // calculate checksum of content, start after the size + ckA = 0; + ckB = 0; + for (i = 0; i < ishtar_curPacketSize; ++i) + { + ckA += *(ishtar_WrapAddr(ishtar_dataStartMarker + i)); + ckB += ckA; + } + + // checksum correct + if (ishtar_contentChecksumRead == (ckA << 8 | ckB)) + { + // handle the packet + ishtar_HandlePacket(ishtar_dataStartMarker, ishtar_curPacketSize); + ++ishtar_numberOfValidMessages; + } + else + ++ishtar_numberOfDropContent; + + // the begining of the buffer is at the next char in all cases. + ishtar_packetBegin = ishtar_WrapAddr(addr + 1); + + // go back for next message + ishtar_state = ISHTAR_STATE_HEADER1; + } + } + else if (ishtar_state == ISHTAR_STATE_HEADER2) + { + if (c == ISHTAR_HEADER2) + ishtar_state = ISHTAR_STATE_HEADER3; + else if (c == ISHTAR_STATE_HEADER1) + { + ishtar_state = ISHTAR_STATE_HEADER2; + ++ishtar_numberOfDropHeader2; + } + else + { + ishtar_state = ISHTAR_STATE_HEADER1; + ++ishtar_numberOfDropHeader2; + } + } + else if (ishtar_state == ISHTAR_STATE_HEADER3) + { + if (c == ISHTAR_HEADER3) + ishtar_state = ISHTAR_STATE_HEADER4; + else if (c == ISHTAR_STATE_HEADER1) + { + ishtar_state = ISHTAR_STATE_HEADER2; + ++ishtar_numberOfDropHeader3; + } + else + { + ishtar_state = ISHTAR_STATE_HEADER1; + ++ishtar_numberOfDropHeader3; + } + } + else if (ishtar_state == ISHTAR_STATE_HEADER4) + { + if (c == ISHTAR_HEADER4) + { + ishtar_state = ISHTAR_STATE_SIZE; + ishtar_curPacketSize = 0; + ishtar_sizeByteNum = 0; + } + else if (c == ISHTAR_STATE_HEADER1) + { + ishtar_state = ISHTAR_STATE_HEADER2; + ++ishtar_numberOfDropHeader4; + } + else + { + ishtar_state = ISHTAR_STATE_HEADER1; + ++ishtar_numberOfDropHeader4; + } + } + else + ishtar_state = ISHTAR_STATE_HEADER1; +} + +// step + +/*! +* This function checks if there are some packets to treat in the input buffer +* If yes, it calls the decoding functions which send the answers to these packets. +*/ +void ishtar_Step() +{ + // atomically read the curent bufPos + unsigned char* bufPos = ishtar_bufPos; + + while (ishtar_consumePos != bufPos) + { + ishtar_ConsumeBufferedByte(ishtar_consumePos); + ishtar_consumePos = ishtar_WrapAddr(ishtar_consumePos + 1); + } +} + +/*! +* This function reads the start of a packet and determines it type. +* It then calls the corresponding dedicated function to decode the packet. +*/ +void ishtar_HandlePacket(unsigned char * addr, unsigned long len) +{ + ishtar_MessageId type; + + ishtar_AtInc(&addr, (unsigned char*)&type, sizeof(ishtar_MessageId)); + + switch (type) + { + case HELLO: + { + ishtar_HandleHelloCall(addr, len - sizeof(ishtar_MessageId)); + break; + } + case GET_SERVICE_LIST: + { + ishtar_HandleGetServiceListCall(addr, len - sizeof(ishtar_MessageId)); + break; + } + case GET_VALUES: + { + ishtar_HandleGetCall(addr, len - sizeof(ishtar_MessageId)); + break; + } + case SET_VALUES: + { + ishtar_HandleSetCall(addr, len - sizeof(ishtar_MessageId)); + break; + } + case BYE_BYE: + { + ishtar_HandleByeByeCall(addr, len - sizeof(ishtar_MessageId)); + break; + } + default: + { + return; + } + } +} + +/*! +* This function decodes the Hello calls and sends the Hello answer +*/ +void ishtar_HandleHelloCall(unsigned char * addr, unsigned long len) +{ + + // Stop snapshot when hello received + ishtar_snapshotActive = 0; + + ishtar_NodeType nodeType; + ishtar_VersionType version; + + ishtar_MessageId hello = HELLO; + ishtar_ProtocolType protocol; + + unsigned long answerSize; + unsigned short sizeChecksum; + + // READ + ishtar_AtInc(&addr, (unsigned char*)&nodeType, sizeof(ishtar_NodeType)); + ishtar_AtInc(&addr, (unsigned char*)&version, sizeof(ishtar_VersionType)); + + // CALCULATE + if (version == ISHTAR_PROTOCOL_VERSION) + protocol = EMBEDDED; + else + protocol = INCOMPATIBLE; + + // SEND + answerSize = sizeof(ishtar_MessageId) + sizeof(ishtar_ProtocolType); + sizeChecksum = ishtar_CalculateSizeChecksum(answerSize); + + ishtar_currentSendFunc = ishtar_externalSendBlockingFunc; + ishtar_SendHeader(); + // send size and size checksum + ishtar_SendData((unsigned char*)(&answerSize), sizeof(unsigned long)); + ishtar_SendData((unsigned char*)(&sizeChecksum), sizeof(unsigned short)); + // send content + ishtar_InitCk(); + ishtar_SendData((unsigned char*)(&hello), sizeof(ishtar_MessageId)); + ishtar_SendData((unsigned char*)(&protocol), sizeof(ishtar_ProtocolType)); + ishtar_SendCk(); + + ishtar_externalFlushFunc(); + ishtar_currentSendFunc = ishtar_externalSendFunc; + + ishtar_connected = 1; +} + +/*! +* This function decodes the ServiceList calls and sends the list of all registered variables +*/ +void ishtar_HandleGetServiceListCall(unsigned char * addr, unsigned long len) +{ + // Nothing to read + // Calculate size + unsigned long answerSize; // AnswerType + numberOfVariables + ishtar_ServiceId i; + + ishtar_MessageId serviceList; + unsigned short sizeChecksum; + + // READ - nothing + + // SEND + answerSize = sizeof(ishtar_MessageId) + sizeof(ishtar_ServiceId); + serviceList = SERVICE_LIST; + // ID (4) + name.size(4) + name(X) + type(4) + flags(4) + length(4) + // Must be in a for loop as the name of services have different sizes + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + answerSize += sizeof(ishtar_ServiceId) + sizeof(ishtar_ValueVectorSize) + ishtar_Strlen(ishtar_services[i].name) + sizeof(ishtar_ValueVectorType) + sizeof(ishtar_ServiceFlags) + sizeof(ishtar_ValueVectorSize); + } + + // calculate size checksum + sizeChecksum = ishtar_CalculateSizeChecksum(answerSize); + + ishtar_currentSendFunc = ishtar_externalSendBlockingFunc; + ishtar_SendHeader(); + // send size and size checksum + ishtar_SendData((unsigned char*)(&answerSize), sizeof(unsigned long)); + ishtar_SendData((unsigned char*)(&sizeChecksum), sizeof(unsigned short)); + + // send content + ishtar_InitCk(); + ishtar_SendData((unsigned char*)(&serviceList), sizeof(ishtar_MessageId)); + ishtar_SendData((unsigned char*)(&ishtar_numberOfVariables), sizeof(ishtar_ServiceId)); + + // fill table + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + // 4 service id + ishtar_SendData((unsigned char*)(&i), sizeof(ishtar_ServiceId)); + // name.size(4) + name(X) + ishtar_SendString(ishtar_services[i].name); + // 4 service.type + ishtar_SendData((unsigned char*)(&(ishtar_services[i].type)), sizeof(ishtar_ValueVectorType)); + // 4 service.flags + ishtar_SendData((unsigned char*)(&(ishtar_services[i].flags)), sizeof(ishtar_ServiceFlags)); + // 4 service.length + ishtar_SendData((unsigned char*)(&(ishtar_services[i].length)), sizeof(ishtar_ValueVectorSize)); + } + + ishtar_SendCk(); + + ishtar_externalFlushFunc(); + ishtar_currentSendFunc = ishtar_externalSendFunc; +} + +/*! +* This function decodes the Get calls and sends the values for the requested data +*/ +void ishtar_HandleGetCall(unsigned char * addr, unsigned long len) +{ + // Read + ishtar_RequestId requestID; + ishtar_ServiceId numberOfIds; + ishtar_ValueVectorSize numberOfIndices; + + + unsigned long answerSize;// VALUES(4) + requestID(4) + size(4) + unsigned short sizeChecksum; + ishtar_ServiceId i; + ishtar_ValueVectorSize j; + + ishtar_ServiceId id; + ishtar_ValueVectorSize indice; + ishtar_ValueVectorSize length; + unsigned char snapshot = 0; + ishtar_MessageId values; + unsigned char * ids; + + // READ + ishtar_AtInc(&addr,(unsigned char*)&requestID, sizeof(ishtar_RequestId)); + ishtar_AtInc(&addr,(unsigned char*)&snapshot, sizeof(unsigned char)); + ishtar_AtInc(&addr,(unsigned char*)&numberOfIds, sizeof(ishtar_ServiceId)); + + if (snapshot) + { + // saves the snapshot id + ishtar_snapshotId = requestID; + // snapshot canceled + if (numberOfIds == 0) + { + ishtar_snapshotActive = 0; + } + // new snapshot asked + else + { + ishtar_snapshotActive = 1; + } + + // clear old snapshot + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + ishtar_services[i].inSnapshot = 0; + } + } + + ids = addr; + + // Size + answerSize = sizeof(ishtar_MessageId) + sizeof(ishtar_RequestId); + + values = VALUES; + + for (i = 0; i<numberOfIds; ++i) + { + // read id of service + ishtar_AtInc(&addr,(unsigned char*)&id, sizeof(ishtar_ServiceId)); + + // Problem, a corrupted message has been validated + if ( id >= ishtar_numberOfVariables) + { + ++ishtar_corruptedValidated; + return; + } + + // if the variable is in the snapshot + if (snapshot) + { + ishtar_services[id].inSnapshot = 1; + } + + // Read the number of indices + ishtar_AtInc(&addr,(unsigned char*)&numberOfIndices, sizeof(ishtar_ValueVectorSize)); + // Eat these indices, so that the next variable id is correct + for (j = 0; j < numberOfIndices; ++j) + { + ishtar_AtInc(&addr,(unsigned char*)&indice, sizeof(ishtar_ValueVectorSize)); + // Problem, a corrupter message has been validated + if (indice > ishtar_services[id].length) + { + ++ishtar_corruptedValidated; + return; + } + } + + // if the size is 0, it means variable size, so we must specify it. + if (ishtar_services[id].length == 0 && ishtar_services[id].type == UCHAR) + { + answerSize += sizeof(ishtar_ValueVectorSize);// size of the size + answerSize += ishtar_Strlen((char*)(ishtar_services[id].value)); // size of the data + } + else + { + // we only put the data in the next message + // here the full variable + if (numberOfIndices == 0) + { + answerSize += ((unsigned long)(ishtar_services[id].length)) * ishtar_TypeSize(ishtar_services[id].type); + } + // here only some values + else + { + answerSize += ((unsigned long)(numberOfIndices)) * ishtar_TypeSize(ishtar_services[id].type); + } + } + } + + // answer only if non-snapshot, otherwise it will be done in ishtar_Snapshot() + if (!snapshot) + { + sizeChecksum = ishtar_CalculateSizeChecksum(answerSize); + + // SEND + ishtar_SendHeader(); + // send size and size checksum + ishtar_SendData((unsigned char*)(&answerSize), 4); + ishtar_SendData((unsigned char*)(&sizeChecksum), 2); + + // send content + ishtar_InitCk(); + ishtar_SendData((unsigned char*)(&values), sizeof(ishtar_MessageId)); + ishtar_SendData((unsigned char*)(&requestID), sizeof(ishtar_RequestId)); + + for (i = 0; i < numberOfIds; ++i) + { + // service id + ishtar_AtInc(&ids, (unsigned char*)&id, sizeof(ishtar_ServiceId)); + // number of indices + ishtar_AtInc(&ids,(unsigned char*)&numberOfIndices, sizeof(ishtar_ValueVectorSize)); + + // length == 0 mean variable size, ONLY for char or UCHAR, with ended caracter equal to '\0' + if (ishtar_services[id].type == UCHAR && ishtar_services[id].length == 0) + { + length = ishtar_Strlen((char*)(ishtar_services[id].value)); + ishtar_SendData((unsigned char*)(&length), sizeof(ishtar_ValueVectorSize)); + + for (j = 0; j < length; ++j) + { + ishtar_SendValue((unsigned char*)ishtar_services[id].value, ishtar_services[id].type, j); + } + + } + else + { + // read the indices + if (numberOfIndices > 0) + { + for (j = 0; j < numberOfIndices; ++j) + { + ishtar_AtInc(&ids,(unsigned char*)&indice, sizeof(ishtar_ValueVectorSize)); + ishtar_SendValue((unsigned char*)ishtar_services[id].value, ishtar_services[id].type, indice); + + } + } + else + { + for (j = 0; j < ishtar_services[id].length; ++j) + { + + ishtar_SendValue((unsigned char*)ishtar_services[id].value, ishtar_services[id].type, j); + } + } + } + } + + ishtar_SendCk(); + ishtar_externalFlushFunc(); + } +} + +/*! +* This function decodes the Set calls and updates local variables +*/ +void ishtar_HandleSetCall(unsigned char * addr, unsigned long len) +{ + ishtar_RequestId requestID; + unsigned char feedback; + ishtar_ServiceId numberOfIds; + ishtar_ValueVectorSize numberOfIndices; + ishtar_ServiceId i; + ishtar_ValueVectorSize j; + ishtar_ServiceId id; + ishtar_ValueVectorSize indice; + unsigned char * indicesAddr; + + unsigned long answerSize; + unsigned short sizeChecksum; + ishtar_MessageId setAck; + + + // READ + // request id + ishtar_AtInc(&addr, (unsigned char*)&requestID, sizeof(ishtar_RequestId)); + // feedback + ishtar_AtInc(&addr, (unsigned char*)&feedback, 1); + //numberOfIds + ishtar_AtInc(&addr, (unsigned char*)&numberOfIds, sizeof(ishtar_ServiceId)); + + for (i = 0; i < numberOfIds; ++i) + { + //id = ishtar_ulongAtInc(&addr); + ishtar_AtInc(&addr, (unsigned char*)&id, sizeof(ishtar_ServiceId)); + + // Problem, a corrupted message has been validated + if (id > ishtar_numberOfVariables) + { + ++ishtar_corruptedValidated; + return; + } + + // number of indices + ishtar_AtInc(&addr, (unsigned char*)&numberOfIndices, sizeof(ishtar_ValueVectorSize)); + indicesAddr = addr; + + // readonly, so skip + if (ishtar_services[id].flags & READ_ONLY) + { + if (numberOfIndices == 0) + { + // skip + ishtar_IncAddr(&addr, ishtar_TypeSize(ishtar_services[id].type) * ((unsigned long)(ishtar_services[id].length)));// values + } + else + { + // skip + ishtar_IncAddr(&addr, numberOfIndices * sizeof(ishtar_ValueVectorSize));// indices + ishtar_IncAddr(&addr, ishtar_TypeSize(ishtar_services[id].type) * numberOfIndices);// values + } + } + else + { + if (numberOfIndices == 0) + { + for (j = 0; j < ishtar_services[id].length; ++j) + ishtar_SetValueInc((unsigned char*)ishtar_services[id].value,ishtar_services[id].type, j, &addr); + } + else + { + ishtar_IncAddr(&addr, numberOfIndices * sizeof(ishtar_ValueVectorSize)); + + // now addr points to the first value, indicesAddr to the first index + + for (j = 0; j < numberOfIndices; ++j) + { + ishtar_AtInc(&indicesAddr, (unsigned char*)&indice, sizeof(ishtar_ValueVectorSize)); + // Problem, a corrupted message has been validated + if (indice > ishtar_services[id].length) + { + ++ishtar_corruptedValidated; + return; + } + + ishtar_SetValueInc((unsigned char*)ishtar_services[id].value, ishtar_services[id].type, (unsigned long)indice, &addr); + } + } + + // call feedback function if existing + if (ishtar_services[id].feedbackFunc) + ishtar_services[id].feedbackFunc(&ishtar_services[id]); + } + } + // SEND - the ack if feedback enabled + if (feedback) + { + setAck = SET_ACK; + answerSize = sizeof(ishtar_MessageId) + sizeof(ishtar_RequestId); + sizeChecksum = ishtar_CalculateSizeChecksum(answerSize); + + ishtar_SendHeader(); + // send size and size checksum + ishtar_SendData((unsigned char*)(&answerSize), 4); + ishtar_SendData((unsigned char*)(&sizeChecksum), 2); + + // send content + ishtar_InitCk(); + ishtar_SendData((unsigned char*)(&setAck), sizeof(ishtar_MessageId)); + ishtar_SendData((unsigned char*)(&requestID), sizeof(ishtar_RequestId)); + ishtar_SendCk(); + + ishtar_externalFlushFunc(); + } +} + +/*! +* This function decodes the content of a disconnection packet and stops the snapshot. +*/ +void ishtar_HandleByeByeCall(unsigned char * addr, unsigned long len) +{ + ishtar_snapshotActive = 0; + ishtar_connected = 0; +} + +/*! +* This function first checks if there is an active snapshot. +* If yes, it sends the data for this snapshot. +*/ +void ishtar_Snapshot() +{ + if (ishtar_snapshotActive && ishtar_connected) + { + ishtar_RequestId requestID; + + unsigned long answerSize;// VALUES(4) + requestID(4) + size(4) + unsigned short sizeChecksum; + ishtar_ServiceId i; + ishtar_ValueVectorSize j; + ishtar_ValueVectorSize length; + + ishtar_MessageId values; + + answerSize = sizeof(ishtar_MessageId) + sizeof(ishtar_RequestId); + + values = VALUES; + requestID = ishtar_snapshotId; + + // CALCULATE SIZE + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + // if the variable is in the snapshot + if (ishtar_services[i].inSnapshot == 1) + { + // if the size is 0, it mean variable, so we must specify it. + if (ishtar_services[i].length == 0) + { + answerSize += sizeof(ishtar_ValueVectorSize); + answerSize += ishtar_Strlen((char*)(ishtar_services[i].value)); + } + else + { + // in snapshots, the full variable is sent, cannot save indices in embedded version + answerSize += ((unsigned long)(ishtar_services[i].length)) * ishtar_TypeSize(ishtar_services[i].type); + } + } + } + + ishtar_snapshotSize = answerSize; + sizeChecksum = ishtar_CalculateSizeChecksum(answerSize); + + // SEND + ishtar_SendHeader(); + // send size and size checksum + ishtar_SendData((unsigned char*)(&answerSize), 4); + ishtar_SendData((unsigned char*)(&sizeChecksum), 2); + + // send content + ishtar_InitCk(); + ishtar_SendData((unsigned char*)(&values), sizeof(ishtar_MessageId)); + ishtar_SendData((unsigned char*)(&requestID), sizeof(ishtar_RequestId)); + + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + if (ishtar_services[i].inSnapshot == 1) + { + // service id + // length == 0 mean variable size, ONLY for char or UCHAR, with ended caracter equal to '\0' + if (ishtar_services[i].length == 0 && ishtar_services[i].type == UCHAR) + { + length = ishtar_Strlen((char*)(ishtar_services[i].value)); + ishtar_SendData((unsigned char*)(&length), sizeof(ishtar_ValueVectorSize)); + + for (j = 0; j < length; ++j) + { + ishtar_SendValue((unsigned char*)ishtar_services[i].value, ishtar_services[i].type, j); + } + + } + else + { + length = ishtar_services[i].length; + for (j=0; j < length; ++j) + { + ishtar_SendValue((unsigned char*)ishtar_services[i].value, ishtar_services[i].type, j); + } + } + } + } + + ishtar_SendCk(); + + ishtar_externalFlushFunc(); + } +} + + +/*! +* This function reads the values from the memory and assign them to the Ishtar variables. +* +* It first read the checksum in the 2 first bytes and checks if it is correct, then it reads and assigns the value. +* The checksum is used to invalidate memory data when the variable list is changed. +*/ +void ishtar_LoadFromMemory() +{ + unsigned short i; + unsigned short j; + unsigned short size; + unsigned short nameSize; + unsigned short addr = ishtar_memoryMinAddress; + unsigned char readChecksumA, readChecksumB; + + if (!ishtar_memoryReadFunc) + { + ishtar_memoryError = READ_FUNC_NULL; + return; + } + + // read checksum first + if (ishtar_memoryReadFunc(addr++, &readChecksumA, 1) != 1) + { + ishtar_memoryError = READ_ERROR; + return; + } + ishtar_numberOfBytesReadFromMemory += 1; + if (ishtar_memoryReadFunc(addr++, &readChecksumB, 1) != 1) + { + ishtar_memoryError = READ_ERROR; + return; + } + ishtar_numberOfBytesReadFromMemory += 1; + + // verify checksums + ishtar_memoryChecksumA = 0; + ishtar_memoryChecksumB = 0; + + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + if (ishtar_services[i].flags & PERSISTENT) + { + // the id, type, length and name are used in the checksum + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].type; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].length; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + ishtar_memoryChecksumA += (unsigned char)i; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + + nameSize = ishtar_Strlen(ishtar_services[i].name); + for (j = 0; j < nameSize; ++j) + { + // checksum the name + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].name[j]; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + } + } + } + + // checksum is wrong + if (!(readChecksumA == ishtar_memoryChecksumA && readChecksumB == ishtar_memoryChecksumB)) + { + ishtar_memoryError = CHECKSUM_WRONG; + return; + } + + // assign the values + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + if (ishtar_services[i].flags & PERSISTENT) + { + // size of this variable in the memory + size = (unsigned short)(ishtar_TypeSize(ishtar_services[i].type) * ishtar_services[i].length); + // write value to memory + if (size != ishtar_memoryReadFunc(addr, ishtar_services[i].value, size)) + { + ishtar_memoryError = READ_ERROR; + return; + } + addr += size; + ishtar_numberOfBytesReadFromMemory += size; + + // call feedback function if existing + if (ishtar_services[i].feedbackFunc) + ishtar_services[i].feedbackFunc(&ishtar_services[i]); + } + } + + ishtar_memoryError = 0; +} + +/*! +* This function writes the values of the Ishtar variables to the memory. +* +* It first checks that the is enough space in the memory, then it writes the checksum in the first 2 bytes, and then the values. +*/ +void ishtar_SaveToMemory() +{ + unsigned short i; + unsigned short j; + unsigned short size = 2; + unsigned short nameSize; + unsigned short addr = ishtar_memoryMinAddress + 2; + + if (!ishtar_memoryWriteFunc) + { + ishtar_memoryError = WRITE_FUNC_NULL; + return; + } + + // check size + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + if (ishtar_services[i].flags & PERSISTENT) + { + size += ishtar_TypeSize(ishtar_services[i].type) * ishtar_services[i].length; + } + } + + // checks if there is enough memory available + if (ishtar_memoryMaxAddress - ishtar_memoryMinAddress < size) + { + ishtar_memoryError = NOT_ENOUGH_SPACE; + return; + } + + + // write and calculate checksum + ishtar_memoryChecksumA = 0; + ishtar_memoryChecksumB = 0; + + for (i = 0; i < ishtar_numberOfVariables; ++i) + { + if (ishtar_services[i].flags & PERSISTENT) + { + // the id, type, length and name are used in the checksum + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].type; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].length; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + ishtar_memoryChecksumA += (unsigned char)i; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + + nameSize = ishtar_Strlen(ishtar_services[i].name); + for (j = 0; j < nameSize; ++j) + { + // checksum the name + ishtar_memoryChecksumA += (unsigned char)ishtar_services[i].name[j]; + ishtar_memoryChecksumB += ishtar_memoryChecksumA; + } + + // size of this variable in the memory + size = (unsigned short)(ishtar_TypeSize(ishtar_services[i].type) * ishtar_services[i].length); + // write value to memory + if (size != ishtar_memoryWriteFunc(addr, ishtar_services[i].value, size)) + { + ishtar_memoryError = WRITE_ERROR; + return; + } + addr += size; + ishtar_numberOfBytesWrittenToMemory += size; + } + } + + // end writing checksum + if (ishtar_memoryWriteFunc(ishtar_memoryMinAddress, &ishtar_memoryChecksumA, 1) != 1) + { + ishtar_memoryError = WRITE_ERROR; + return; + } + ishtar_numberOfBytesWrittenToMemory += 1; + if (ishtar_memoryWriteFunc(ishtar_memoryMinAddress + 1, &ishtar_memoryChecksumB, 1) != 1) + { + ishtar_memoryError = WRITE_ERROR; + return; + } + ishtar_numberOfBytesWrittenToMemory += 1; + + ishtar_memoryError = NO_ERROR; +} + +// init + + +/*! +* This function inits Ishtar Embedded server +* +* @param externalSendFunc The external function to send data +* @param externalFlushFunc The external function to flush data output buffer +* +**/ +void ishtar_Init(ishtar_ExternalSendFunc externalSendFunc, ishtar_ExternalFlushFunc externalFlushFunc) +{ + ishtar_externalSendFunc = externalSendFunc; + ishtar_externalSendBlockingFunc = externalSendFunc; + ishtar_currentSendFunc = externalSendFunc; + + if (externalFlushFunc) + { + ishtar_externalFlushFunc = externalFlushFunc; + } + else + { + ishtar_externalFlushFunc = &ishtar_DoNothing; + } + + ishtar_InitBuffer(); + + // DEBUG +#if ISHTAR_DEBUG + ishtar_RegisterDebugVars(); +#endif + +} + +/*! +* This function inits Ishtar Embedded server with the use of +* a different sending function for big messages. +* The HELLO and SERVICE_LIST packets use the blocking function, other packets the non-blocking +* +* WARNING: Using this function may cause the host to stuck for a while when the client asks for +* the list of all services, as the blocking function could take *several seconds* to send the data +* +* @param externalSendFunc The external function to send data +* @param externalSendBlockFunc The external blocking function to send data (big packets) +* @param externalFlushFunc The external function to flush data output buffer +* +**/ +void ishtar_InitWithBlock(ishtar_ExternalSendFunc externalSendFunc, ishtar_ExternalSendFunc externalSendBlockFunc, ishtar_ExternalFlushFunc externalFlushFunc) +{ + ishtar_externalSendFunc = externalSendFunc; + ishtar_externalSendBlockingFunc = externalSendBlockFunc; + ishtar_currentSendFunc = externalSendFunc; + + if (externalFlushFunc) + { + ishtar_externalFlushFunc = externalFlushFunc; + } + else + { + ishtar_externalFlushFunc = &ishtar_DoNothing; + } + + ishtar_InitBuffer(); + + // DEBUG +#if ISHTAR_DEBUG + ishtar_RegisterDebugVars(); +#endif +} + +/*! +* This function inits the receive buffers and pointers. +*/ +void ishtar_InitBuffer() +{ + ishtar_bufBegin = ishtar_buffer; + ishtar_bufEnd = ishtar_buffer + ISHTAR_BUFFER_SIZE; + ishtar_bufPos = ishtar_buffer; + + ishtar_consumePos = ishtar_buffer; + + ishtar_packetBegin = ishtar_buffer; +} + +/*! +* This function directly registers several variables to monitor Ishtar itself +*/ +void ishtar_RegisterDebugVars() +{ + ishtar_Variable("ishtar.overflows", (unsigned char*)(&ishtar_numberOfOverflows), UINT, 1, 0); + ishtar_Variable("ishtar.variables", (unsigned char*)(&ishtar_numberOfVariables), USHORT, 1, 0); + ishtar_Variable("ishtar.dropHeader1", (unsigned char*)(&ishtar_numberOfDropHeader1), UINT, 1, 0); + ishtar_Variable("ishtar.dropHeader2", (unsigned char*)(&ishtar_numberOfDropHeader2), UINT, 1, 0); + ishtar_Variable("ishtar.dropHeader3", (unsigned char*)(&ishtar_numberOfDropHeader3), UINT, 1, 0); + ishtar_Variable("ishtar.dropHeader4", (unsigned char*)(&ishtar_numberOfDropHeader4), UINT, 1, 0); + ishtar_Variable("ishtar.dropSize", (unsigned char*)(&ishtar_numberOfDropSize), UINT, 1, 0); + ishtar_Variable("ishtar.dropContent", (unsigned char*)(&ishtar_numberOfDropContent), UINT, 1, 0); + ishtar_Variable("ishtar.bytesSent", (unsigned char*)(&ishtar_numberOfBytesSent), UINT, 1, 0); + ishtar_Variable("ishtar.bytesReceived", (unsigned char*)(&ishtar_numberOfBytesReceived), UINT, 1, 0); + ishtar_Variable("ishtar.validMessages", (unsigned char*)(&ishtar_numberOfValidMessages), UINT, 1, 0); + ishtar_Variable("ishtar.memoryBytesRead", (unsigned char*)(&ishtar_numberOfBytesReadFromMemory), UINT, 1, 0); + ishtar_Variable("ishtar.memoryBytesWritten", (unsigned char*)(&ishtar_numberOfBytesWrittenToMemory), UINT, 1, 0); + ishtar_Variable("ishtar.memoryError", (unsigned char*)(&ishtar_memoryError), UCHAR, 1, 0); + ishtar_Variable("ishtar.snapshotSize", (unsigned char*)(&ishtar_snapshotSize), UINT, 1, 0); +} + +/*! +* This function inits the non-volatile memory access functions +* +* @param memoryReadFunc A pointer to the external function that reads the non-volatile memory +* @param memoryWriteFunc A pointer to the external function that writes the non-volatile memory +* @param minAddress The lowest memory address that Ishtar is allowed to write +* @param maxAddress The highest memory address that Ishtar is allowed to write +*/ +void ishtar_InitMemoryAccess(ishtar_MemoryReadFunc memoryReadFunc, ishtar_MemoryWriteFunc memoryWriteFunc, unsigned short minAddress, unsigned short maxAddress) +{ + ishtar_memoryReadFunc = memoryReadFunc; + ishtar_memoryWriteFunc = memoryWriteFunc; + + ishtar_memoryMinAddress = minAddress; + ishtar_memoryMaxAddress = maxAddress; +} + +/*! +* This function registers a variable into Ishtar in order to make it accessible to external clients +* +* @param name The textual name of the variable. Use '.' character to create sub-groups, e.g. "gps.position.longitude" +* @param var A pointer to the real variable or to the root of the array of variables +* @param type The type of the variable : BOOL, CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE +* @param length The number of elements in the array, or 1 for a normal variable +* @param flags The flags for this variable : 0 or READ_ONLY +*/ +ishtar_ServiceId ishtar_Variable(const char* name, void* var, ishtar_ValueVectorType type, ishtar_ValueVectorSize length, ishtar_ServiceFlags flags) +{ + return ishtar_VariableFeedback(name, var, type, length, flags, 0); +} + +/*! +* This function registers a variable into Ishtar in order to make it accessible to external clients +* +* @param name The textual name of the variable. Use '.' character to create sub-groups, e.g. "gps.position.longitude" +* @param var A pointer to the real variable or to the root of the array of variables +* @param type The type of the variable : BOOL, CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE +* @param length The number of elements in the array, or 1 for a normal variable +* @param flags The flags for this variable : 0 or READ_ONLY +* @param feedbackFunc Pointer to a function called whenever the corresponding variable is modified. +*/ +ishtar_ServiceId ishtar_VariableFeedback(const char* name, void* var, ishtar_ValueVectorType type, ishtar_ValueVectorSize length, ishtar_ServiceFlags flags, ishtar_VariableModifiedFunc feedbackFunc) +{ + if (ishtar_numberOfVariables < ISHTAR_MAX_NUMBER_OF_SERVICES) + { + // If the length == 0, then the variable must be read-only because there is no dynamic allocation + if (length == 0) + { + flags |= READ_ONLY; + } + ishtar_services[ishtar_numberOfVariables].name = name; + ishtar_services[ishtar_numberOfVariables].type = type; + ishtar_services[ishtar_numberOfVariables].length = length; + ishtar_services[ishtar_numberOfVariables].flags = flags; + ishtar_services[ishtar_numberOfVariables].value = var; + ishtar_services[ishtar_numberOfVariables].inSnapshot = 0; + ishtar_services[ishtar_numberOfVariables].feedbackFunc = feedbackFunc; + + + return ishtar_numberOfVariables++; + } + return 0; +} + + +/*! +* This function calculates the length of a zero-terminated string +* +* @param The zero-terminated string for which the length will be calculated +* @return The length of the string or ISHTAR_STRING_MAX_SIZE if the string is too long (to prevent from getting stuck) +*/ +unsigned long ishtar_Strlen(const char * addr) +{ + unsigned long l = 0; + while (*addr != '\0' && l < ISHTAR_STRING_MAX_SIZE) + { + ++l; + ++addr; + } + return l; +} + +/*! +* This function returns the number of bytes taken by a variable of a certain type +* +* @param type The IShtar-defined type of the variable : BOOL, CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE +*/ +unsigned long ishtar_TypeSize(ishtar_ValueVectorType type) +{ + unsigned long size = 0; + if (type == CHAR || type == UCHAR || type == BOOL) + { + size = sizeof(char); + } + else if (type == SHORT || type == USHORT) + { + size = sizeof(short); + } + else if (type == FLOAT || type == INT || type == UINT) + { + size = sizeof(long); + } + else if (type == DOUBLE) + { + size = sizeof(double); + } + return size; +} + +/*! +* This function returns true if the server already received a HELLO message since it started, false otherwise +*/ +unsigned char ishtar_IsConnected() +{ + return ishtar_connected; +} + +unsigned short ishtar_ServiceCount() +{ + return ishtar_numberOfVariables; +} + + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 086ea145b6d7 ishtar.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ishtar.h Thu May 12 08:30:17 2011 +0000 @@ -0,0 +1,178 @@ +/* + Ishtar Embedded + Copyright (C) 2008-2010: + + Alexandre Habersaat <alexandre dot habersaat at gmail dot com> + Antoine Beyeler <abeyeler at ab-ware dot com> + (http://www.ab-ware.com) + Stephane Magnenat <stephane at magnenat dot net> + (http://stephane.magnenat.net) + + All rights reserved. + + Ishtar Embedded is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Ishtar Embedded is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Ishtar Embedded. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*! +* \file ishtar.h +* \brief Header file of the Ishtar Embedded server +* +* \author Alexandre Habersaat, Antoine Beyeler +* +* This file contains the public interface of the Ishtar Embedded server +*/ + +#ifndef __ISHTAR_H__ +#define __ISHTAR_H__ + +#ifdef ISHTAR_PREFIX + #include ISHTAR_PREFIX +#endif + +// #include <stdio.h> + +#include "ishtar_def.h" + +//----------------------------- +// Module's options +//----------------------------- + +#ifndef ISHTAR_DEBUG + //! Ishtar debug mode + #define ISHTAR_DEBUG 1 +#endif + +#ifndef ISHTAR_MAX_NUMBER_OF_SERVICES + //! The maximum number of services / variables that can be registered in Ishtar + #define ISHTAR_MAX_NUMBER_OF_SERVICES 250 +#endif + +#ifndef ISHTAR_BUFFER_SIZE + //! The size of the reception buffer + #define ISHTAR_BUFFER_SIZE 800 +#endif + +#ifndef ISHTAR_STRING_MAX_SIZE + //! The maximum size of a string in Ishtar Embedded + #define ISHTAR_STRING_MAX_SIZE 100 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ISHTAR_MAX_VEC_SIZE +//! Maximum size for vectors +#define ISHTAR_MAX_VEC_SIZE 65535 +#endif + +#ifndef ISHTAR_MAX_SERVICES_COUNT +// Maximum number of services +#define ISHTAR_MAX_SERVICES_COUNT 65535 +#endif + +#if ISHTAR_MAX_VEC_SIZE > 65535 + typedef unsigned long ishtar_ValueVectorSize; +#elif ISHTAR_MAX_VEC_SIZE > 255 + typedef unsigned short ishtar_ValueVectorSize; +#else + typedef unsigned char ishtar_ValueVectorSize; +#endif + +typedef unsigned char ishtar_ValueVectorType; + +#if ISHTAR_MAX_SERVICES_COUNT > 65535 + typedef unsigned long ishtar_ServiceId; +#else + typedef unsigned short ishtar_ServiceId; +#endif + +typedef unsigned char ishtar_ServiceFlags; +typedef unsigned short ishtar_MessageId; +typedef unsigned short ishtar_RequestId; + +typedef unsigned long ishtar_ProtocolType; +typedef unsigned long ishtar_NodeType; +typedef unsigned long ishtar_VersionType; + +// forward declaration +//typedef struct ishtar_ServiceDescription ishtar_ServiceDescriptionPtr; +typedef struct ishtar_ServiceDescriptionTag* ishtar_ServiceDescriptionPtr; + +//! Type definition for the external function used to send data through communication +typedef void (*ishtar_ExternalSendFunc)(unsigned char *, unsigned long); +//! Type definition for the external function used to flush the data output buffer at the end of each message that is sent +typedef void (*ishtar_ExternalFlushFunc)(); +//! Type definition for the external function used to write data in non-volatile memory +typedef unsigned short (*ishtar_MemoryWriteFunc)(unsigned short address, void* data, unsigned short length); +//! Type definition for the external function used to read data from non-volatile memory +typedef unsigned short (*ishtar_MemoryReadFunc)(unsigned short address, void* data, unsigned short length); +//! Type definition for the variable modified callback. +typedef void (*ishtar_VariableModifiedFunc)(ishtar_ServiceDescriptionPtr variable); + +//! The structure for the description of services / variables +typedef struct ishtar_ServiceDescriptionTag +{ + const char* name; //!< The name of the variable + ishtar_ValueVectorType type; //!< The type of the variable + ishtar_ValueVectorSize length; //!< The length of the array + ishtar_ServiceFlags flags; //!< The flags for the variable (READ_ONLY) + void* value; //!< The pointer to the local real variable + unsigned char inSnapshot; //!< If this variable is part of the snapshot + ishtar_VariableModifiedFunc feedbackFunc; //!< Function called when the variable is remotely modified +} ishtar_ServiceDescription; + + +//----------------------------- +// Public functions +//----------------------------- + +//! This function inits the Ishtar Embedded server +void ishtar_Init(ishtar_ExternalSendFunc externalSendFunc, ishtar_ExternalFlushFunc externalFlushFunc); +//! This function inits the Ishtar Embedded server, and configures it to work with two different send functions, a non-blocking one and a blocking one +void ishtar_InitWithBlock(ishtar_ExternalSendFunc externalSendFunc, ishtar_ExternalSendFunc externalSendBlockFunc, ishtar_ExternalFlushFunc externalFlushFunc); +//! This function inits the non-volatile memory access functions +void ishtar_InitMemoryAccess(ishtar_MemoryReadFunc memoryReadFunc, ishtar_MemoryWriteFunc memoryWriteFunc, unsigned short minAddress, unsigned short maxAddress); + +//! This function registers a local variable in the Ishtar library to make it accessible to external clients connected to the server +ishtar_ServiceId ishtar_Variable(const char* name, void* var, ishtar_ValueVectorType type, ishtar_ValueVectorSize length, ishtar_ServiceFlags flags); +//! This function registers a local variable in the Ishtar library to make it accessible to external clients connected to the server +ishtar_ServiceId ishtar_VariableFeedback(const char* name, void* var, ishtar_ValueVectorType type, ishtar_ValueVectorSize length, ishtar_ServiceFlags flags, ishtar_VariableModifiedFunc feedbackFunc); +//! This function checks treats every packet that arrived since the last call +void ishtar_Step(); + +//! This function should be called each time data bytes are received through communication +void ishtar_ReceiveData(unsigned char * data, unsigned long len); +//! This function should be called each time a data byte is received through communication +void ishtar_ReceiveDataByte(unsigned char c); +//! This function sends the active snapshot if any, otherwise it does nothing +void ishtar_Snapshot(); + +//! This function reads the values from the memory and assign them to the Ishtar variables +void ishtar_LoadFromMemory(); +//! This function writes the values of the Ishtar variables to the memory +void ishtar_SaveToMemory(); + +//! This function returns true if the server already received a Hello message from a client +unsigned char ishtar_IsConnected(); + +//! This funtion returns the number of currently registered variable. +unsigned short ishtar_ServiceCount(); + +#ifdef __cplusplus +} +#endif + +#endif
diff -r 000000000000 -r 086ea145b6d7 ishtar_def.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ishtar_def.h Thu May 12 08:30:17 2011 +0000 @@ -0,0 +1,187 @@ +/* + Ishtar Embedded + Copyright (C) 2008-2009: + + Alexandre Habersaat <alexandre dot habersaat at gmail dot com> + Antoine Beyeler <abeyeler at ab-ware dot com> + (http://www.ab-ware.com) + Stephane Magnenat <stephane at magnenat dot net> + (http://stephane.magnenat.net) + + All rights reserved. + + Ishtar Embedded is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Ishtar Embedded is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Ishtar Embedded. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*! +* \file ishtar_def.h +* \brief Definition file of the Ishtar Embedded server +* +* \author Alexandre Habersaat, Antoine Beyeler +* \date 2008-06-12 +* +* This file contains the defintions and enumerations used by the Ishtar protocol +* +*/ + +#ifndef __ISHTAR_DEF_H__ +#define __ISHTAR_DEF_H__ + +#ifdef ISHTAR_PREFIX + #include ISHTAR_PREFIX +#endif + +#define ISHTAR_PROTOCOL_VERSION 7 + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISHTAR_HEADER1 (0x66) +#define ISHTAR_HEADER2 (0x57) +#define ISHTAR_HEADER3 (0xD9) +#define ISHTAR_HEADER4 (0xF4) + +#define ISHTAR_NUMBER_OF_SIZE_BYTES 4 +#define ISHTAR_NUMBER_OF_CHECKSUM_BYTES 2 + +//! Size definition for strings that have a variable size depending of their content +#define ISHTAR_STRING_SIZE 0 + +//! Enumeration for Answer messages (server to client) +enum IshtarAnswerType +{ + //! Hello answer + HELLO=0, + //! OK message + OK, + //! Error + ERROR, + //! List of services + SERVICE_LIST, + //! Values of a given service + VALUES, + //! Confirmation of a set + SET_ACK + +}; + +//! Enumeration for Call messages (client to server) +enum IshtarCallType +{ + //! Hello call for connection + //HELLO=0, + //! Service list request + GET_SERVICE_LIST=1, + //! Values read request + GET_VALUES, + //! Values write request + SET_VALUES, + //! Disconnection notification + BYE_BYE +}; + +//! Enumeration for node type +enum IshtarNodeType +{ + //! Ishtar server node + SERVER=0, + //! Ishtar client node + CLIENT +}; + +//! Enumeration for message type +enum IshtarMessageType +{ + //! Connection was successful + CONNECTION_SUCCESSFUL = 0 +}; + +//! Enumeration for error types +enum IshtarErrorTypes +{ + //! A request service does not exists any more + SERVICE_DOES_NOT_EXISTS = 0, + //! The server and the client are running incompatible protocol version + INCOMPATIBLE_PROTOCOL_VERSION +}; + +//! Enumeration for protocol type +enum IshtarProtocolType +{ + REGULAR = 0, //!< regular protocol should be used + EMBEDDED, //!< embedded version of the protocol should be used + INCOMPATIBLE //!< this server is not compatible with the request protocol version +}; + +//! Enumeration for variable types +enum IshtarType +{ + LONG = 0, //!< 32 bits signed integer, corresponds to signed long + ULONG, //!< 32 bits unsigned integer, corresponds to unsigned long + SHORT, //!< 16 bits signed integer, corresponds to signed short + USHORT, //!< 16 bits unsigned integer, corresponds to unsigned short + CHAR, //!< 8 bits signed integer, corresponds to signed char + UCHAR, //!< 8 bits unsigned integer, corresponds to unsigned char + FLOAT, //!< 32 bits floating point value, corresponds to float + DOUBLE, //!< 64 bits double precision floating point value, corresponds to double + BOOL, //!< true/false value, serialized on a UCHAR + + //TODO: depracated, remove + INT=0, //!< 32 bits signed integer, corresponds to signed long, deprecated alias for LONG + UINT, //!< 32 bits unsigned integer, corresponds to unsigned long, deprecated alias for ULONG + +}; + +//! Enumeration for service options (flags) +enum IshtarFlags +{ + //! No flags + NO_FLAGS=0, + //! Service can only be read + READ_ONLY=0x1, + //! Each value has a name + NAMED_VALUES=0x2, + //! Each value is bounded + CONSTRAINT_VALUES=0x4, + //! Service can be saved/loaded from memory + PERSISTENT=0x80 +}; + +//! Enumeration for the memery errors +enum IshtarMemoryErrors +{ + //! No error occured + NO_ERROR=0, + //! The write function is not defined + WRITE_FUNC_NULL, + //! The read function is not defined + READ_FUNC_NULL, + //! The memory space is too small + NOT_ENOUGH_SPACE, + //! The variable list has been modified since last save + CHECKSUM_WRONG, + //! The external function could not write + WRITE_ERROR, + //! The internal function could not read + READ_ERROR + +}; + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file
diff -r 000000000000 -r 086ea145b6d7 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu May 12 08:30:17 2011 +0000 @@ -0,0 +1,12 @@ +#include "mbed.h" + +DigitalOut myled(LED1); + +int main() { + while(1) { + myled = 1; + wait(0.2); + myled = 0; + wait(0.2); + } +}
diff -r 000000000000 -r 086ea145b6d7 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Thu May 12 08:30:17 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912