├── Makefile ├── Message.cpp ├── Message.h ├── MessageHandler.cpp ├── MessageHandler.h ├── Nonce.cpp ├── Nonce.h ├── PDMBasal.cpp ├── PDMBasal.h ├── PDMBolus.cpp ├── PDMBolus.h ├── PDMCancelTime.cpp ├── PDMCancelTime.h ├── PDMGetState.cpp ├── PDMGetState.h ├── PDMPairing.cpp ├── PDMPairing.h ├── PDMVerifyPairing.cpp ├── PDMVerifyPairing.h ├── PODPairing.cpp ├── PODPairing.h ├── Packet.cpp ├── Packet.h ├── PacketHandler.cpp ├── PacketHandler.h ├── README.md ├── RFModem.cpp ├── RFModem.h ├── SubMessage.cpp ├── SubMessage.h ├── SubMessageSeed.cpp ├── SubMessageSeed.h ├── SubMessageStatus.cpp ├── SubMessageStatus.h ├── records ├── pairing.sh ├── rcv.sh └── tx.sh └── rtlomniv2.cpp /Makefile: -------------------------------------------------------------------------------- 1 | all: rtlomniv2 2 | 3 | CC = g++ 4 | GCCVERSION = $(shell gcc --version | grep ^gcc | sed 's/^.* //g') 5 | #CFLAGS = -std=c++98 6 | CFLAGS += -Wall -g -O0 -Wno-unused-variable -Wno-sign-compare 7 | 8 | LDFLAGS = -lm -lliquid -lpthread 9 | 10 | 11 | rtlomniv2: RFModem.cpp RFModem.h Packet.cpp Packet.h PacketHandler.cpp PacketHandler.h Message.cpp Message.h SubMessage.h SubMessage.cpp SubMessageStatus.h SubMessageStatus.cpp MessageHandler.h MessageHandler.cpp PDMGetState.h Nonce.h Nonce.cpp PDMGetState.cpp rtlomniv2.cpp SubMessageSeed.h SubMessageSeed.cpp PODPairing.h PODPairing.cpp PDMPairing.h PDMPairing.cpp PDMVerifyPairing.h PDMVerifyPairing.cpp PDMCancelTime.h PDMCancelTime.cpp PDMBolus.h PDMBolus.cpp PDMBasal.h PDMBasal.cpp ./librpitx/src/librpitx.a 12 | $(CC) $(CFLAGS) -o rtlomniv2 RFModem.cpp Packet.cpp Message.cpp PacketHandler.cpp MessageHandler.cpp SubMessage.cpp SubMessageStatus.cpp PDMGetState.cpp Nonce.cpp SubMessageSeed.cpp PODPairing.cpp PDMPairing.cpp PDMVerifyPairing.cpp PDMCancelTime.cpp PDMBolus.cpp PDMBasal.cpp rtlomniv2.cpp ./librpitx/src/librpitx.a $(LDFLAGS) 13 | 14 | 15 | -------------------------------------------------------------------------------- /Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.h" 2 | #include 3 | #include 4 | 5 | Message::Message() 6 | { 7 | } 8 | 9 | Message::~Message() 10 | { 11 | } 12 | 13 | 14 | //Packet Layer(1518695192.877):POD ID1:ffffffff Seq:4 PktLen:31 crc8:fd(OK)ff ff ff ff 04 1d 01 1b 13 88 10 08 34 0a 50 02 07 00 02 07 00 02 03 00 00 a5 5f 00 09 ed 72 15 | //Tx ACK 5 16 | //Packet Layer(1518695193.38):ACK ID1:ffffffff Seq:5 PktLen:4 crc8:89(OK)1f108958 17 | //Packet Layer(1518695193.140):CON ID1:ffffffff Seq:6 PktLen:6 crc8:27(OK)1f10895882b0 18 | //Tx ACK 7 19 | //Msg Layer:POD ID2:ffffffff Seq:1 Len:29/29 crc16:82b0/82b0 (OK)011b13881008340a5002070002070002030000a55f0009 1f10895882b0 20 | 21 | 22 | int Message::SetFirst(Packet *packet) 23 | { 24 | Reset(); 25 | Source=packet->Type; 26 | ID2=(packet->Body[0]<<24)|(packet->Body[1]<<16)|(packet->Body[2]<<8)|(packet->Body[3]); 27 | Sequence=(packet->Body[4]&0x3F)>>2; 28 | TargetLen=(packet->Body[5]|((packet->Body[4]&3)<<8)); 29 | memcpy(Body,packet->Body+6,packet->PacketLen-6);//Message Header(6) - CRC16 (2) 30 | MessageLen+=packet->PacketLen-6; 31 | 32 | memcpy(CompleteRawMessage,packet->Body,packet->PacketLen); 33 | RawLen+=packet->PacketLen; 34 | return 0; 35 | } 36 | 37 | int Message::SetCon(Packet *packet) 38 | { 39 | memcpy(Body+MessageLen,packet->Body,packet->PacketLen); 40 | MessageLen+=packet->PacketLen; 41 | 42 | memcpy(CompleteRawMessage+RawLen,packet->Body,packet->PacketLen); 43 | RawLen+=packet->PacketLen; 44 | return 0; 45 | } 46 | 47 | 48 | int Message::SetMessageFromPacket(Packet *packet) 49 | { 50 | switch(packet->Type) 51 | { 52 | case POD:SetFirst(packet);break; 53 | case PDM:SetFirst(packet);break; 54 | case ACK:return -1;break; 55 | case CON:SetCon(packet);break; 56 | default:break; 57 | } 58 | 59 | if((TargetLen+2)==MessageLen) 60 | { 61 | crc16=(CompleteRawMessage[RawLen-2]<<8)|CompleteRawMessage[RawLen-1]; 62 | if(computecrc16(CompleteRawMessage,RawLen-2)==crc16) IsValid=true; 63 | MessageLen=MessageLen-2; //We remove CRC16 64 | 65 | if(IsValid==true) return 0; else fprintf(stderr,"CRC16 ERROR\n"); 66 | } 67 | return -1; 68 | } 69 | 70 | //*************************************DATA DEFINITION AND CRC*********************************************** 71 | unsigned int crc_table16[] = {0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011,0x8033, 72 | 0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022,0x8063,0x0066, 73 | 0x006c,0x8069,0x0078,0x807d,0x8077,0x0072,0x0050,0x8055,0x805f, 74 | 0x005a,0x804b,0x004e,0x0044,0x8041,0x80c3,0x00c6,0x00cc,0x80c9, 75 | 0x00d8,0x80dd,0x80d7,0x00d2,0x00f0,0x80f5,0x80ff,0x00fa,0x80eb, 76 | 0x00ee,0x00e4,0x80e1,0x00a0,0x80a5,0x80af,0x00aa,0x80bb,0x00be, 77 | 0x00b4,0x80b1,0x8093,0x0096,0x009c,0x8099,0x0088,0x808d,0x8087, 78 | 0x0082,0x8183,0x0186,0x018c,0x8189,0x0198,0x819d,0x8197,0x0192, 79 | 0x01b0,0x81b5,0x81bf,0x01ba,0x81ab,0x01ae,0x01a4,0x81a1,0x01e0, 80 | 0x81e5,0x81ef,0x01ea,0x81fb,0x01fe,0x01f4,0x81f1,0x81d3,0x01d6, 81 | 0x01dc,0x81d9,0x01c8,0x81cd,0x81c7,0x01c2,0x0140,0x8145,0x814f, 82 | 0x014a,0x815b,0x015e,0x0154,0x8151,0x8173,0x0176,0x017c,0x8179, 83 | 0x0168,0x816d,0x8167,0x0162,0x8123,0x0126,0x012c,0x8129,0x0138, 84 | 0x813d,0x8137,0x0132,0x0110,0x8115,0x811f,0x011a,0x810b,0x010e, 85 | 0x0104,0x8101,0x8303,0x0306,0x030c,0x8309,0x0318,0x831d,0x8317, 86 | 0x0312,0x0330,0x8335,0x833f,0x033a,0x832b,0x032e,0x0324,0x8321, 87 | 0x0360,0x8365,0x836f,0x036a,0x837b,0x037e,0x0374,0x8371,0x8353, 88 | 0x0356,0x035c,0x8359,0x0348,0x834d,0x8347,0x0342,0x03c0,0x83c5, 89 | 0x83cf,0x03ca,0x83db,0x03de,0x03d4,0x83d1,0x83f3,0x03f6,0x03fc, 90 | 0x83f9,0x03e8,0x83ed,0x83e7,0x03e2,0x83a3,0x03a6,0x03ac,0x83a9, 91 | 0x03b8,0x83bd,0x83b7,0x03b2,0x0390,0x8395,0x839f,0x039a,0x838b, 92 | 0x038e,0x0384,0x8381,0x0280,0x8285,0x828f,0x028a,0x829b,0x029e, 93 | 0x0294,0x8291,0x82b3,0x02b6,0x02bc,0x82b9,0x02a8,0x82ad,0x82a7, 94 | 0x02a2,0x82e3,0x02e6,0x02ec,0x82e9,0x02f8,0x82fd,0x82f7,0x02f2, 95 | 0x02d0,0x82d5,0x82df,0x02da,0x82cb,0x02ce,0x02c4,0x82c1,0x8243, 96 | 0x0246,0x024c,0x8249,0x0258,0x825d,0x8257,0x0252,0x0270,0x8275, 97 | 0x827f,0x027a,0x826b,0x026e,0x0264,0x8261,0x0220,0x8225,0x822f, 98 | 0x022a,0x823b,0x023e,0x0234,0x8231,0x8213,0x0216,0x021c,0x8219, 99 | 0x0208,0x820d,0x8207,0x0202}; 100 | 101 | unsigned int Message::computecrc16(unsigned char *data,int len) 102 | { 103 | 104 | unsigned int acc = 0x00; 105 | 106 | 107 | for(int i=0;i> 8) ^ crc_table16[(acc ^ data[i]) & 0xff]; 111 | } 112 | 113 | 114 | return acc; 115 | } 116 | 117 | void Message::PrintState() 118 | { 119 | if((Source!=PDM)&&(Source!=POD)) return; 120 | fprintf(stderr,"Msg Layer:"); 121 | switch(Source) 122 | { 123 | case PDM:fprintf(stderr,"PDM ");break; 124 | case POD:fprintf(stderr,"POD ");break; 125 | 126 | default:fprintf(stderr,"UNKOWN ");break; 127 | } 128 | fprintf(stderr,"ID2:%08x ",ID2); 129 | fprintf(stderr,"Seq:%d ",Sequence); 130 | fprintf(stderr,"Len:%d/%d ",MessageLen,TargetLen); 131 | fprintf(stderr,"crc16:%04x/%04x ",crc16,computecrc16(CompleteRawMessage,RawLen-2)); 132 | if(IsValid) fprintf(stderr,"(OK)"); else fprintf(stderr,"(KO)"); 133 | for(int i=0;i>24; 153 | CompleteRawMessage[1]=ID2>>16; 154 | CompleteRawMessage[2]=ID2>>8; 155 | CompleteRawMessage[3]=ID2&0xFF; 156 | 157 | CompleteRawMessage[4]=(Sequence<<2)|((MessageLen>>8)&0x3); 158 | CompleteRawMessage[5]=MessageLen&0xFF; 159 | 160 | memcpy(CompleteRawMessage+6,Body,MessageLen); 161 | 162 | unsigned int Messagecrc=computecrc16(CompleteRawMessage,MessageLen+6); 163 | CompleteRawMessage[MessageLen+6]=Messagecrc>>8; 164 | CompleteRawMessage[MessageLen+6+1]=Messagecrc&0xFF; 165 | 166 | int MessageLengthRemaining=MessageLen+6+2; 167 | int ByteSent=0; 168 | do 169 | { 170 | packet_list[packet_list_len].ID1=ID1; 171 | packet_list[packet_list_len].Sequence=PacketSequence; 172 | if(packet_list_len==0) 173 | packet_list[packet_list_len].Type=Source; 174 | else 175 | packet_list[packet_list_len].Type=CON; 176 | 177 | if(MessageLengthRemaining>(MAX_BYTE_BODY)) 178 | 179 | packet_list[packet_list_len].PacketLen=MAX_BYTE_BODY; 180 | else 181 | packet_list[packet_list_len].PacketLen=MessageLengthRemaining; 182 | memcpy(packet_list[packet_list_len].Body,CompleteRawMessage+ByteSent,packet_list[packet_list_len].PacketLen); 183 | ByteSent+= packet_list[packet_list_len].PacketLen; 184 | MessageLengthRemaining-=packet_list[packet_list_len].PacketLen; 185 | packet_list_len++; 186 | 187 | PacketSequence=(PacketSequence+2)%32; //+2 because POD should always answer with packet +1 188 | 189 | } 190 | while (MessageLengthRemaining>0); 191 | return packet_list_len; 192 | 193 | } 194 | 195 | int Message::AddToBody(unsigned char* SubMessage,unsigned int SubMessageLen) 196 | { 197 | memcpy(Body+MessageLen,SubMessage,SubMessageLen); 198 | MessageLen+=SubMessageLen; 199 | return 0; 200 | } 201 | 202 | 203 | -------------------------------------------------------------------------------- /Message.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _MESSAGE 3 | #define _MESSAGE 4 | 5 | #include "Packet.h" 6 | #define MAX_BYTE_MSG_BODY 32000 7 | #define MAX_PACKET_BY_MESSAGE 10 8 | class Message 9 | { 10 | 11 | private: 12 | unsigned char CompleteRawMessage[MAX_BYTE_MSG_BODY]; 13 | unsigned int RawLen=0; 14 | public: 15 | unsigned Source=0; 16 | unsigned int ID2=0; 17 | unsigned int Sequence=0; 18 | unsigned int TargetLen=0; 19 | unsigned int MessageLen=0; 20 | unsigned int crc16=0; 21 | unsigned char Body[MAX_BYTE_MSG_BODY]; 22 | Packet packet_list[MAX_PACKET_BY_MESSAGE]; 23 | int packet_list_len=0; 24 | bool IsValid=false; 25 | int SetMessageFromPacket(Packet *packet); 26 | Message(); 27 | ~Message(); 28 | unsigned int computecrc16(unsigned char *data,int len); 29 | void PrintState(); 30 | 31 | int SetFirst(Packet *packet); 32 | int SetCon(Packet *packet); 33 | int Reset(); 34 | 35 | int PacketizeMessage(unsigned int ID1,unsigned int Sequence); 36 | int AddToBody(unsigned char* SubMessage,unsigned int SubMessageLen); 37 | }; 38 | #endif 39 | -------------------------------------------------------------------------------- /MessageHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageHandler.h" 2 | #include "SubMessage.h" 3 | #include 4 | #include 5 | #include 6 | 7 | MessageHandler::MessageHandler(RFModem *current_modem,bool Monitoring_mode) 8 | { 9 | modem=current_modem; 10 | Monitoring=Monitoring_mode; 11 | packethandler.Init(modem,Monitoring); 12 | } 13 | 14 | MessageHandler::~MessageHandler() 15 | { 16 | 17 | } 18 | 19 | int MessageHandler::SetMessageSequence(int MsgSequence) 20 | { 21 | if(MsgSequence<0) MsgSequence+=16; 22 | MessageSequence=MsgSequence%16; 23 | return 0; 24 | } 25 | 26 | void MessageHandler::SetLotTid(unsigned long TheLot,unsigned long TheTid) 27 | { 28 | Lotid=TheLot; 29 | Tid=TheTid; 30 | PODSeed.SetLotTid(Lotid,Tid); 31 | } 32 | 33 | int MessageHandler::WaitForNextMessage() 34 | { 35 | 36 | if(Monitoring) 37 | { 38 | if(packethandler.WaitForNextPacket()==1) 39 | { 40 | 41 | int res= message.SetMessageFromPacket(&packethandler.rcvpacket); 42 | message.PrintState(); 43 | fprintf(stderr,"\n"); 44 | if(res==0) ParseSubMessage(); 45 | 46 | 47 | 48 | 49 | } 50 | } 51 | else 52 | { 53 | if(packethandler.WaitForNextPacket()==1) 54 | { 55 | //packethandler.packet.PrintState(); 56 | int res= message.SetMessageFromPacket(&packethandler.rcvpacket); 57 | if(res==0) message.PrintState(); 58 | fprintf(stderr,"\n"); 59 | if(res==0) 60 | { 61 | MessageSequence=message.Sequence; 62 | 63 | ParseSubMessage(); 64 | } 65 | return res; 66 | 67 | 68 | } 69 | } 70 | return -1; 71 | } 72 | 73 | 74 | int MessageHandler::ParseSubMessage() 75 | { 76 | 77 | 78 | 79 | int IndexInMessage=0; 80 | int res=0; 81 | do 82 | { 83 | SubMessage submessage(&message); 84 | 85 | res=submessage.ParseSubMessage(message.Body+IndexInMessage,message.TargetLen-IndexInMessage); 86 | if(res!=-1) IndexInMessage+=res; 87 | if(submessage.Len>0) 88 | { 89 | submessage.PrintState(); 90 | #define ANSI_COLOR_GREEN "\x1b[32m" 91 | #define ANSI_COLOR_RESET "\x1b[0m" 92 | #define ANSI_COLOR_RED "\x1b[31m" 93 | fprintf(stderr,ANSI_COLOR_GREEN); 94 | switch(submessage.Type) 95 | { 96 | case 0x1D: 97 | { 98 | PODStatus.SetFromSubMessage(&submessage); 99 | PODStatus.InterpertSubmessage(); 100 | PODStatus.PrintState(); 101 | }break; 102 | case 0x06: 103 | { 104 | PODSeed.SetFromSubMessage(&submessage,MessageSequence); 105 | PODSeed.InterpertSubmessage(); 106 | PODSeed.PrintState(); 107 | }break; 108 | 109 | case 0x01: 110 | { 111 | podpairing.SetFromSubMessage(&submessage); 112 | podpairing.InterpertSubmessage(); 113 | podpairing.PrintState(); 114 | //Lotid=podpairing.Lot; 115 | //Tid=podpairing.Tid; 116 | 117 | // Add update ID2 / LotID /TID 118 | } 119 | break; 120 | default: 121 | { 122 | fprintf(stderr,ANSI_COLOR_RED); 123 | fprintf(stderr,"SubMessage Type %x not parsed\n",submessage.Type); 124 | } 125 | break; 126 | } 127 | 128 | fprintf(stderr,ANSI_COLOR_RESET); 129 | } 130 | } 131 | while(res!=-1); 132 | return 0; 133 | 134 | } 135 | 136 | int MessageHandler::TxMessage() 137 | { 138 | 139 | //packethandler.txack.ID1=ID1; 140 | 141 | 142 | message.ID2=ID2; 143 | message.Sequence=MessageSequence; 144 | message.Source=PDM; 145 | message.PacketizeMessage(ID1,packethandler.Sequence); 146 | int res=0; 147 | for(int i=0;i",MessageSequence); 216 | SetMessageSequence(MessageSequence+1); 217 | fprintf(stderr,"Msg Seq cmd=%d\n",MessageSequence); 218 | 219 | PDMGetState cmdgetstate; 220 | cmdgetstate.Create(TypeState); 221 | message.Reset(); 222 | cmdgetstate.submessage.AttachToMessage(&message); 223 | cmdgetstate.submessage.AddToMessage(); 224 | return TxMessage(); 225 | } 226 | 227 | int MessageHandler::Pairing(unsigned long TargetID2) 228 | { 229 | ID1=0xFFFFFFFF; 230 | ID2=0xFFFFFFFF; 231 | packethandler.SetTxAckID(ID1,TargetID2); 232 | 233 | SetMessageSequence(0); 234 | packethandler.Sequence=0; 235 | 236 | PDMPairing cmdpdmpairing; 237 | cmdpdmpairing.Create(TargetID2); 238 | message.Reset(); 239 | cmdpdmpairing.submessage.AttachToMessage(&message); 240 | cmdpdmpairing.submessage.AddToMessage(); 241 | 242 | return TxMessage(); 243 | 244 | } 245 | 246 | int MessageHandler::VerifyPairing(unsigned long TargetID2) 247 | { 248 | ID1=0xFFFFFFFF; 249 | ID2=0xFFFFFFFF; 250 | packethandler.SetTxAckID(ID1,TargetID2); 251 | SetMessageSequence(MessageSequence-1); 252 | 253 | PDMVerifyPairing cmdpdmverifypairing; 254 | cmdpdmverifypairing.Create(TargetID2,Lotid,Tid); 255 | message.Reset(); 256 | cmdpdmverifypairing.submessage.AttachToMessage(&message); 257 | cmdpdmverifypairing.submessage.AddToMessage(); 258 | 259 | return TxMessage(); 260 | 261 | } 262 | 263 | int MessageHandler::FinishPairing(unsigned long TargetID2) 264 | { 265 | ID1=ID2=TargetID2; 266 | 267 | packethandler.SetTxAckID(ID1,ID2); 268 | SetMessageSequence(MessageSequence+1);//2 269 | 270 | PDMCancelTime cmdpdmcanceltime; 271 | 272 | nonce.SyncNonce(Lotid,Tid,0); 273 | unsigned long FirstNonce=nonce.GetNounce(0); 274 | 275 | cmdpdmcanceltime.Create(FirstNonce,0); 276 | message.Reset(); 277 | cmdpdmcanceltime.submessage.AttachToMessage(&message); 278 | cmdpdmcanceltime.submessage.AddToMessage(); 279 | 280 | return TxMessage(); 281 | 282 | } 283 | 284 | int MessageHandler::FinishPairing2(unsigned long TargetID2) 285 | { 286 | ID1=ID2=TargetID2; 287 | 288 | packethandler.SetTxAckID(ID1,ID2); 289 | SetMessageSequence(MessageSequence+1);//4 290 | PDMCancelTime cmdpdmcanceltime; 291 | 292 | nonce.SyncNonce(Lotid,Tid,0); 293 | unsigned long FirstNonce=nonce.GetNounce(1); 294 | cmdpdmcanceltime.Create(FirstNonce,1); 295 | message.Reset(); 296 | cmdpdmcanceltime.submessage.AttachToMessage(&message); 297 | cmdpdmcanceltime.submessage.AddToMessage(); 298 | 299 | return TxMessage(); 300 | 301 | } 302 | 303 | int MessageHandler::Purging() 304 | { 305 | SetMessageSequence(MessageSequence+1);//6 306 | PDMBolus cmdpdmbolus; 307 | 308 | nonce.SyncNonce(Lotid,Tid,0); 309 | unsigned long ComputeNonce=nonce.GetNounce(2); 310 | cmdpdmbolus.Create(2.6,ComputeNonce,true); 311 | message.Reset(); 312 | cmdpdmbolus.submessage.AttachToMessage(&message); 313 | cmdpdmbolus.submessage.AddToMessage(); 314 | cmdpdmbolus.CreateExtra(2.6,true); 315 | cmdpdmbolus.submessage.AddToMessage(); 316 | 317 | return TxMessage(); 318 | 319 | } 320 | 321 | int MessageHandler::FinishPurging() 322 | { 323 | SetMessageSequence(MessageSequence+1);//8 324 | PDMCancelTime cmdpdmcanceltime; 325 | 326 | nonce.SyncNonce(Lotid,Tid,0); 327 | unsigned long FirstNonce=nonce.GetNounce(3); 328 | cmdpdmcanceltime.Create(FirstNonce,2); 329 | message.Reset(); 330 | cmdpdmcanceltime.submessage.AttachToMessage(&message); 331 | cmdpdmcanceltime.submessage.AddToMessage(); 332 | 333 | return TxMessage(); 334 | 335 | } 336 | 337 | int MessageHandler::BeginInjection() 338 | { 339 | SetMessageSequence(MessageSequence+1);//10 340 | PDMBasal cmdpdmbasal; 341 | 342 | nonce.SyncNonce(Lotid,Tid,0); 343 | unsigned long ComputeNonce=nonce.GetNounce(4); 344 | cmdpdmbasal.Create(0,ComputeNonce,true); 345 | message.Reset(); 346 | cmdpdmbasal.submessage.AttachToMessage(&message); 347 | cmdpdmbasal.submessage.AddToMessage(); 348 | cmdpdmbasal.CreateExtra(0,true); 349 | cmdpdmbasal.submessage.AddToMessage(); 350 | 351 | return TxMessage(); 352 | } 353 | 354 | int MessageHandler::FinishInjection() 355 | { 356 | SetMessageSequence(MessageSequence+1);//12 357 | PDMCancelTime cmdpdmcanceltime; 358 | 359 | nonce.SyncNonce(Lotid,Tid,0); 360 | unsigned long FirstNonce=nonce.GetNounce(5); 361 | cmdpdmcanceltime.Create(FirstNonce,3); 362 | message.Reset(); 363 | cmdpdmcanceltime.submessage.AttachToMessage(&message); 364 | cmdpdmcanceltime.submessage.AddToMessage(); 365 | 366 | return TxMessage(); 367 | } 368 | 369 | int MessageHandler::FinishInjection2() 370 | { 371 | 372 | SetMessageSequence(MessageSequence+1);//14 373 | PDMBolus cmdpdmbolus; 374 | 375 | nonce.SyncNonce(Lotid,Tid,0); 376 | unsigned long ComputeNonce=nonce.GetNounce(6); 377 | cmdpdmbolus.Create(0.5,ComputeNonce,true); 378 | message.Reset(); 379 | cmdpdmbolus.submessage.AttachToMessage(&message); 380 | cmdpdmbolus.submessage.AddToMessage(); 381 | cmdpdmbolus.CreateExtra(0.5,true); 382 | cmdpdmbolus.submessage.AddToMessage(); 383 | 384 | return TxMessage(); 385 | 386 | } 387 | 388 | int MessageHandler::Bolus(float units) 389 | { 390 | packethandler.SetTxAckID(ID1,0); 391 | SetMessageSequence(MessageSequence+1); 392 | int RememberSeq=MessageSequence; 393 | PDMBolus cmdpdmbolus; 394 | cmdpdmbolus.Create(units,0x851072aa,false); 395 | message.Reset(); 396 | cmdpdmbolus.submessage.AttachToMessage(&message); 397 | cmdpdmbolus.submessage.AddToMessage(); 398 | cmdpdmbolus.CreateExtra(units,false); 399 | cmdpdmbolus.submessage.AddToMessage(); 400 | int res= TxMessage(); 401 | if(res==0) 402 | { 403 | sleep(1); 404 | SetMessageSequence(RememberSeq); // Exceptionnaly same msg sequence 405 | nonce.SyncNonce(Lotid,Tid,PODSeed.Seed); 406 | unsigned long ComputeNonce=nonce.GetNounce(0); 407 | cmdpdmbolus.Create(units,ComputeNonce,false); 408 | message.Reset(); 409 | cmdpdmbolus.submessage.AttachToMessage(&message); 410 | cmdpdmbolus.submessage.AddToMessage(); 411 | cmdpdmbolus.CreateExtra(units,false); 412 | cmdpdmbolus.submessage.AddToMessage(); 413 | return TxMessage(); 414 | } 415 | return -1; 416 | } 417 | 418 | 419 | 420 | -------------------------------------------------------------------------------- /MessageHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef _MESSAGE_HANDLER 2 | #define _MESSAGE_HANDLER 3 | 4 | #include "Message.h" 5 | #include "PacketHandler.h" 6 | #include "SubMessageStatus.h" 7 | #include "SubMessageSeed.h" 8 | #include "PODPairing.h" 9 | #include "PDMPairing.h" 10 | #include "PDMVerifyPairing.h" 11 | #include "PDMCancelTime.h" 12 | #include "PDMGetState.h" 13 | #include "Nonce.h" 14 | #include "PDMBolus.h" 15 | #include "PDMBasal.h" 16 | 17 | class MessageHandler 18 | { 19 | 20 | private: 21 | RFModem *modem; 22 | unsigned char MessageSequence=0xFF; 23 | 24 | bool Monitoring=true; 25 | bool Transmitting=false; 26 | 27 | 28 | public: 29 | PacketHandler packethandler; 30 | unsigned long ID1; 31 | unsigned long ID2; 32 | Message message; 33 | SubMessageStatus PODStatus; 34 | SubMessageSeed PODSeed; 35 | PodPairing podpairing; 36 | PDMPairing pdmpairing; 37 | Nonce nonce; 38 | unsigned long Lotid; 39 | unsigned long Tid; 40 | 41 | MessageHandler(RFModem *current_modem,bool Monitoring_mode=true); 42 | ~MessageHandler(); 43 | 44 | void SetLotTid(unsigned long TheLot,unsigned long TheTid); 45 | int SetMessageSequence(int MsgSequence); 46 | int WaitForNextMessage(); 47 | int ParseSubMessage(); 48 | 49 | int TxMessage(); 50 | int TxMessageWaitAck(int MaxRetry); 51 | 52 | 53 | int GetPodState(int TypeState); 54 | int Pairing(unsigned long TargetID2); 55 | int VerifyPairing(unsigned long TargetID2); 56 | int FinishPairing(unsigned long TargetID2); 57 | int FinishPairing2(unsigned long TargetID2); 58 | int Purging(); 59 | int FinishPurging(); 60 | int BeginInjection(); 61 | int FinishInjection(); 62 | int FinishInjection2(); 63 | int Bolus(float units); 64 | }; 65 | #endif 66 | -------------------------------------------------------------------------------- /Nonce.cpp: -------------------------------------------------------------------------------- 1 | #include "Nonce.h" 2 | #include 3 | 4 | Nonce::Nonce() 5 | { 6 | TabNounce=(unsigned long*)malloc(MAX_NOUNCES_PROCESS*sizeof(unsigned long)); 7 | } 8 | 9 | Nonce::~Nonce() 10 | { 11 | free(TabNounce); 12 | TabNounce=NULL; 13 | } 14 | 15 | int Nonce::SyncNonce(unsigned long lot, unsigned long tid,int Seed) 16 | { 17 | unsigned long Nonce=0; 18 | unsigned char byte_F9=0; 19 | 20 | a7[0]=(lot & 0xFFFF) + 0x55543DC3 + (lot >> 16); 21 | a7[0]&=0xFFFFFFFF; 22 | a7[1]=(tid & 0xFFFF) + 0xAAAAE44E + (tid >> 16); 23 | a7[1]&=0xFFFFFFFF; 24 | 25 | 26 | 27 | a7[0]+=(Seed&0xFF); 28 | 29 | 30 | for(int i=2;i<18;i++) 31 | { 32 | a7[i]=GenerateEntryNonce(); 33 | } 34 | 35 | if(Seed==0) 36 | byte_F9 = (a7[0] + a7[1]) & 0xF; 37 | else 38 | byte_F9=(a7[0] + a7[1]) & 0xF; 39 | for(int i=0;i<=MAX_NOUNCES_PROCESS;i++) 40 | { 41 | 42 | Nonce=a7[2+byte_F9]; 43 | TabNounce[i]=Nonce; 44 | a7[2 + byte_F9] = GenerateEntryNonce(); 45 | byte_F9=Nonce&0xF; 46 | 47 | } 48 | fprintf(stderr,"Set Nonce table for Lot %ld Tid %ld\n",lot,tid); 49 | return 0; 50 | } 51 | 52 | unsigned long Nonce::GenerateEntryNonce() 53 | { 54 | a7[0] = ((a7[0] >> 16) + (a7[0] & 0xFFFF) * 0x5D7F) & 0xFFFFFFFF; 55 | a7[1] = ((a7[1] >> 16) + (a7[1] & 0xFFFF) * 0x8CA0) & 0xFFFFFFFF; 56 | return ((a7[1] + (a7[0] << 16)) & 0xFFFFFFFF); 57 | } 58 | 59 | 60 | unsigned long Nonce::GetNounce(int IndexNounce) 61 | { 62 | unsigned long ProcessNounce=TabNounce[IndexNounce]; 63 | fprintf(stderr,"Nonce(%d)= %lx\n",IndexNounce,ProcessNounce); 64 | return ProcessNounce; 65 | } 66 | 67 | int Nonce::PrintState() 68 | { 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /Nonce.h: -------------------------------------------------------------------------------- 1 | #ifndef _NONCE 2 | #define _NONCE 3 | #include 4 | #include 5 | #define MAX_NOUNCES_PROCESS 100 6 | 7 | class Nonce 8 | { 9 | private: 10 | unsigned long *TabNounce=NULL; 11 | unsigned long a7[18]; 12 | unsigned long GenerateEntryNonce(); 13 | public: 14 | 15 | 16 | Nonce(); 17 | ~Nonce(); 18 | int SyncNonce(unsigned long lot, unsigned long tid,int Seed); 19 | unsigned long GetNounce(int IndexNounce); 20 | int PrintState(); 21 | 22 | }; 23 | #endif 24 | -------------------------------------------------------------------------------- /PDMBasal.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMBasal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | PDMBasal::PDMBasal() 8 | { 9 | 10 | } 11 | 12 | void PDMBasal::SetFromSubMessage(SubMessage *submessage_in) 13 | { 14 | submessage.Len=submessage_in->Len; 15 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 16 | } 17 | 18 | 19 | int PDMBasal::InterpertSubmessage() 20 | { 21 | 22 | 23 | return 0; 24 | 25 | } 26 | 27 | int PDMBasal::PrintState() 28 | { 29 | 30 | return 0; 31 | } 32 | 33 | int PDMBasal::Create(float Units,unsigned int Nonce,bool DividedFieldA) 34 | { 35 | 36 | submessage.Type=0x1a; 37 | submessage.Len=22; 38 | 39 | submessage.Body[0]=Nonce>>24; 40 | submessage.Body[1]=Nonce>>16; 41 | submessage.Body[2]=Nonce>>8; 42 | submessage.Body[3]=Nonce&0xFF; 43 | 44 | 45 | //00 01 dc 22 2c c0 00 03 10 04 b8 03 f8 04 f8 04 18 04 46 | submessage.Body[4]=0x00; 47 | submessage.Body[5]=0x01; 48 | submessage.Body[6]=0xdc; 49 | submessage.Body[7]=0x22; 50 | submessage.Body[8]=0x2c; 51 | submessage.Body[9]=0xc0; 52 | submessage.Body[10]=0x00; 53 | submessage.Body[11]=0x03; 54 | submessage.Body[12]=0x10; 55 | submessage.Body[13]=0x04; 56 | submessage.Body[14]=0xB8; 57 | submessage.Body[15]=0x03; 58 | submessage.Body[16]=0xF8; 59 | submessage.Body[17]=0x04; 60 | submessage.Body[18]=0xF8; 61 | submessage.Body[19]=0x04; 62 | submessage.Body[20]=0x18; 63 | submessage.Body[21]=0x04; 64 | 65 | return 0; 66 | } 67 | 68 | int PDMBasal::CreateExtra(float Units,bool Pairing) 69 | { 70 | submessage.Type=0x13; 71 | submessage.Len=26; 72 | 73 | //40 02 02 6d 01 e8 48 00 00 2d 02 62 5a 00 01 c7 03 10 bc db 05 fa 02 62 5a 00 74 | submessage.Body[0]=0x40; 75 | submessage.Body[1]=0x02; 76 | submessage.Body[2]=0x02; 77 | submessage.Body[3]=0x6d; 78 | 79 | submessage.Body[4]=0x01; 80 | submessage.Body[5]=0xE8; 81 | submessage.Body[6]=0x48; 82 | submessage.Body[7]=0x00; 83 | submessage.Body[8]=0x00; 84 | submessage.Body[9]=0x2d; 85 | submessage.Body[10]=0x02; 86 | submessage.Body[11]=0x62; 87 | submessage.Body[12]=0x5a; 88 | submessage.Body[13]=0x00; 89 | submessage.Body[14]=0x01; 90 | submessage.Body[15]=0xC7; 91 | submessage.Body[16]=0x03; 92 | submessage.Body[17]=0x10; 93 | submessage.Body[18]=0xBC; 94 | submessage.Body[19]=0xDB; 95 | submessage.Body[20]=0x05; 96 | submessage.Body[21]=0xFA; 97 | submessage.Body[22]=0x02; 98 | submessage.Body[23]=0x62; 99 | submessage.Body[24]=0x5A; 100 | submessage.Body[25]=0x00; 101 | return 0; 102 | } 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /PDMBasal.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMBASAL 3 | #define _PDMBASAL 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMBasal 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | unsigned long ID2; 16 | 17 | PDMBasal(); 18 | void SetFromSubMessage(SubMessage *submessage_in); 19 | int InterpertSubmessage(); 20 | int PrintState(); 21 | int Create(float Units,unsigned int Nonce,bool DividedFieldA); 22 | int CreateExtra(float Units,bool Pairing); 23 | }; 24 | #endif 25 | -------------------------------------------------------------------------------- /PDMBolus.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMBolus.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | PDMBolus::PDMBolus() 8 | { 9 | 10 | } 11 | 12 | void PDMBolus::SetFromSubMessage(SubMessage *submessage_in) 13 | { 14 | submessage.Len=submessage_in->Len; 15 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 16 | } 17 | 18 | 19 | int PDMBolus::InterpertSubmessage() 20 | { 21 | 22 | 23 | return 0; 24 | 25 | } 26 | 27 | int PDMBolus::PrintState() 28 | { 29 | 30 | return 0; 31 | } 32 | 33 | int PDMBolus::Create(float Units,unsigned int Nonce,bool DividedFieldA) 34 | { 35 | 36 | submessage.Type=0x1a; 37 | submessage.Len=14; 38 | 39 | submessage.Body[0]=Nonce>>24; 40 | submessage.Body[1]=Nonce>>16; 41 | submessage.Body[2]=Nonce>>8; 42 | submessage.Body[3]=Nonce&0xFF; 43 | 44 | submessage.Body[4]=0x2; // BOLUS TYPE 45 | 46 | submessage.Body[7]=1; // Duration 30 minutes 47 | unsigned int FieldA=0; 48 | if(DividedFieldA) 49 | FieldA=round(Units*8.0/0.05); 50 | else 51 | FieldA=round(Units*16.0/0.05); 52 | 53 | submessage.Body[8]=FieldA>>8; 54 | submessage.Body[9]=FieldA&0xFF; 55 | unsigned int UnitRate=round(Units/0.05); 56 | submessage.Body[10]=UnitRate>>8; 57 | submessage.Body[11]=UnitRate&0xFF; 58 | submessage.Body[12]=UnitRate>>8; 59 | submessage.Body[13]=UnitRate&0xFF; 60 | 61 | unsigned int CheckSum=0; 62 | for(int i=7;i<14;i++) 63 | { 64 | CheckSum+=submessage.Body[i]; 65 | } 66 | CheckSum=CheckSum&0xFFFF; 67 | submessage.Body[5]=CheckSum>>8; 68 | submessage.Body[6]=CheckSum&0xFF; 69 | 70 | return 0; 71 | } 72 | 73 | int PDMBolus::CreateExtra(float Units,bool Pairing) 74 | { 75 | submessage.Type=0x17; 76 | submessage.Len=13; 77 | //Correct : 00 02 08 00 01 86 a0 00 00 00 00 00 00 78 | //False : 1f108958ae1f108958181f1a0e7926c76d02010a0101a000340034 170d 00 02 08 00 00 18 6a f8 79 | unsigned int UnitExtra=round(Units/(0.1*0.05)); 80 | submessage.Body[0]=0; 81 | submessage.Body[1]=UnitExtra>>8; 82 | submessage.Body[2]=UnitExtra&0xFF; 83 | submessage.Body[3]=0; 84 | if(Pairing) 85 | { 86 | 87 | submessage.Body[4]=0x01;//Unkown -> 200000 in decimal 88 | submessage.Body[5]=0x86; 89 | submessage.Body[6]=0xA0; 90 | submessage.Body[7]=0x0; 91 | submessage.Body[8]=0x0; 92 | submessage.Body[9]=0x0; 93 | submessage.Body[10]=0x0; 94 | submessage.Body[11]=0x0; 95 | submessage.Body[12]=0x0; 96 | } 97 | else 98 | { 99 | submessage.Body[4]=0x03;//Unkown -> 200000 in decimal 100 | submessage.Body[5]=0x0D; 101 | submessage.Body[6]=0x40; 102 | submessage.Body[7]=0x0; 103 | submessage.Body[8]=0x0; 104 | submessage.Body[9]=0x0; 105 | submessage.Body[10]=0x0; 106 | submessage.Body[11]=0x0; 107 | submessage.Body[12]=0x0; 108 | } 109 | 110 | return 0; 111 | } 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /PDMBolus.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMBOLUS 3 | #define _PDMBOLUS 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMBolus 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | unsigned long ID2; 16 | 17 | PDMBolus(); 18 | void SetFromSubMessage(SubMessage *submessage_in); 19 | int InterpertSubmessage(); 20 | int PrintState(); 21 | int Create(float Units,unsigned int Nonce,bool DividedFieldA); 22 | int CreateExtra(float Units,bool Pairing); 23 | }; 24 | #endif 25 | -------------------------------------------------------------------------------- /PDMCancelTime.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMCancelTime.h" 2 | #include 3 | #include 4 | 5 | 6 | PDMCancelTime::PDMCancelTime() 7 | { 8 | 9 | } 10 | 11 | void PDMCancelTime::SetFromSubMessage(SubMessage *submessage_in) 12 | { 13 | submessage.Len=submessage_in->Len; 14 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 15 | } 16 | 17 | 18 | int PDMCancelTime::InterpertSubmessage() 19 | { 20 | 21 | ID2=(submessage.Body[0]<<24)|(submessage.Body[1]<<16)|(submessage.Body[2]<<8)|(submessage.Body[0]); 22 | return 0; 23 | 24 | } 25 | 26 | int PDMCancelTime::PrintState() 27 | { 28 | printf("Request PDM CancelTime %lx",ID2); 29 | return 0; 30 | } 31 | 32 | int PDMCancelTime::Create(unsigned long Nonce, int Type) 33 | { 34 | 35 | submessage.Type=0x19; 36 | submessage.Len =10; 37 | submessage.Body[0]=Nonce>>24; 38 | submessage.Body[1]=Nonce>>16; 39 | submessage.Body[2]=Nonce>>8; 40 | submessage.Body[3]=Nonce&0xFF; 41 | // 42 | if(Type==0) 43 | { 44 | submessage.Body[4]=0x4c; 45 | submessage.Body[5]=0x00; 46 | submessage.Body[6]=0x00; 47 | submessage.Body[7]=0x64; 48 | submessage.Body[8]=0x01; 49 | submessage.Body[9]=0x02; 50 | } 51 | if(Type==1) 52 | { 53 | submessage.Body[4]=0x78; 54 | submessage.Body[5]=0x37; 55 | submessage.Body[6]=0x00; 56 | submessage.Body[7]=0x05; 57 | submessage.Body[8]=0x08; 58 | submessage.Body[9]=0x02; 59 | } 60 | if(Type==2) 61 | { 62 | submessage.Body[4]=0x38; 63 | submessage.Body[5]=0x00; 64 | submessage.Body[6]=0x10; 65 | submessage.Body[7]=0xA3; 66 | submessage.Body[8]=0x03; 67 | submessage.Body[9]=0x02; 68 | } 69 | if(Type==3) 70 | { 71 | 72 | // //79a410df0502280012830602020f00000202 73 | //79 a4 10 df 05 02 28 00 12 83 06 02 02 0f 00 00 02 02 74 | submessage.Body[4]=0x79; 75 | submessage.Body[5]=0xa4; 76 | submessage.Body[6]=0x10; 77 | submessage.Body[7]=0xdf; 78 | submessage.Body[8]=0x05; 79 | submessage.Body[9]=0x02; 80 | submessage.Body[10]=0x28; 81 | submessage.Body[11]=0x00; 82 | submessage.Body[12]=0x12; 83 | submessage.Body[13]=0x83; 84 | submessage.Body[14]=0x06; 85 | submessage.Body[15]=0x02; 86 | submessage.Body[16]=0x02; 87 | submessage.Body[17]=0x0F; 88 | submessage.Body[18]=0x00; 89 | submessage.Body[19]=0x00; 90 | submessage.Body[20]=0x02; 91 | submessage.Body[21]=0x02; 92 | submessage.Len=22; 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /PDMCancelTime.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMCANCELTIME 3 | #define _PDMCANCELTIME 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMCancelTime 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | unsigned long ID2; 16 | 17 | PDMCancelTime(); 18 | void SetFromSubMessage(SubMessage *submessage_in); 19 | int InterpertSubmessage(); 20 | int PrintState(); 21 | int Create(unsigned long Nonce, int Type); 22 | }; 23 | #endif 24 | -------------------------------------------------------------------------------- /PDMGetState.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMGetState.h" 2 | #include 3 | #include 4 | 5 | 6 | PDMGetState::PDMGetState() 7 | { 8 | 9 | } 10 | 11 | void PDMGetState::SetFromSubMessage(SubMessage *submessage_in) 12 | { 13 | submessage.Len=submessage_in->Len; 14 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 15 | } 16 | 17 | 18 | int PDMGetState::InterpertSubmessage() 19 | { 20 | 21 | TypeState=submessage.Body[0]; 22 | return 0; 23 | 24 | } 25 | 26 | int PDMGetState::PrintState() 27 | { 28 | printf("Request POD State type %x",TypeState); 29 | return 0; 30 | } 31 | 32 | int PDMGetState::Create(int Type) 33 | { 34 | submessage.Type=0xE; 35 | TypeState=Type; 36 | submessage.Body[0]=TypeState; 37 | submessage.Len=1; 38 | return 0; 39 | } 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /PDMGetState.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMGETSTATE 3 | #define _PDMGETSTATE 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMGetState 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | int TypeState; 16 | 17 | PDMGetState(); 18 | void SetFromSubMessage(SubMessage *submessage_in); 19 | int InterpertSubmessage(); 20 | int PrintState(); 21 | int Create(int Type); 22 | }; 23 | #endif 24 | -------------------------------------------------------------------------------- /PDMPairing.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMPairing.h" 2 | #include 3 | #include 4 | 5 | 6 | PDMPairing::PDMPairing() 7 | { 8 | 9 | } 10 | 11 | void PDMPairing::SetFromSubMessage(SubMessage *submessage_in) 12 | { 13 | submessage.Len=submessage_in->Len; 14 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 15 | } 16 | 17 | 18 | int PDMPairing::InterpertSubmessage() 19 | { 20 | 21 | ID2=(submessage.Body[0]<<24)|(submessage.Body[1]<<16)|(submessage.Body[2]<<8)|(submessage.Body[0]); 22 | return 0; 23 | 24 | } 25 | 26 | int PDMPairing::PrintState() 27 | { 28 | printf("Request PDM Paring %lx",ID2); 29 | return 0; 30 | } 31 | 32 | int PDMPairing::Create(unsigned long ID2Request) 33 | { 34 | submessage.Type=0x7; 35 | ID2=ID2Request; 36 | submessage.Body[0]=ID2>>24; 37 | submessage.Body[1]=ID2>>16; 38 | submessage.Body[2]=ID2>>8; 39 | submessage.Body[3]=ID2; 40 | submessage.Len=4; 41 | return 0; 42 | } 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PDMPairing.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMPAIRING 3 | #define _PDMPAIRING 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMPairing 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | unsigned long ID2; 16 | 17 | PDMPairing(); 18 | void SetFromSubMessage(SubMessage *submessage_in); 19 | int InterpertSubmessage(); 20 | int PrintState(); 21 | int Create(unsigned long ID2Request); 22 | }; 23 | #endif 24 | -------------------------------------------------------------------------------- /PDMVerifyPairing.cpp: -------------------------------------------------------------------------------- 1 | #include "PDMVerifyPairing.h" 2 | #include 3 | #include 4 | #include 5 | 6 | PDMVerifyPairing::PDMVerifyPairing() 7 | { 8 | 9 | } 10 | 11 | void PDMVerifyPairing::SetFromSubMessage(SubMessage *submessage_in) 12 | { 13 | submessage.Len=submessage_in->Len; 14 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 15 | } 16 | 17 | 18 | int PDMVerifyPairing::InterpertSubmessage() 19 | { 20 | 21 | 22 | return 0; 23 | 24 | } 25 | 26 | int PDMVerifyPairing::PrintState() 27 | { 28 | printf("Request PDM Paring %lx",ID2); 29 | return 0; 30 | } 31 | 32 | int PDMVerifyPairing::Create(unsigned long ID2Request,unsigned long TheLot,unsigned long TheTid) 33 | { 34 | ID2=ID2Request; 35 | Lot=TheLot; 36 | Tid=TheTid; 37 | 38 | submessage.Type=0x3; 39 | submessage.Body[0]=ID2>>24; 40 | submessage.Body[1]=ID2>>16; 41 | submessage.Body[2]=ID2>>8; 42 | submessage.Body[3]=ID2; 43 | submessage.Body[4]=0x0; // Ignored 44 | submessage.Body[5]=0x4; // Unknown 45 | 46 | time_t t = time(NULL); 47 | 48 | struct tm *tm = localtime(&t); 49 | 50 | submessage.Body[6]=tm->tm_mon+1; 51 | submessage.Body[7]=tm->tm_mday; 52 | submessage.Body[8]=tm->tm_year-100; // year from 2000 53 | submessage.Body[9]=tm->tm_hour; 54 | submessage.Body[10]=tm->tm_min; 55 | 56 | // Lot 57 | submessage.Body[11]=Lot>>24; 58 | submessage.Body[12]=Lot>>16; 59 | submessage.Body[13]=Lot>>8; 60 | submessage.Body[14]=Lot&0xFF; 61 | 62 | //Tid 63 | submessage.Body[15]=Tid>>24; 64 | submessage.Body[16]=Tid>>16; 65 | submessage.Body[17]=Tid>>8; 66 | submessage.Body[18]=Tid&0xFF; 67 | submessage.Len=19; 68 | return 0; 69 | } 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /PDMVerifyPairing.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PDMVERIFYPAIRING 3 | #define _PDMVERIFYPAIRING 4 | 5 | #include "Message.h" 6 | #include "SubMessage.h" 7 | #define MAX_BYTE_SUBMSG_BODY 255 8 | 9 | class PDMVerifyPairing 10 | { 11 | private: 12 | 13 | public: 14 | SubMessage submessage; 15 | unsigned long ID2; 16 | unsigned long Tid; 17 | unsigned long Lot; 18 | 19 | PDMVerifyPairing(); 20 | void SetFromSubMessage(SubMessage *submessage_in); 21 | int InterpertSubmessage(); 22 | int PrintState(); 23 | int Create(unsigned long ID2Request,unsigned long TheLot,unsigned long TheTid); 24 | }; 25 | #endif 26 | -------------------------------------------------------------------------------- /PODPairing.cpp: -------------------------------------------------------------------------------- 1 | #include "PODPairing.h" 2 | #include 3 | #include 4 | 5 | PodPairing::PodPairing() 6 | { 7 | 8 | } 9 | 10 | 11 | 12 | void PodPairing::SetFromSubMessage(SubMessage *submessage_in) 13 | { 14 | 15 | submessage.Len=submessage_in->Len; 16 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 17 | } 18 | 19 | 20 | int PodPairing::InterpertSubmessage() 21 | { 22 | 23 | if(submessage.Len<0x15) return -1; 24 | if(submessage.Len==0x1b)//27 25 | { 26 | PM=(submessage.Body[7]<<16)|(submessage.Body[8]<<8)|(submessage.Body[9]); 27 | PI=(submessage.Body[10]<<16)|(submessage.Body[11]<<8)|(submessage.Body[12]); 28 | State=submessage.Body[14]; 29 | Lot=(submessage.Body[15]<<24)|(submessage.Body[16]<<16)|(submessage.Body[17]<<8)|submessage.Body[18]; 30 | Tid=(submessage.Body[19]<<24)|(submessage.Body[20]<<16)|(submessage.Body[21]<<8)|submessage.Body[22]; 31 | ID2= (submessage.Body[23]<<24)|(submessage.Body[24]<<16)|(submessage.Body[25]<<8)|submessage.Body[26]; 32 | 33 | 34 | } 35 | 36 | if(submessage.Len==0x15)//21 37 | { 38 | PM=(submessage.Body[0]<<16)|(submessage.Body[1]<<8)|(submessage.Body[2]); 39 | PI=(submessage.Body[3]<<16)|(submessage.Body[4]<<8)|(submessage.Body[5]); 40 | State=submessage.Body[7]; 41 | Lot=(submessage.Body[8]<<24)|(submessage.Body[9]<<16)|(submessage.Body[10]<<8)|submessage.Body[11]; 42 | Tid=(submessage.Body[12]<<24)|(submessage.Body[13]<<16)|(submessage.Body[14]<<8)|submessage.Body[15]; 43 | Rssi=submessage.Body[16]; 44 | ID2=(submessage.Body[17]<<24)|(submessage.Body[18]<<16)|(submessage.Body[19]<<8)|submessage.Body[20]; 45 | 46 | } 47 | 48 | return 0; 49 | 50 | } 51 | 52 | int PodPairing::PrintState() 53 | { 54 | if(submessage.Len==0x15) 55 | fprintf(stderr,"PodPairing : LotId %ld Tid %ld State = %d ID2=%lx PM=%d.%d.%d PI=%d.%d.%d Rssi=%x \n",Lot,Tid,State,ID2,(int)((PM>>16)&0xFF),(int)((PM>>8)&0xFF),(int)((PM&0xFF)),(int)((PI>>16)&0xFF),(int)((PI>>8)&0xFF),(int)(PI&0xFF),Rssi); 56 | if(submessage.Len==0x1B) 57 | fprintf(stderr,"PodPairing : LotId %ld Tid %ld State = %d ID2=%lx PM=%d.%d.%d PI=%d.%d.%d \n",Lot,Tid,State,ID2,(int)((PM>>16)&0xFF),(int)((PM>>8)&0xFF),(int)((PM&0xFF)),(int)((PI>>16)&0xFF),(int)((PI>>8)&0xFF),(int)(PI&0xFF)); 58 | return 0; 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /PODPairing.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PODPAIRING 3 | #define _PODPAIRING 4 | 5 | #include "SubMessage.h" 6 | 7 | class PodPairing 8 | { 9 | private: 10 | 11 | SubMessage submessage; 12 | int Type=0; 13 | 14 | public: 15 | 16 | unsigned long Tid=0; 17 | unsigned long Lot=0; 18 | unsigned long ID2=0; 19 | unsigned long PM=0; 20 | unsigned long PI=0; 21 | int State=0; 22 | int Rssi=0; 23 | 24 | PodPairing(); 25 | void SetFromSubMessage(SubMessage *submessage_in); 26 | int InterpertSubmessage(); 27 | int PrintState(); 28 | }; 29 | #endif 30 | -------------------------------------------------------------------------------- /Packet.cpp: -------------------------------------------------------------------------------- 1 | #include "Packet.h" 2 | #include 3 | #include 4 | 5 | Packet::Packet() 6 | { 7 | } 8 | 9 | Packet::Packet(unsigned char *Frame,int Len) 10 | { 11 | SetPacketFromFrame(Frame,Len); 12 | } 13 | 14 | Packet::~Packet() 15 | { 16 | } 17 | 18 | int Packet::SetPacketFromFrame(unsigned char *Frame,int Len) 19 | { 20 | Reset(); 21 | crc8=Frame[Len-1]; 22 | if(computecrc_8(0x00,Frame, Len-1)==crc8) IsValid=true; 23 | 24 | ID1=(Frame[0]<<24)|(Frame[1]<<16)|(Frame[2]<<8)|(Frame[3]); 25 | Sequence=Frame[4]&0x1F; 26 | Type=(Frame[4]>>5); 27 | PacketLen=Len-1-5; 28 | memcpy(Body,Frame+5,PacketLen); 29 | clock_gettime(CLOCK_REALTIME, &arrival_time); 30 | return 0; 31 | } 32 | 33 | /** 34 | * \file 35 | * Functions and types for CRC checks. 36 | * 37 | * Generated on Thu Oct 12 16:51:00 2017 38 | * by pycrc v0.9.1, https://pycrc.org 39 | * using the configuration: 40 | * - Width = 8 41 | * - Poly = 0x07 42 | * - XorIn = 0x00 43 | * - ReflectIn = False 44 | * - XorOut = 0x00 45 | * - ReflectOut = False 46 | * - Algorithm = table-driven 47 | */ 48 | 49 | static const unsigned char crc_table[256] = { 50 | 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 51 | 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 52 | 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 53 | 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 54 | 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 55 | 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, 56 | 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 57 | 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 58 | 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 59 | 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 60 | 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 61 | 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, 62 | 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 63 | 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 64 | 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 65 | 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 66 | }; 67 | 68 | 69 | unsigned char Packet::computecrc_8(unsigned char crc, const void *data, int data_len) 70 | { 71 | const unsigned char *d = (const unsigned char *)data; 72 | unsigned int tbl_idx; 73 | 74 | while (data_len--) { 75 | tbl_idx = crc ^ *d; 76 | crc = crc_table[tbl_idx] & 0xff; 77 | d++; 78 | } 79 | return crc & 0xff; 80 | }; 81 | 82 | void Packet::PrintState() 83 | { 84 | fprintf(stderr,"Packet Layer(%ld.%ld):",arrival_time.tv_sec,arrival_time.tv_nsec/(int)1e6); 85 | switch(Type) 86 | { 87 | case PDM:fprintf(stderr,"PDM ");break; 88 | case POD:fprintf(stderr,"POD ");break; 89 | case ACK:fprintf(stderr,"ACK ");break; 90 | case CON:fprintf(stderr,"CON ");break; 91 | default:fprintf(stderr,"UNKOWN ");break; 92 | } 93 | 94 | fprintf(stderr,"ID1:%08x ",ID1); 95 | fprintf(stderr,"Seq:%d PktLen:%d crc8:%x",Sequence,PacketLen,crc8); 96 | if(IsValid) fprintf(stderr,"(OK)"); else fprintf(stderr,"(KO)"); 97 | for(int i=0;i>24; 106 | Frame[1]=ID1>>16; 107 | Frame[2]=ID1>>8; 108 | Frame[3]=ID1&0xFF; 109 | Frame[4]=(Type<<5)|(Sequence&0x1F); 110 | memcpy(Frame+5,Body,PacketLen); 111 | FrameLen=PacketLen+5; 112 | Frame[FrameLen]=computecrc_8(0,Frame,FrameLen); 113 | FrameLen++; 114 | return FrameLen; 115 | 116 | } 117 | 118 | void Packet::Reset() 119 | { 120 | ID1=0; 121 | Type=0; 122 | Sequence=0; 123 | PacketLen=0; 124 | crc8=0; 125 | IsValid=false; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /Packet.h: -------------------------------------------------------------------------------- 1 | #ifndef _PACKET 2 | #define _PACKET 3 | 4 | #include 5 | 6 | #define MAX_BYTE_BODY (31) 7 | enum {ACK=0b010,CON=0b100,PDM=0b101,POD=0b111}; 8 | class Packet 9 | { 10 | 11 | private: 12 | 13 | public: 14 | unsigned int ID1=0; 15 | unsigned char Type=0; 16 | unsigned char Sequence=0; 17 | unsigned int PacketLen=0; 18 | unsigned char crc8=0; 19 | unsigned char Body[MAX_BYTE_BODY]; 20 | struct timespec arrival_time; 21 | 22 | bool IsValid=false; 23 | int SetPacketFromFrame(unsigned char *Frame,int Len); 24 | Packet(); 25 | Packet(unsigned char *Frame,int Len); 26 | ~Packet(); 27 | unsigned char computecrc_8(unsigned char crc, const void *data, int data_len); 28 | void PrintState(); 29 | int GetFrame(unsigned char *Frame); 30 | void Reset(); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /PacketHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "PacketHandler.h" 2 | #include 3 | #include 4 | 5 | 6 | PacketHandler::PacketHandler() 7 | { 8 | } 9 | 10 | 11 | PacketHandler::PacketHandler(RFModem *current_modem,bool Monitoring_mode) 12 | { 13 | Init(current_modem,Monitoring_mode); 14 | 15 | } 16 | 17 | PacketHandler::~PacketHandler() 18 | { 19 | } 20 | 21 | void PacketHandler::Init(RFModem *current_modem,bool Monitoring_mode) 22 | { 23 | modem=current_modem; 24 | Monitoring=Monitoring_mode; 25 | } 26 | 27 | int PacketHandler::WaitForNextPacket() 28 | { 29 | if(Monitoring) 30 | { 31 | while(1) 32 | { 33 | int Len=modem->Receive(Frame,600); 34 | if(Len>0) 35 | { 36 | rcvpacket.SetPacketFromFrame(Frame,Len); 37 | if(rcvpacket.IsValid) 38 | { 39 | rcvpacket.PrintState(); 40 | if(Sequence==0xFF) Sequence=(rcvpacket.Sequence+31)%32; // Init , never has a paquet sequence, set to the first seen 41 | if(rcvpacket.Sequence==(Sequence+1)%32) 42 | { 43 | Sequence=rcvpacket.Sequence; 44 | return(1); 45 | } 46 | else // Bad sequence Number : surely a previous packet not acknowledge 47 | { 48 | 49 | if(rcvpacket.Sequence>Sequence) 50 | { 51 | fprintf(stderr,"Bad packet Seq %d but waited %d\n",rcvpacket.Sequence,(Sequence+1)%32); 52 | Sequence=rcvpacket.Sequence; // FixMe roll up with modulo 32 53 | return(1); 54 | } 55 | return(-1); 56 | } 57 | } 58 | } 59 | else // Timeout 60 | { 61 | return(-2); 62 | } 63 | } 64 | } 65 | else 66 | { 67 | while(1) 68 | { 69 | int Len=modem->Receive(Frame,400); 70 | if(Len>0) 71 | { 72 | rcvpacket.SetPacketFromFrame(Frame,Len); 73 | 74 | if(rcvpacket.IsValid) 75 | { 76 | //if(Transmitting) printf("Tx\n"); else printf("Rx\n"); 77 | rcvpacket.PrintState(); 78 | if(Sequence==0xFF) Sequence=(rcvpacket.Sequence+31)%32; // Init , never has a paquet sequence, set to the first seen 79 | if(rcvpacket.Sequence==(Sequence+1)%32) 80 | { 81 | Sequence=rcvpacket.Sequence; 82 | if(Transmitting) 83 | { 84 | if((rcvpacket.Type==PDM)||(rcvpacket.Type==CON)) continue; //Do not receive or own commands 85 | 86 | } 87 | else 88 | { 89 | if((rcvpacket.Type==ACK)) continue; //Do not receive or own commands 90 | TxAck((rcvpacket.Sequence+1)%32);//answer to POD/CON 91 | } 92 | return(1); 93 | } 94 | else // Bad sequence Number : surely a previous packet not acknowledge 95 | { 96 | Sequence=rcvpacket.Sequence; 97 | if(Transmitting) 98 | { 99 | if((rcvpacket.Type==PDM)||(rcvpacket.Type==CON)) continue; //Do not receive or own commands 100 | } 101 | else 102 | { 103 | if((rcvpacket.Type==ACK)) continue; //Do not receive or own commands 104 | TxAck((rcvpacket.Sequence+1)%32);//answer to POD/CON 105 | } 106 | printf("Bad seq number rcv %d / wanted %d\n",rcvpacket.Sequence,(Sequence+1)%32); 107 | 108 | 109 | //if(!Transmitting) TxAck((rcvpacket.Sequence+1)%32); 110 | return(-1); 111 | } 112 | } 113 | } 114 | else // Timeout 115 | { 116 | return(-2); 117 | } 118 | } 119 | } 120 | 121 | } 122 | 123 | 124 | int PacketHandler::SetTxAckID(unsigned long AckID1,unsigned long AckID2) 125 | { 126 | txack.ID1=AckID1; 127 | txack.Type=ACK; 128 | txack.PacketLen=4; 129 | txack.Body[0]=AckID2>>24; 130 | txack.Body[1]=AckID2>>16; 131 | txack.Body[2]=AckID2>>8; 132 | txack.Body[3]=AckID2; 133 | return 0; 134 | } 135 | 136 | int PacketHandler::TxAck(int AckSequence) 137 | { 138 | txack.Sequence=AckSequence; 139 | Sequence=AckSequence; 140 | fprintf(stderr,"Tx ACK %d\n",AckSequence); 141 | TxPacket(&txack,true); 142 | 143 | return 0; 144 | } 145 | int PacketHandler::TxPacket(Packet *packet_to_tx,bool ShortSync) 146 | { 147 | unsigned char FrameTx[MAX_BYTE_PER_PACKET]; 148 | int len=packet_to_tx->GetFrame(FrameTx); 149 | modem->Transmit(FrameTx,len,ShortSync); 150 | return 0; 151 | } 152 | 153 | int PacketHandler::TxPacketWaitAck(Packet *packet_to_tx,int MaxRetry,bool LastPacket) 154 | { 155 | Transmitting=true; 156 | int TxStatus=0; 157 | for(int i=0;(TxStatus!=1)&&(i 4 | #include 5 | 6 | void *RFModem::ReadSDR(void * arg) 7 | { 8 | RFModem *Modem=(RFModem *)arg; 9 | while(1) 10 | { 11 | int Result=Modem->ProcessRF(); 12 | if(Result==2) 13 | { 14 | sem_post(&sem_receive); 15 | } 16 | //if(Result==0) break; 17 | } 18 | return NULL; 19 | } 20 | 21 | 22 | 23 | RFModem::RFModem() 24 | { 25 | InitRF(); 26 | for(int i=0;i(0,0); 28 | }; 29 | 30 | RFModem::~RFModem() 31 | { 32 | delete fskmod; 33 | }; 34 | 35 | int RFModem::SetIQFile(char *IQFileName,int Direction) 36 | { 37 | if(Direction==0)//Receive 38 | { 39 | iqfilein=fopen(IQFileName, "r"); 40 | if(iqfilein==NULL) {printf("Can't open %s\n",IQFileName);return(-1);}; 41 | pthread_create (&thReadSDR,NULL, &this->ReadSDR,this); 42 | } 43 | /* if(Direction==1)//Transmit 44 | { 45 | iqfileout=fopen (IQFileName, "wb"); 46 | if(iqfileout==NULL) {printf("Can't open %s\n",IQFileName);return(-1);}; 47 | pthread_create (&thWriteSDR,NULL, &this->WriteSDR,this); 48 | }*/ 49 | return 0; 50 | } 51 | 52 | 53 | 54 | 55 | 56 | //RF Process is 57 | // Get U8 IQ sample at 1.3Msymbols (32*Omnipod symbol rate) 58 | // In order to remove DC spike, tuning of receiver is 325KHz above 59 | // 1 : 1.3M U8 IQ -> 1.3M Complex float 60 | // 2 : NCO +325Khz 61 | // 3 : Decimation by 4 62 | // 4 : FM Demodulation 63 | // 5 : Decision with number of transition inside a window of 8 sample 64 | // Todo : Between 2 and 3, make a low pass filtering to avoid replicant signals 65 | // After 3: Make a matched filter (correlator) with conjugate signal of SYNC signal 66 | 67 | void RFModem::InitRF() 68 | { 69 | 70 | float IQSR=1300000.0; // 32*Baudrate 71 | 72 | // Create NCO 73 | float FreqUp= 325000.0+5000; 74 | MyNCO = nco_crcf_create(LIQUID_NCO); 75 | nco_crcf_set_phase(MyNCO, 0.0f); 76 | nco_crcf_set_frequency(MyNCO, 2.0*M_PI*FreqUp/IQSR); // Tuning frequency is SR/4 away : here 256/4=64KHZ : 433923+64=433987 77 | 78 | // Create decimator by 4 79 | 80 | int type = LIQUID_RESAMP_DECIM; 81 | unsigned int num_stages = 2; // decimate by 2^2=4 82 | float fc = 0.2f; // signal cut-off frequency 83 | float f0 = 0.0f; // (ignored) 84 | float As = 60.0f; // stop-band attenuation 85 | MyDecim = msresamp2_crcf_create(type, num_stages, fc, f0, As); 86 | 87 | 88 | float BaudRate=40625.0; 89 | // FM Demodulation 90 | float FSKDeviationHz=26296.0;//26370.0; //Inspectrum show +/-20KHZ ? 91 | 92 | fdem=freqdem_create(FSKDeviationHz*2*4/IQSR); 93 | 94 | //FSK modulator 95 | //fmod = fskmod_create(1,8,FSKDeviationHz/(8*BaudRate)); // 1 bit by symbol / 8 IQ samples by symbol (upsample*8), Deviation : DeviationHz/(Upsample*Baudrate) 96 | //uint64_t Freq=433923000; 97 | float Deviation=26370; 98 | uint64_t Freq=433914000; 99 | int SR=40625; 100 | 101 | int FiFoSize=MAX_SYMBOLS; 102 | fskmod=new fskburst(Freq,SR,Deviation,14,FiFoSize); 103 | ReceiveSampleBySymbol = IQSR/40625; // filter samples/symbol -> Baudrate 104 | buf_rx=(liquid_float_complex*)malloc(ReceiveSampleBySymbol*sizeof(liquid_float_complex)); 105 | iq_buffer=(uint8_t *)malloc(ReceiveSampleBySymbol*2*sizeof(uint8_t)); // 1Byte I, 1Byte Q 106 | 107 | 108 | } 109 | 110 | int RFModem::SetStatus(int Status) 111 | { 112 | StatusModem=Status; 113 | return StatusModem; 114 | } 115 | 116 | //*************************************************************************************************** 117 | //*********************************** RECEIVE PART ************************************************** 118 | //*************************************************************************************************** 119 | 120 | 121 | int RFModem::Receive(unsigned char *Frame,int Timeoutms) 122 | { 123 | struct timespec ts; 124 | clock_gettime(CLOCK_REALTIME, &ts); 125 | 126 | ts.tv_nsec+=Timeoutms*1e6; 127 | if(ts.tv_nsec>1e9) 128 | { 129 | ts.tv_nsec-=1e9; 130 | ts.tv_sec+=1; 131 | } 132 | StatusModem=Status_Receive; 133 | int ReceiveFrame=0; 134 | int res=0; 135 | while((ReceiveFrame==0)&&(res==0)) 136 | { 137 | res= sem_timedwait(&sem_receive,&ts); 138 | if(res==0) 139 | { 140 | if(IndexData>6) 141 | { 142 | memcpy(Frame,BufferData,IndexData); 143 | ReceiveFrame=1; 144 | } 145 | } 146 | } 147 | if(ReceiveFrame==1) 148 | return IndexData; 149 | else 150 | return -1; 151 | } 152 | 153 | 154 | int RFModem::AddData(unsigned char DataValue) 155 | { 156 | static int CountHeader=0; 157 | //printf("\nIndexdata%d->%x:%x\n",IndexData,DataValue^0xFF,DataValue); 158 | if((IndexData==0)&&DataValue==0x54) {CountHeader++;return 1;} //Skip SYNC BYTE : 0x54 is No t inverted 159 | if((IndexData==0)&&DataValue==0xC3) {/*printf("_");*/return 1;} //Skip 2SYNC BYTE : C3 is not inverted 160 | if(IndexData==0) {/*printf("CountHeader=%d\n",CountHeader);*/CountHeader=0;} 161 | if(IndexData=0) 191 | { 192 | //printf(" M%d ",bitDecoded); 193 | 194 | DecodedByte=(DecodedByte<<1)|bitDecoded; 195 | //DecodedByte=(DecodedByte)bitDecoded<<(7-IndexInByte); 196 | if(IndexInByte<7) 197 | { 198 | IndexInByte++; 199 | FinalByteValue=-1; //In decoding state 200 | } 201 | else 202 | { 203 | IndexInByte=0; 204 | FinalByteValue=(DecodedByte)&0xFF; 205 | //printf("."); 206 | //printf("->%x\n",FinalByteValue); 207 | DecodedByte=0; 208 | } 209 | } 210 | else 211 | { 212 | IndexInByte=0; 213 | DecodedByte=0; 214 | FinalByteValue=-1; 215 | } 216 | 217 | return FinalByteValue;// 218 | 219 | } 220 | 221 | //*************************************************************************************************** 222 | //*********************************** FSK LAYER ***************************************************** 223 | //*************************************************************************************************** 224 | 225 | 226 | 227 | #define FSK_SYNC_RUNNING 0 228 | #define FSK_SYNC_ON 1 229 | #define FSK_SYNC_OFF 2 230 | 231 | 232 | 233 | int RFModem::GetFSKSync(unsigned char Sym) 234 | { 235 | static int Index=0; 236 | static unsigned int Buffer=0; 237 | 238 | int FSKCurrentStatus=FSK_SYNC_RUNNING; 239 | 240 | Buffer=((Buffer<<1)&0xFFFE)|Sym; 241 | 242 | if(Buffer==0x6665) {/*printf("#");*/Buffer=0;FSKCurrentStatus=FSK_SYNC_ON;} 243 | if((Buffer&0xF)==0xF) FSKCurrentStatus=FSK_SYNC_OFF; 244 | 245 | return(FSKCurrentStatus); 246 | } 247 | 248 | int RFModem::ProcessRF() 249 | { 250 | 251 | unsigned int i=0; 252 | unsigned int j; 253 | static unsigned int SampleTime=0; 254 | int bytes_read=0; 255 | static int Lock=-1; 256 | float resultautocor=0; 257 | bytes_read = fread(iq_buffer, 1, ReceiveSampleBySymbol*2, iqfilein); 258 | 259 | if(StatusModem!=Status_Receive) return 0; 260 | 261 | if (bytes_read ==ReceiveSampleBySymbol*2) 262 | { 263 | 264 | // convert u8 to f32 and NCO 265 | for (j=0, i=0; j((((uint8_t*)iq_buffer)[j] -127.5)/128.0,(((uint8_t*)iq_buffer)[j+1] -127.5)/128.0); 268 | liquid_float_complex rdown; 269 | nco_crcf_step(MyNCO); 270 | nco_crcf_mix_up(MyNCO, r, &rdown); 271 | buf_rx[i]=rdown; 272 | } 273 | liquid_float_complex AfterDecim[ReceiveSampleBySymbol/4]; 274 | float FmAmplitude[ReceiveSampleBySymbol/4]; 275 | 276 | for(i=0;i=0.4)) 295 | {Sym[NbSymbol++]=1;FMState=1;SampleFromLastTransition=0;} 296 | else 297 | if((FMState==1)&&(FmAmplitude[i]<-0.4)) {Sym[NbSymbol++]=0;FMState=0;SampleFromLastTransition=0;} 298 | 299 | if(SampleFromLastTransition>(ReceiveSampleBySymbol/4+2)) {Sym[NbSymbol++]=FMState;SampleFromLastTransition=0;} 300 | } 301 | 302 | if((NbSymbol>2)||(NbSymbol==0)) return 1;/* else printf("%d",NbSymbol);*/// More than 2 transition is surely noise 303 | 304 | 305 | for(int i=0;i=0) 317 | { 318 | unsigned char ManchesterByte=Manchester; 319 | //fwrite(&ManchesterByte,1,1,ManchesterFile); 320 | if(AddData(Manchester)==0) //Packet is too long !!! 321 | { 322 | FSKSyncStatus=0; 323 | ManchesterAdd(-1); 324 | return(2); 325 | }; 326 | 327 | } 328 | else 329 | { 330 | 331 | if(Manchester==-2) 332 | { 333 | //printf("\n Unlock \n"); 334 | //ParsePacket(SampleTime*1e3/IQSR); //ms 335 | 336 | 337 | FSKSyncStatus=0; // Error in Manchester 338 | //IndexData=0; 339 | ManchesterAdd(-1); 340 | 341 | return(2); 342 | 343 | } 344 | 345 | 346 | } 347 | 348 | } 349 | else 350 | ManchesterAdd(-1); 351 | 352 | //if(FSKSyncStatus!=1) 353 | { 354 | int InTimeSync=GetFSKSync(Sym[i]); 355 | if(FSKSyncStatus==0) 356 | { 357 | switch(InTimeSync) 358 | { 359 | case FSK_SYNC_ON: FSKSyncStatus=1; IndexData=0;break; 360 | case FSK_SYNC_OFF:FSKSyncStatus=0;break; 361 | } 362 | } 363 | } 364 | } 365 | 366 | 367 | 368 | 369 | return 1; 370 | 371 | } 372 | else 373 | return 0; 374 | 375 | } 376 | 377 | //*************************************************************************************************** 378 | //*********************************** TX FUNCTIONS ************************************************** 379 | //*************************************************************************************************** 380 | 381 | int RFModem::Transmit(unsigned char *Frame,unsigned int Length,bool ShortPacket) 382 | { 383 | if(Length>MAXPACKETLENGTH) return -1; 384 | TxSymbolsSize=0; 385 | StatusModem=Status_Transmit; 386 | WriteSync(ShortPacket); 387 | for(int i=0;iMAX_SYMBOLS) 399 | { 400 | printf("\n Tx Overflow :%d\n",TxSymbolsSize); 401 | TxSymbolsSize=0; 402 | } 403 | 404 | } 405 | 406 | 407 | 408 | void RFModem::WriteByteManchester(unsigned char Byte,char flip) 409 | { 410 | unsigned char ByteFlip; 411 | if(flip==1) ByteFlip=Byte^0xFF; else ByteFlip=Byte; 412 | //printf("%x",ByteFlip); 413 | for(int i=7;i>=0;i--) 414 | { 415 | if(((ByteFlip>>i)&0x1)==0) 416 | { 417 | WriteFSKIQ(0); 418 | WriteFSKIQ(1); 419 | } 420 | else 421 | { 422 | WriteFSKIQ(1); 423 | WriteFSKIQ(0); 424 | } 425 | } 426 | } 427 | 428 | void RFModem::WriteSync(bool ShortPacket) 429 | { 430 | //TxSymbolsSize=0; // Should alread by reset by last sending 431 | if(TxSymbolsSize!=0) printf("Tx overflow ????\n"); 432 | int NbPreamble=0; 433 | if(ShortPacket) 434 | NbPreamble=100; 435 | else 436 | NbPreamble=100; 437 | for(int i=0;iSetSymbols(TxSymbols,TxSymbolsSize); 459 | 460 | StatusModem=Status_Receive; 461 | 462 | } 463 | 464 | 465 | -------------------------------------------------------------------------------- /RFModem.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _RFMODEM 3 | #define _RFMODEM 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using std::complex; 13 | #include 14 | #include "./librpitx/src/librpitx.h" 15 | 16 | #define MAX_BYTE_PER_PACKET (31+6) 17 | #define MAXPACKETLENGTH MAX_BYTE_PER_PACKET 18 | 19 | static sem_t sem_receive; 20 | static sem_t sem_tx; 21 | 22 | class RFModem { 23 | 24 | private: 25 | 26 | static void *ReadSDR(void * arg); 27 | static void *WriteSDR(void * arg); 28 | fskburst *fskmod=NULL; 29 | //Common 30 | int StatusModem=Status_Idle; 31 | 32 | //Rx 33 | uint8_t* iq_buffer; // 1Byte I, 1Byte Q 34 | 35 | liquid_float_complex *buf_rx; 36 | 37 | nco_crcf MyNCO; 38 | msresamp2_crcf MyDecim; 39 | freqdem fdem; 40 | FILE* iqfilein=NULL; 41 | unsigned int ReceiveSampleBySymbol=0; 42 | unsigned char BufferData[MAXPACKETLENGTH]; 43 | int IndexData=0; 44 | bool FrameIsPresent=0; 45 | 46 | pthread_t thReadSDR; // Thread read in RTLSDR 47 | 48 | 49 | //Tx 50 | 51 | 52 | #define MAX_SYMBOLS (MAX_BYTE_PER_PACKET+200+50)*8*2 53 | unsigned char TxSymbols[MAX_SYMBOLS]; // 8bits*2(MANCHESTER) 54 | int TxSymbolsSize=0; 55 | 56 | liquid_float_complex buf_tx[MAX_SYMBOLS*8]; //8 samples by symbol 57 | int buf_tx_len=0; 58 | 59 | #define RPITX_BURST_SIZE 1000 60 | liquid_float_complex dummy_tx[RPITX_BURST_SIZE]; 61 | 62 | pthread_mutex_t muttx = PTHREAD_MUTEX_INITIALIZER; 63 | pthread_t thWriteSDR; // Thread read in RTLSDR 64 | 65 | 66 | private: 67 | void InitRF(); 68 | int AddData(unsigned char DataValue); 69 | int ManchesterAdd(int BitValue); 70 | int GetFSKSync(unsigned char Sym); 71 | 72 | 73 | void WriteFSKIQ(unsigned char bit); 74 | void WriteByteManchester(unsigned char Byte,char flip); 75 | void WriteSync(bool ShortPacket); 76 | void WriteEnd(); 77 | 78 | public: 79 | RFModem(); 80 | ~RFModem(); 81 | int ProcessRF(); // Only public for thread 82 | int SetIQFile(char *IQFileName,int Direction); 83 | int Receive(unsigned char *Frame,int Timeoutms); 84 | int Transmit(unsigned char *Frame,unsigned int Length,bool ShortPacket); 85 | enum {Status_Idle,Status_Receive,Status_Transmit}; 86 | int SetStatus(int Status); 87 | 88 | }; 89 | #endif 90 | -------------------------------------------------------------------------------- /SubMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "SubMessage.h" 2 | #include 3 | #include 4 | 5 | SubMessage::SubMessage() 6 | { 7 | 8 | } 9 | 10 | SubMessage::SubMessage(Message *messagein) 11 | { 12 | AttachToMessage(messagein); 13 | } 14 | 15 | SubMessage::~SubMessage() 16 | { 17 | } 18 | 19 | void SubMessage::AttachToMessage(Message *messagein) 20 | { 21 | message=messagein; 22 | } 23 | 24 | int SubMessage::AddToMessage() 25 | { 26 | message->AddToBody(&Type,1); 27 | message->AddToBody(&Len,1); 28 | message->AddToBody(Body,Len); 29 | return 0; 30 | } 31 | 32 | void SubMessage::PrintState() 33 | { 34 | fprintf(stderr,"SubMsg Layer:"); 35 | switch(message->Source) 36 | { 37 | case PDM:fprintf(stderr,"PDM ");break; 38 | case POD:fprintf(stderr,"POD ");break; 39 | 40 | default:fprintf(stderr,"UNKOWN ");break; 41 | } 42 | fprintf(stderr,"Type:%02x ",Type); 43 | fprintf(stderr,"Len:%d ",Len); 44 | for(int i=0;i 3 | #include 4 | 5 | //*************************************DATA DEFINITION AND CRC*********************************************** 6 | unsigned int nonce_table16[] = {0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011,0x8033, 7 | 0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022,0x8063,0x0066, 8 | 0x006c,0x8069,0x0078,0x807d,0x8077,0x0072,0x0050,0x8055,0x805f, 9 | 0x005a,0x804b,0x004e,0x0044,0x8041,0x80c3,0x00c6,0x00cc,0x80c9, 10 | 0x00d8,0x80dd,0x80d7,0x00d2,0x00f0,0x80f5,0x80ff,0x00fa,0x80eb, 11 | 0x00ee,0x00e4,0x80e1,0x00a0,0x80a5,0x80af,0x00aa,0x80bb,0x00be, 12 | 0x00b4,0x80b1,0x8093,0x0096,0x009c,0x8099,0x0088,0x808d,0x8087, 13 | 0x0082,0x8183,0x0186,0x018c,0x8189,0x0198,0x819d,0x8197,0x0192, 14 | 0x01b0,0x81b5,0x81bf,0x01ba,0x81ab,0x01ae,0x01a4,0x81a1,0x01e0, 15 | 0x81e5,0x81ef,0x01ea,0x81fb,0x01fe,0x01f4,0x81f1,0x81d3,0x01d6, 16 | 0x01dc,0x81d9,0x01c8,0x81cd,0x81c7,0x01c2,0x0140,0x8145,0x814f, 17 | 0x014a,0x815b,0x015e,0x0154,0x8151,0x8173,0x0176,0x017c,0x8179, 18 | 0x0168,0x816d,0x8167,0x0162,0x8123,0x0126,0x012c,0x8129,0x0138, 19 | 0x813d,0x8137,0x0132,0x0110,0x8115,0x811f,0x011a,0x810b,0x010e, 20 | 0x0104,0x8101,0x8303,0x0306,0x030c,0x8309,0x0318,0x831d,0x8317, 21 | 0x0312,0x0330,0x8335,0x833f,0x033a,0x832b,0x032e,0x0324,0x8321, 22 | 0x0360,0x8365,0x836f,0x036a,0x837b,0x037e,0x0374,0x8371,0x8353, 23 | 0x0356,0x035c,0x8359,0x0348,0x834d,0x8347,0x0342,0x03c0,0x83c5, 24 | 0x83cf,0x03ca,0x83db,0x03de,0x03d4,0x83d1,0x83f3,0x03f6,0x03fc, 25 | 0x83f9,0x03e8,0x83ed,0x83e7,0x03e2,0x83a3,0x03a6,0x03ac,0x83a9, 26 | 0x03b8,0x83bd,0x83b7,0x03b2,0x0390,0x8395,0x839f,0x039a,0x838b, 27 | 0x038e,0x0384,0x8381,0x0280,0x8285,0x828f,0x028a,0x829b,0x029e, 28 | 0x0294,0x8291,0x82b3,0x02b6,0x02bc,0x82b9,0x02a8,0x82ad,0x82a7, 29 | 0x02a2,0x82e3,0x02e6,0x02ec,0x82e9,0x02f8,0x82fd,0x82f7,0x02f2, 30 | 0x02d0,0x82d5,0x82df,0x02da,0x82cb,0x02ce,0x02c4,0x82c1,0x8243, 31 | 0x0246,0x024c,0x8249,0x0258,0x825d,0x8257,0x0252,0x0270,0x8275, 32 | 0x827f,0x027a,0x826b,0x026e,0x0264,0x8261,0x0220,0x8225,0x822f, 33 | 0x022a,0x823b,0x023e,0x0234,0x8231,0x8213,0x0216,0x021c,0x8219, 34 | 0x0208,0x820d,0x8207,0x0202}; 35 | 36 | SubMessageSeed::SubMessageSeed() 37 | { 38 | 39 | } 40 | 41 | void SubMessageSeed::SetLotTid(unsigned long TheLot,unsigned long TheTid) 42 | { 43 | Lot=TheLot; 44 | Tid=TheTid; 45 | } 46 | 47 | void SubMessageSeed::SetFromSubMessage(SubMessage *submessage_in,int SeqMessage) 48 | { 49 | SeqMessagePOD=SeqMessage; 50 | submessage.Len=submessage_in->Len; 51 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 52 | } 53 | 54 | 55 | int SubMessageSeed::InterpertSubmessage() 56 | { 57 | 58 | 59 | if(submessage.Len==3) 60 | { 61 | Type=submessage.Body[0]; 62 | 63 | if(Type==0x14) // Sync Seed 64 | { 65 | unsigned int Crc=0; 66 | if(SeqMessagePOD==0) SeqMessagePOD=16; // PDM request is seq 15 67 | Crc=nonce_table16[SeqMessagePOD-1];//Index-1 ??? Byte FA is byte1 -> This is the SequenceMessage from the PDM (means actual POD seq-1) 68 | unsigned int Result=((unsigned int)(submessage.Body[1])<<8)|submessage.Body[2]; 69 | unsigned int LotTid=(unsigned int)(Lot&0xFFFF)+(unsigned int)(Tid&0xFFFF); 70 | //fprintf(stderr,"Seed request with seq=%d : \n",SeqMessagePOD); 71 | for(int SearchSeed=0;SearchSeed<128;SearchSeed++) 72 | { 73 | if(((LotTid+Crc+0x72AA)&0xFFFF)==(Result^SearchSeed)) //Fixme 0x72AA is unique fake nounce generated by PDM 74 | { 75 | Seed=SearchSeed; 76 | return 0; // Found the new Seed 77 | } 78 | 79 | } 80 | } 81 | else 82 | fprintf(stderr,"Unknown Seed Type\n"); 83 | 84 | 85 | } 86 | else 87 | { 88 | printf("SubMessageSeed incorrect len:%d\n",submessage.Len); 89 | return -1; 90 | } 91 | return -1; 92 | 93 | } 94 | 95 | int SubMessageSeed::PrintState() 96 | { 97 | fprintf(stderr,"LotId %ld Tid %ld Seed = %d \n",Lot,Tid,Seed); 98 | return 0; 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /SubMessageSeed.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SUBMESSAGESEED 3 | #define _SUBMESSAGESEED 4 | 5 | #include "SubMessage.h" 6 | 7 | class SubMessageSeed 8 | { 9 | private: 10 | 11 | SubMessage submessage; 12 | int Type=0; 13 | unsigned long Tid=0; 14 | unsigned long Lot=0; 15 | public: 16 | int Seed; 17 | int SeqMessagePOD; 18 | 19 | SubMessageSeed(); 20 | void SetLotTid(unsigned long TheLot,unsigned long TheTid); 21 | void SetFromSubMessage(SubMessage *submessage_in,int SeqMessagePOD); 22 | int InterpertSubmessage(); 23 | int PrintState(); 24 | }; 25 | #endif 26 | -------------------------------------------------------------------------------- /SubMessageStatus.cpp: -------------------------------------------------------------------------------- 1 | #include "SubMessageStatus.h" 2 | #include 3 | #include 4 | 5 | 6 | SubMessageStatus::SubMessageStatus() 7 | { 8 | 9 | } 10 | 11 | void SubMessageStatus::SetFromSubMessage(SubMessage *submessage_in) 12 | { 13 | submessage.Len=submessage_in->Len; 14 | memcpy(submessage.Body,submessage_in->Body,submessage.Len); 15 | } 16 | 17 | 18 | int SubMessageStatus::InterpertSubmessage() 19 | { 20 | 21 | 22 | if(submessage.Len>=9) 23 | { 24 | 25 | InsulinState=submessage.Body[0]>>4; 26 | PoDState=submessage.Body[0]&0xF; 27 | TotalUnit=((submessage.Body[1]&0xF)<<9)|(submessage.Body[2]<<1)|(submessage.Body[3]>>7); 28 | LastCommandMsgSeq=(submessage.Body[3]>>3)&0xF; 29 | InsulinNotDelivered=((submessage.Body[3]&0x3)<<8)|submessage.Body[4]; 30 | Alarm=((submessage.Body[5]&0x7F)<<1)|(submessage.Body[6]>>7); 31 | MinutesActive=((submessage.Body[6]&0x7F)<<6)|((submessage.Body[7]>>2)&0x3F); 32 | ReservoirLevel=(((submessage.Body[7]&0x03)<<8)+(submessage.Body[8])); 33 | } 34 | else 35 | { 36 | printf("Len <9:%d\n",submessage.Len); 37 | return -1; 38 | } 39 | return 0; 40 | 41 | } 42 | 43 | int SubMessageStatus::PrintState() 44 | { 45 | switch(InsulinState) 46 | { 47 | case 0:printf("Insulin stopped");break; 48 | case 1:printf("Basal running");break; 49 | case 2:printf("Temp Basal running");break; 50 | case 4:printf("Purgin");break; 51 | case 5:printf("Bolusing");break; 52 | case 6:printf("Bolusing+Tempbasal");break; 53 | default:printf("Unknown %x",InsulinState);break; 54 | } 55 | printf(" "); 56 | 57 | printf("PODState:"); 58 | 59 | switch(PoDState) 60 | { 61 | case 3:printf("Pairing success");break; 62 | case 4:printf("Purging");break; 63 | case 5:printf("Ready for injection");break; 64 | case 6:printf("Injection done");break; 65 | case 8:printf("Normal running");break; 66 | case 9:printf("Running with low insulin");break; 67 | case 15:printf("Inactive");break; 68 | default:printf("Unknown %d",PoDState); 69 | 70 | }; 71 | printf(" "); 72 | 73 | 74 | printf("Insulin(total):%0.2fu ",TotalUnit*0.05); 75 | 76 | 77 | printf("PODMsg#%d ",LastCommandMsgSeq); 78 | 79 | printf("Insulin not delivered:%0.2fu",InsulinNotDelivered*0.05); 80 | printf(" "); 81 | 82 | printf("Alarm:"); 83 | 84 | 85 | switch(Alarm) 86 | { 87 | case 0x8:printf("Perim soon");break; 88 | case 0x80:printf("Replace POD");break; 89 | case 0x82:printf("Replace PODEx");break; 90 | case 0x20:printf("End of cancel insulin in 15 minutes");break; //beep 91 | case 0x40:printf("End of cancel insulin now");break; //beep beeeeep beep beeeeeep 92 | case 0:printf("Normal");break; 93 | default:printf("Unknown x%x",Alarm);break; 94 | } 95 | printf(" "); 96 | 97 | 98 | int Days=MinutesActive/60/24; 99 | int Hours=(MinutesActive-Days*60*24)/60; 100 | int Minutes=(MinutesActive-Days*60*24-Hours*60); 101 | printf("POD Active for %d days %d hours %d minutes",Days,Hours,Minutes);printf(" ");//7+6 102 | 103 | if((ReservoirLevel&0xFF)!=0xFF) 104 | printf("Reservoir Level %0.01fU",(ReservoirLevel)*50.0/1024.0); 105 | else 106 | printf("Reservoir Level over 50U"); 107 | printf("\n"); 108 | return 0; 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /SubMessageStatus.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SUBMESSAGESTATUS 3 | #define _SUBMESSAGESTATUS 4 | 5 | #define MAX_BYTE_SUBMSG_BODY 255 6 | #include "SubMessage.h" 7 | 8 | class SubMessageStatus 9 | { 10 | private: 11 | 12 | SubMessage submessage; 13 | public: 14 | int InsulinState; 15 | int PoDState; 16 | int TotalUnit; 17 | int LastCommandMsgSeq; 18 | int InsulinNotDelivered; 19 | int Alarm; 20 | int MinutesActive; 21 | int ReservoirLevel; 22 | 23 | SubMessageStatus(); 24 | void SetFromSubMessage(SubMessage *submessage_in); 25 | int InterpertSubmessage(); 26 | int PrintState(); 27 | }; 28 | #endif 29 | -------------------------------------------------------------------------------- /records/pairing.sh: -------------------------------------------------------------------------------- 1 | rm fifo.cu8 mkfifo fifo.cu8 rm FSK.ft mkfifo FSK.ft 2 | 3 | 4 | rtl_sdr -g 30 -f 434248000 -s 1300000 fifo.cu8 & 5 | #sudo ../rpitx/rpitx -m IQ -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 & 6 | #sudo perf record -e sched:sched_stat_sleep -e sched:sched_switch -e cpu-clock,faults ../rpitx/rpitx -m IQFLOAT -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 & 7 | sudo /home/pi/rpitx/rpitx -m IQFLOAT -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 -d 100 & 8 | #../rtlomniv2 -i fifo.cu8 -m tx -a 1f108958 -p 8 -n 1 -l 42335 -t 650610 9 | ../rtlomniv2 -i fifo.cu8 -m tx -a 1f108958 -p 0 -n 0 -l 43262 -t 580058 10 | 11 | #./rtlomni -i fifo.cu8 -m tx -a 1f108958 -t 650610 -l 42335 -n 0 -p 0 -c 12 | 13 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 0 -p 0 -c 14 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 3 -p 3 -c 15 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 5 -p 8 -c 16 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 7 -p 11 -c 17 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 9 -p 13 -c 18 | -------------------------------------------------------------------------------- /records/rcv.sh: -------------------------------------------------------------------------------- 1 | mkfifo fifo.cu8 2 | rtl_sdr -g 30 -f 434248000 -s 1300000 fifo.cu8 & 3 | ../rtlomniv2 -i fifo.cu8 -l 43262 -t 560069 4 | 5 | -------------------------------------------------------------------------------- /records/tx.sh: -------------------------------------------------------------------------------- 1 | rm fifo.cu8 2 | mkfifo fifo.cu8 3 | 4 | 5 | rtl_sdr -g 30 -f 434248000 -s 1300000 fifo.cu8 & 6 | #sudo ../rpitx/rpitx -m IQ -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 & 7 | #sudo perf record -e sched:sched_stat_sleep -e sched:sched_switch -e cpu-clock,faults ../rpitx/rpitx -m IQFLOAT -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 & 8 | #sudo /home/pi/rpitx/rpitx -m IQFLOAT -i FSK.ft -f 433916 -s 325000 -c 1 -a 14 -d 100 & 9 | sudo ../rtlomniv2 -i fifo.cu8 -m tx -a 1f10895a -n 15 -l 43262 -t 560069 10 | 11 | #./rtlomni -i fifo.cu8 -m tx -a 1f108958 -t 650610 -l 42335 -n 0 -p 0 -c 12 | 13 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 0 -p 0 -c 14 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 3 -p 3 -c 15 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 5 -p 8 -c 16 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 7 -p 11 -c 17 | #./rtlomni -i fifo.cu8 -m tx -a 1f10895a -t 650610 -l 42335 -n 9 -p 13 -c 18 | -------------------------------------------------------------------------------- /rtlomniv2.cpp: -------------------------------------------------------------------------------- 1 | /* Created by Evariste Courjaud F5OEO (2017-2018). Code is GPL v2 2 | rtlomni is a software to sniff RF packets using a RTLSDR dongle in order to analysis Omnipod protocol. 3 | 4 | Credits : 5 | 6 | This work is mainly based on https://github.com/ps2/omnipod_rf 7 | 8 | Hope this could help and contribute to https://github.com/openaps/openomni 9 | 10 | SDR demodulation and signal processing is based on excellent https://github.com/jgaeddert/liquid-dsp/ 11 | 12 | Licence : 13 | 14 | This program is free software: you can redistribute it and/or modify 15 | it under the terms of the GNU General Public License as published by 16 | the Free Software Foundation, either version 2 of the License, or 17 | (at your option) any later version. 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | You should have received a copy of the GNU General Public License 23 | along with this program. If not, see . 24 | */ 25 | 26 | 27 | 28 | #include "RFModem.h" 29 | //#include "Packet.h" 30 | #include "PacketHandler.h" 31 | #include "Message.h" 32 | #include "MessageHandler.h" 33 | 34 | #include 35 | #include 36 | 37 | 38 | #define PROGRAM_VERSION "0.0.2" 39 | 40 | void print_usage() 41 | { 42 | 43 | fprintf(stderr,\ 44 | "rtlomni (%s)\n\ 45 | Usage:rtlomniv2 -i File [-l LotID] [-t Tid][-c][-m Mode][-a Address][-n Msg sequence][-p PacketSeq][-h] \n\ 46 | -i Input File (RF type(.cu8) or RFTrace from RfCat \n\ 47 | -l LotID \n\ 48 | -t Tide \n\ 49 | -c Colorize messages \n\ 50 | -d Write copy of input RF packet(debug.cu8) \n\ 51 | -m Mode {tx,rx} (rx by default) \n\ 52 | -a Physical POD address in Hexa \n\ 53 | -n Message Sequence Number to start with \n\ 54 | -p Packet Sequence Number to start with \n\ 55 | -h help (print this help).\n\ 56 | Example : ./rtlomni -i omniup325.cu8 for reading a capture file from rtlsdr\n\ 57 | Example : ./rtlomni -i badcrc.txt for reading a capture file from rfcat\n\ 58 | \n", \ 59 | PROGRAM_VERSION); 60 | 61 | } /* end function print_usage */ 62 | 63 | int main(int argc, char **argv) 64 | { 65 | int a; 66 | int anyargs = 0; 67 | char inputname[255]; 68 | char outputname[255]="FSK.ft"; 69 | bool Monitoring=1; 70 | int MessageSeqStart=0; 71 | int PacketSeqStart=0; 72 | unsigned long PhysicalPodAddress; 73 | unsigned long mlot=0; 74 | unsigned mtid=0; 75 | while (1) 76 | { 77 | a = getopt(argc, argv, "i:l:t:cdm:a:n:p:h"); 78 | 79 | if (a == -1) 80 | { 81 | if (anyargs) break; 82 | else a = 'h'; //print usage and exit 83 | } 84 | anyargs = 1; 85 | 86 | switch (a) 87 | { 88 | case 'i': // InputFile 89 | strcpy(inputname,optarg); 90 | break; 91 | case 'm': // Mode Tx ou Rx 92 | if(strcmp(optarg,"tx")==0) Monitoring=false; 93 | break; 94 | case 'l': // Lot 95 | mlot=atol(optarg); 96 | break; 97 | case 't': // Tid 98 | mtid=atol(optarg); 99 | break; 100 | /* 101 | case 'c': // Colorize message 102 | colorize=1; 103 | break; 104 | case 'd': // Debug mode : recording I/Q 105 | debugfileiq=1; 106 | break; 107 | */ 108 | case 'a': // Physical Adress (need for Tx) 109 | { 110 | char *p; 111 | PhysicalPodAddress=strtoul(optarg, &p, 16); 112 | } 113 | break; 114 | case 'n': // Message sequence 115 | MessageSeqStart=atoi(optarg); 116 | break; 117 | case 'p': // Packet Sequence 118 | PacketSeqStart=atoi(optarg); 119 | break; 120 | 121 | case 'h': // help 122 | print_usage(); 123 | exit(0); 124 | break; 125 | case -1: 126 | break; 127 | case '?': 128 | if (isprint(optopt)) 129 | { 130 | fprintf(stderr, "rtlomni `-%c'.\n", optopt); 131 | } 132 | else 133 | { 134 | fprintf(stderr, "rtlomni: unknown option character `\\x%x'.\n", optopt); 135 | } 136 | print_usage(); 137 | 138 | exit(1); 139 | break; 140 | default: 141 | print_usage(); 142 | exit(1); 143 | break; 144 | }/* end switch a */ 145 | }/* end while getopt() */ 146 | 147 | RFModem Modem; 148 | Modem.SetIQFile(inputname,0); 149 | if(!Monitoring) 150 | { 151 | Modem.SetIQFile(outputname,1); 152 | } 153 | unsigned char Frame[MAX_BYTE_PER_PACKET]; 154 | 155 | //Message message; 156 | //PacketHandler packethandler(&Modem,Monitoring); 157 | 158 | MessageHandler messagehandler(&Modem,Monitoring); 159 | messagehandler.ID1=PhysicalPodAddress; 160 | messagehandler.ID2=PhysicalPodAddress; 161 | messagehandler.SetMessageSequence(MessageSeqStart); 162 | messagehandler.packethandler.Sequence=PacketSeqStart; 163 | messagehandler.SetLotTid(mlot,mtid); 164 | if(Monitoring) 165 | { 166 | while(1) 167 | { 168 | messagehandler.WaitForNextMessage(); 169 | 170 | } 171 | } 172 | else 173 | { 174 | 175 | if(messagehandler.GetPodState(0x46)==-1) {fprintf(stderr,"Get State");exit(0);}; 176 | 177 | //messagehandler.Bolus(0.1); 178 | //sleep(20); 179 | //messagehandler.GetPodState(0x46); 180 | // **************  THE COMPLETE PAIRING PROCESS ***************** 181 | 182 | //messagehandler.ID1=0xFFFFFFFF; 183 | //messagehandler.ID2=0xFFFFFFFF; 184 | 185 | 186 | /* while(messagehandler.Pairing(PhysicalPodAddress)==-1) 187 | { 188 | 189 | 190 | } 191 | 192 | //if(messagehandler.VerifyPairing(PhysicalPodAddress)==-1) {fprintf(stderr,"VerifyPairing Failed");exit(0);} //Lot ID seems not correct : fixme ! 193 | if(messagehandler.GetPodState(0x0)==-1) {fprintf(stderr,"Get State");exit(0);}; 194 | 195 | // if(messagehandler.FinishPairing(PhysicalPodAddress)==-1) {fprintf(stderr,"FinishPairing Failed");exit(0);} ; 196 | if(messagehandler.FinishPairing2(PhysicalPodAddress)==-1) {fprintf(stderr,"FinishPairing2 Failed");exit(0);} ; 197 | sleep(1); 198 | if(messagehandler.Purging()==-1) {fprintf(stderr,"Purging Failed");exit(0);} 199 | sleep(60); 200 | 201 | if(messagehandler.FinishPurging()==-1) {fprintf(stderr,"FinishPurging Failed");exit(0);} 202 | //Ready for injection 203 | if(messagehandler.BeginInjection()==-1) {fprintf(stderr,"BeginInjection Failed");exit(0);} 204 | sleep(30); 205 | 206 | if(messagehandler.FinishInjection()==-1) {fprintf(stderr,"FinishInjection Failed");exit(0);} 207 | if(messagehandler.FinishInjection2()==-1) {fprintf(stderr,"FinishInjection Failed");exit(0);} 208 | sleep(5); 209 | messagehandler.GetPodState(0); 210 | */ 211 | while(1) 212 | { 213 | messagehandler.WaitForNextMessage(); 214 | 215 | } 216 | 217 | }; 218 | 219 | } 220 | --------------------------------------------------------------------------------