#ifndef CHIRP_HPP #define CHIRP_HPP #include #include #include #include "link.h" #define ALIGN(v, n) v = v&((n)-1) ? (v&~((n)-1))+(n) : v #define FOURCC(a, b, c, d) (((uint32_t)a<<0)|((uint32_t)b<<8)|((uint32_t)c<<16)|((uint32_t)d<<24)) #define CRP_RES_OK 0 #define CRP_RES_ERROR -1 #define CRP_RES_ERROR_RECV_TIMEOUT LINK_RESULT_ERROR_RECV_TIMEOUT #define CRP_RES_ERROR_SEND_TIMEOUT LINK_RESULT_ERROR_SEND_TIMEOUT #define CRP_RES_ERROR_CRC -2 #define CRP_RES_ERROR_PARSE -3 #define CRP_RES_ERROR_MAX_NAK -4 #define CRP_RES_ERROR_MEMORY -5 #define CRP_RES_ERROR_NOT_CONNECTED -6 #define CRP_MAX_NAK 3 #define CRP_RETRIES 3 #define CRP_HEADER_TIMEOUT 1000 #define CRP_DATA_TIMEOUT 500 #define CRP_IDLE_TIMEOUT 500 #define CRP_SEND_TIMEOUT 1000 #define CRP_MAX_ARGS 10 #define CRP_BUFSIZE 0x80 #define CRP_BUFPAD 8 #define CRP_PROCTABLE_LEN 0x40 #define CRP_START_CODE 0xaaaa5555 #define CRP_CALL 0x80 #define CRP_RESPONSE 0x40 #define CRP_INTRINSIC 0x20 #define CRP_DATA 0x10 #define CRP_XDATA 0x18 // data not associated with no associated procedure) #define CRP_CALL_ENUMERATE (CRP_CALL | CRP_INTRINSIC | 0x00) #define CRP_CALL_INIT (CRP_CALL | CRP_INTRINSIC | 0x01) #define CRP_CALL_ENUMERATE_INFO (CRP_CALL | CRP_INTRINSIC | 0x02) #define CRP_ACK 0x59 #define CRP_NACK 0x95 #define CRP_MAX_HEADER_LEN 64 #define CRP_ARRAY 0x80 // bit #define CRP_FLT 0x10 // bit #define CRP_NO_COPY (0x10 | 0x20) #define CRP_HINT 0x40 // bit #define CRP_NULLTERM_ARRAY (0x20 | CRP_ARRAY) // bits #define CRP_INT8 0x01 #define CRP_UINT8 0x01 #define CRP_INT16 0x02 #define CRP_UINT16 0x02 #define CRP_INT32 0x04 #define CRP_UINT32 0x04 #define CRP_FLT32 (CRP_FLT | 0x04) #define CRP_FLT64 (CRP_FLT | 0x08) #define CRP_STRING (CRP_NULLTERM_ARRAY | CRP_INT8) #define CRP_TYPE_HINT 0x64 // type hint identifier #define CRP_INTS8 (CRP_INT8 | CRP_ARRAY) #define CRP_INTS16 (CRP_INT16 | CRP_ARRAY) #define CRP_INTS32 (CRP_INT32 | CRP_ARRAY) #define CRP_UINTS8 CRP_INTS8 #define CRP_UINTS8_NO_COPY (CRP_INTS8 | CRP_NO_COPY) #define CRP_UINTS16_NO_COPY (CRP_INTS16 | CRP_NO_COPY) #define CRP_UINTS32_NO_COPY (CRP_INTS32 | CRP_NO_COPY) #define CRP_UINTS16 CRP_INTS16 #define CRP_UINTS32 CRP_INTS32 #define CRP_FLTS32 (CRP_FLT32 | CRP_ARRAY) #define CRP_FLTS64 (CRP_FLT64 | CRP_ARRAY) #define CRP_HINT8 (CRP_INT8 | CRP_HINT) #define CRP_HINT16 (CRP_INT16 | CRP_HINT) #define CRP_HINT32 (CRP_INT32 | CRP_HINT) #define CRP_HINTS8 (CRP_INT8 | CRP_ARRAY | CRP_HINT) #define CRP_HINTS16 (CRP_INT16 | CRP_ARRAY | CRP_HINT) #define CRP_HINTS32 (CRP_INT32 | CRP_ARRAY | CRP_HINT) #define CRP_HFLTS32 (CRP_FLT32 | CRP_ARRAY | CRP_HINT) #define CRP_HFLTS64 (CRP_FLT64 | CRP_ARRAY | CRP_HINT) #define CRP_HSTRING (CRP_STRING | CRP_HINT) // CRP_HTYPE is for arg lists which are uint8_t arrays #define CRP_HTYPE(v) CRP_TYPE_HINT, (uint8_t)(v>>0&0xff), (uint8_t)(v>>8&0xff), (uint8_t)(v>>16&0xff), (uint8_t)(v>>24&0xff) // regular call args #define INT8(v) CRP_INT8, v #define UINT8(v) CRP_INT8, v #define INT16(v) CRP_INT16, v #define UINT16(v) CRP_INT16, v #define INT32(v) CRP_INT32, v #define UINT32(v) CRP_INT32, v #define FLT32(v) CRP_FLT32, v #define FLT64(v) CRP_FLT64, v #define STRING(s) CRP_STRING, s #define INTS8(len, a) CRP_INTS8, len, a #define UINTS8(len, a) CRP_INTS8, len, a #define UINTS8_NO_COPY(len) CRP_UINTS8_NO_COPY, len #define UINTS16_NO_COPY(len) CRP_UINTS16_NO_COPY, len #define UINTS32_NO_COPY(len) CRP_UINTS32_NO_COPY, len #define INTS16(len, a) CRP_INTS16, len, a #define UINTS16(len, a) CRP_INTS16, len, a #define INTS32(len, a) CRP_INTS32, len, a #define UINTS32(len, a) CRP_INTS32, len, a #define FLTS32(len, a) CRP_FLTS32, len, a #define FLTS64(len, a) CRP_FLTS64, len, a // hint call args #define HINT8(v) CRP_HINT8, v #define UHINT8(v) CRP_HINT8, v #define HINT16(v) CRP_HINT16, v #define UHINT16(v) CRP_HINT16, v #define HINT32(v) CRP_HINT32, v #define UHINT32(v) CRP_HINT32, v #define HFLT32(v) CRP_HFLT32, v #define HFLT64(v) CRP_HFLT64, v #define HSTRING(s) CRP_HSTRING, s #define HINTS8(len, a) CRP_HINTS8, len, a #define UHINTS8(len, a) CRP_HINTS8, len, a #define HINTS16(len, a) CRP_HINTS16, len, a #define UHINTS16(len, a) CRP_HINTS16, len, a #define HINTS32(len, a) CRP_HINTS32, len, a #define UHINTS32(len, a) CRP_HINTS32, len, a #define HFLTS32(len, a) CRP_HFLTS32, len, a #define HFLTS64(len, a) CRP_HFLTS64, len, a #define HTYPE(v) CRP_TYPE_HINT, v #define INT8_IN(v) int8_t & v #define UINT8_IN(v) uint8_t & v #define INT16_IN(v) int16_t & v #define UINT16_IN(v) uint16_t & v #define INT32_IN(v) int32_t & v #define UINT32_IN(v) uint32_t & v #define FLT32_IN(v) float & v #define FLT64_IN(v) double & v #define STRING_IN(s) const char * s #define INTS8_IN(len, a) uint32_t & len, int8_t * a #define UINTS8_IN(len, a) uint32_t & len, uint8_t * a #define INTS16_IN(len, a) uint32_t & len, int16_t * a #define UINTS16_IN(len, a) uint32_t & len, uint16_t * a #define INTS32_IN(len, a) uint32_t & len, int32_t * a #define UINTS32_IN(len, a) uint32_t & len, uint32_t * a #define FLTS32_IN(len, a) uint32_t & len, float * a #define FLTS64_IN(len, a) uint32_t & len, double * a #ifndef END #ifdef __x86_64__ #define END (int64_t)0 #else #define END 0 #endif #endif #define END_OUT_ARGS END #define END_IN_ARGS END // service types #define SYNC 0 #define ASYNC 0x01 // bit #define RETURN_ARRAY 0x02 // bit #define SYNC_RETURN_ARRAY (SYNC | RETURN_ARRAY) #define CRP_RETURN(chirp, ...) chirp->assemble(0, __VA_ARGS__, END) #define CRP_SEND_XDATA(chirp, ...) chirp->assemble(CRP_XDATA, __VA_ARGS__, END) #define callSync(...) call(SYNC, __VA_ARGS__, END) #define callAsync(...) call(ASYNC, __VA_ARGS__, END) #define callSyncArray(...) call(SYNC_RETURN_ARRAY, __VA_ARGS__, END) class Chirp; typedef int16_t ChirpProc; // negative values are invalid typedef uint32_t (*ProcPtr)(Chirp *); struct ProcModule { char *procName; ProcPtr procPtr; uint8_t argTypes[CRP_MAX_ARGS]; char *procInfo; }; struct ProcTableExtension { uint8_t argTypes[CRP_MAX_ARGS]; char *procInfo; }; struct ProcInfo { char *procName; uint8_t *argTypes; char *procInfo; }; struct ProcTableEntry { const char *procName; ProcPtr procPtr; ChirpProc chirpProc; const ProcTableExtension *extension; }; class Chirp { public: Chirp(bool hinterested=false, bool client=false, Link *link=NULL); ~Chirp(); virtual int init(bool connect); int setLink(Link *link); ChirpProc getProc(const char *procName, ProcPtr callback=0); int setProc(const char *procName, ProcPtr proc, ProcTableExtension *extension=NULL); int getProcInfo(ChirpProc proc, ProcInfo *info); int registerModule(const ProcModule *module); void setSendTimeout(uint32_t timeout); void setRecvTimeout(uint32_t timeout); int call(uint8_t service, ChirpProc proc, ...); int call(uint8_t service, ChirpProc proc, va_list args); static uint8_t getType(const void *arg); int service(bool all=true); int assemble(uint8_t type, ...); bool connected(); // utility methods static int serialize(Chirp *chirp, uint8_t *buf, uint32_t bufSize, ...); static int deserialize(uint8_t *buf, uint32_t len, ...); static int vserialize(Chirp *chirp, uint8_t *buf, uint32_t bufSize, va_list *args); static int vdeserialize(uint8_t *buf, uint32_t len, va_list *args); static int deserializeParse(uint8_t *buf, uint32_t len, void *args[]); static int loadArgs(va_list *args, void *recvArgs[]); static int getArgList(uint8_t *buf, uint32_t len, uint8_t *argList); int useBuffer(uint8_t *buf, uint32_t len); static uint16_t calcCrc(uint8_t *buf, uint32_t len); protected: int remoteInit(bool connect); int recvChirp(uint8_t *type, ChirpProc *proc, void *args[], bool wait=false); // null pointer terminates virtual int handleChirp(uint8_t type, ChirpProc proc, const void *args[]); // null pointer terminates virtual void handleXdata(const void *data[]) {(void)data;} virtual int sendChirp(uint8_t type, ChirpProc proc); uint8_t *m_buf; uint8_t *m_bufSave; uint32_t m_len; uint32_t m_offset; uint32_t m_bufSize; bool m_errorCorrected; bool m_sharedMem; bool m_hinformer; bool m_hinterested; bool m_client; uint32_t m_headerLen; uint16_t m_headerTimeout; uint16_t m_dataTimeout; uint16_t m_idleTimeout; uint16_t m_sendTimeout; private: int sendHeader(uint8_t type, ChirpProc proc); int sendFull(uint8_t type, ChirpProc proc); int sendData(); int sendAck(bool ack); // false=nack int sendChirpRetry(uint8_t type, ChirpProc proc); int recvHeader(uint8_t *type, ChirpProc *proc, bool wait); int recvFull(uint8_t *type, ChirpProc *proc, bool wait); int recvData(); int recvAck(bool *ack, uint16_t timeout); // false=nack int32_t handleEnumerate(char *procName, ChirpProc *callback); int32_t handleInit(uint16_t *blkSize, uint8_t *hintSource); int32_t handleEnumerateInfo(ChirpProc *proc); int vassemble(va_list *args); void restoreBuffer(); ChirpProc updateTable(const char *procName, ProcPtr procPtr); ChirpProc lookupTable(const char *procName); int realloc(uint32_t min=0); int reallocTable(); Link *m_link; ProcTableEntry *m_procTable; uint16_t m_procTableSize; uint16_t m_blkSize; uint8_t m_maxNak; uint8_t m_retries; bool m_call; bool m_connected; }; #endif // CHIRP_H