📄 protocol.c
字号:
// ----------------------------------------------------------------------------// Copyright 2006-2007, Martin D. Flynn// All rights reserved// ----------------------------------------------------------------------------//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// // http://www.apache.org/licenses/LICENSE-2.0// // Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// ----------------------------------------------------------------------------// Description:// DMTP communication protocol manager// Manages the dialog between the client and server during connections.// Notes:// - Thread support would be a useful addition to this module. This would allow// an immediate return to the main GPS checking loop without blocking. This// reference implementation will block until data communication has been made// and data has been transferred.// ---// Change History:// 2006/01/04 Martin D. Flynn// -Initial release// 2006/02/09 Martin D. Flynn// -Send ERROR_GPS_EXPIRED/ERROR_GPS_FAILURE is GPS fix has expired// 2006/04/02 Martin D. Flynn// -Clear 'sendIdentification' after sending UniqueID// 2006/05/07 Martin D. Flynn// -Add support for uploading GeoZones// 2006/05/26 Martin D. Flynn// -Allow UniqueID to be >= 4// 2007/01/28 Martin D. Flynn// -WindowsCE port// -Fix 'tight loop' issue when 'serial/bluetooth' transport goes down// (propagate error up from 'protocolReadServerPacket').// -Return ERROR_COMMAND_ERROR for PROP_ERROR_COMMAND_ERROR on 'set' property.// -Switched to generic thread access methods in 'tools/threads.h'// -Flush server input buffers on received EOB-done (serial transport only)// -Separated all protocol variables into a separate structure to allow// multiple simultaneous connecting protocols.// -Changed PKT_SERVER_GET_PROPERTY to retrieve a single property value.// The remaining bytes behind the property key can now be used as arguments// on the property 'get' (via 'PROP_REFRESH_GET').// -Made some significant changes to this module to allow multiple virtual// protocol "instances". (While this would have been easier in 'C++', this// has been implemented in 'C' to allow compiling on any 'C' capable platform.)// 2007/02/05 Martin D. Flynn// -Fixed Fletcher checksum packet generation that inappropriately used// "sizeof(ChecksumFletcher_t)" to determine the length of the checksum value.// This created a compiler dependency that could return a length of 4, instead// of the corrent value '2'. (Thanks to Tomasz Rostanski for catching this!).// 2007/04/28 Martin D. Flynn// -Moved the following functions from 'events.c' to this modules to support // dual transport: evGetEventQueue, evGetHighestPriority,// evEnableOverwrite, evAcknowledgeFirst, evAcknowledgeToSequence// ----------------------------------------------------------------------------#include "stdafx.h" // TARGET_WINCE#include "custom/defaults.h"#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <ctype.h>#include <time.h>#include "custom/log.h"#include "custom/transport.h"#include "custom/gps.h"#include "tools/stdtypes.h"#include "tools/strtools.h"#include "tools/utctools.h"#include "tools/base64.h"#include "tools/checksum.h"#include "base/propman.h"#include "base/events.h"#include "base/cerrors.h"#include "base/serrors.h"#include "base/pqueue.h"#include "base/accting.h"#include "base/packet.h"#include "base/protocol.h"#if defined(ENABLE_UPLOAD)# include "base/upload.h"#endif#include "modules/motion.h"// ----------------------------------------------------------------------------// thread control#ifdef PROTOCOL_THREAD//#warning Protocol thread support enabled#define PROTOCOL_LOCK(PV) MUTEX_LOCK(&((PV)->protocolMutex));#define PROTOCOL_UNLOCK(PV) MUTEX_UNLOCK(&((PV)->protocolMutex));#define PROTOCOL_WAIT(PV) CONDITION_WAIT(&((PV)->protocolCond), &((PV)->protocolMutex));#define PROTOCOL_NOTIFY(PV) CONDITION_NOTIFY(&((PV)->protocolCond));#else//#warning Protocol thread support disabled#define PROTOCOL_LOCK(PV)#define PROTOCOL_UNLOCK(PV)#define PROTOCOL_WAIT(PV)#define PROTOCOL_NOTIFY(PV)#endif// ----------------------------------------------------------------------------/* severe error counts */#define MAX_SEVERE_ERRORS 10#define EXCESSIVE_SEVERE_ERRORS 15// ----------------------------------------------------------------------------// ----------------------------------------------------------------------------// '_protoGetVars' allows separating the protocol handler into separate virtual// instances. Ideally, this should be a C++ class, but this has been implemented// in 'C' to allow this module to compile on any 'C' compatible platform.static ProtocolVars_t protoVars[MAX_SIMULTANEOUS_PROTOCOLS];static ProtocolVars_t *_protoGetVars(const char *fn, int line, int protoNdx){ if (protoNdx <= 0) { // primary protocol return &protoVars[0]; } else if (protoNdx < MAX_SIMULTANEOUS_PROTOCOLS) { // secondary protocol, etc. //logINFO(LOGSRC,"Secondary protocol #%d [%s:%d] ...", protoNdx, fn, line); return &protoVars[protoNdx]; } else { // invalid index, return last protocol //logWARNING(LOGSRC,"Secondary protocol out-of-bounds #%d [%s:%d] ...", protoNdx, fn, line); return &protoVars[MAX_SIMULTANEOUS_PROTOCOLS - 1]; }}// ----------------------------------------------------------------------------// ----------------------------------------------------------------------------#if defined(SECONDARY_SERIAL_TRANSPORT)PacketQueue_DEFINE(secondaryQueue,SECONDARY_EVENT_QUEUE_SIZE);#endif/* get event queue (evGetEventQueue) */static PacketQueue_t *_protocolGetEventQueue(ProtocolVars_t *pv){#if defined(SECONDARY_SERIAL_TRANSPORT) return pv->isPrimary? evGetEventQueue() : &secondaryQueue;#else return evGetEventQueue();#endif}PacketQueue_t *protocolGetEventQueue(int protoNdx){ ProtocolVars_t *pv = _protoGetVars(LOGSRC,protoNdx); return _protocolGetEventQueue(pv);}/* return the highest priority event in the queue (evGetHighestPriority) */static PacketPriority_t _protocolGetHighestPriority(ProtocolVars_t *pv){ PacketQueue_t *evQue = _protocolGetEventQueue(pv); if (evQue) { return pqueGetHighestPriority(evQue); } else { return PRIORITY_NONE; }}/* enable overwriting of the oldest event if the event queue fills up (evEnableOverwrite) */static void _protocolEnableOverwrite(ProtocolVars_t *pv, utBool overwrite){ PacketQueue_t *evQue = _protocolGetEventQueue(pv); if (evQue) { pqueEnableOverwrite(evQue, overwrite); }}/* acknowledge events up to and including the specified sequence (evAcknowledgeToSequence) */static utBool _protocolAcknowledgeToSequence(ProtocolVars_t *pv, UInt32 sequence){ // 'primary' transport events only utBool didAck = utFalse; utBool ackAll = (sequence == SEQUENCE_ALL)? utTrue : utFalse; PacketQueue_t *eventQueue = _protocolGetEventQueue(pv); if (eventQueue && (ackAll || pqueHasSentPacketWithSequence(eventQueue,sequence))) { PacketQueueIterator_t evi; pqueGetIterator(eventQueue, &evi); for (;;) { // As we iterate through the event packets, we can assume the following: // - If we get to a null packet, we are finished with the list // - If we find a packet that hasn't been sent, then all following packets have // also not been sent. // - Once we find the 'first' matching sequence, we delete it then stop. This is // safer that deleting the last matching sequence. (Note: multiple possible // matching sequence numbers can occur if the byte length of the sequence // number is 1 (ie. 0 to 255), and more than 255 events are currently in the // event packet queue. Granted, an unlikely situation, but it can occur.) // - No packet->sequence will ever match SEQUENCE_ALL (see 'ackAll'). Packet_t *pkt = pqueGetNextPacket((Packet_t*)0, &evi); if (!pkt || !pkt->sent) { //logWARNING(LOGSRC,"Stop at first non-sent packet"); break; // stop at first null or non-sent packet } pqueDeleteFirstEntry(eventQueue); didAck = utTrue; if (ackAll) { // ackowledge all sent packets continue; } else if (pkt->sequence == SEQUENCE_ALL) { // This condition can not (should not) occur. // We don't know what the real sequence of the packet is. // it's safer to stop here. break; } else if (pkt->sequence != (sequence & SEQUENCE_MASK(pkt->seqLen))) { // no match yet continue; } break; // stop when sequence matches } } else { logERROR(LOGSRC,"No packet with sequence: 0x%04lX", (UInt32)sequence); } return didAck;}/* acknowledge first sent event (evAcknowledgeFirst) */static utBool _protocolAcknowledgeFirst(ProtocolVars_t *pv){ PacketQueue_t *evQue = _protocolGetEventQueue(pv); if (evQue) { UInt32 seq = pqueGetFirstSentSequence(evQue); // return 'SEQUENCE_ALL' if no first event if (seq != SEQUENCE_ALL) { return _protocolAcknowledgeToSequence(pv,seq); } else { return utFalse; } } else { return utFalse; }}// ----------------------------------------------------------------------------// ----------------------------------------------------------------------------/* set current session packet encoding */static void _protocolSetSessionEncoding(ProtocolVars_t *pv, TransportType_t xportType, PacketEncoding_t enc){ // Since this reference implementation does not support received CSV packet encoding // from the server, we must make sure that our first packet to the server is NOT // CSV encoded if we are transmitting via TRANSPORT_DUPLEX pv->sessionEncoding = enc; pv->sessionEncodingChanged = utFalse; pv->sessionFirstEncoding = pv->sessionEncoding; if (xportType == TRANSPORT_DUPLEX) { if (ENCODING_VALUE(pv->sessionEncoding) == ENCODING_CSV) { PacketEncoding_t dft = ENCODING_BASE64; pv->sessionFirstEncoding = ENCODING_IS_CHECKSUM(enc)? ENCODING_CHECKSUM(dft) : dft; } }}/* return true if specified encoding is supported */static PacketEncoding_t _protocolGetSupportedEncoding(ProtocolVars_t *pv, PacketEncoding_t dftEncoding){ UInt32 enc = ENCODING_VALUE(dftEncoding); // <-- max 15 if (enc == ENCODING_BINARY) { return (PacketEncoding_t)enc; } else { UInt32 propEncodings = pv->isPrimary? propGetUInt32(PROP_COMM_ENCODINGS, 0L) : 0L; // protocol dependent UInt32 encodingMask = propEncodings | ENCODING_REQUIRED_MASK; // <-- must include binary while ((ENCODING_MASK(enc) & encodingMask) == 0L) { // ENCODING_CSV 3 // ENCODING_HEX 2 // ENCODING_BASE64 1 // ENCODING_BINARY 0 enc--; } //if (enc != ENCODING_VALUE(dftEncoding)) { logDEBUG(LOGSRC,"Encoding down-graded to %ld\n", enc); } return ENCODING_IS_CHECKSUM(dftEncoding)? (PacketEncoding_t)ENCODING_CHECKSUM(enc) : (PacketEncoding_t)enc; }}// ----------------------------------------------------------------------------// The following are wrappers to the 'transport.c' module function calls/* return transport 'open' state */utBool protocolIsSpeakFreely(int protoNdx){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -