Advertisement
dess2000

Untitled

Apr 20th, 2018
474
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.71 KB | None | 0 0
  1. #include <due_can.h>
  2.  
  3. /*
  4.  * Data structure to hold the commands to send to the CANBUS
  5.  */
  6. struct Command{
  7.   String theCommand;
  8.   String description;
  9.   CAN_FRAME canFrame;
  10.   uint8_t timesToSend;//how many times to send the command
  11.   uint16_t delayBetweenSends; //delay in miliseconds between sends
  12.   String commandAfter;//if we want to send another command right away, list it here
  13.  
  14.   //Constructor
  15.   Command(String cCMD, String cDescription, uint32_t cID, uint8_t cExtended, uint8_t cLength,
  16.           uint8_t cD0, uint8_t cD1, uint8_t cD2, uint8_t cD3, uint8_t cD4, uint8_t cD5, uint8_t cD6, uint8_t cD7,
  17.           uint8_t cTTS, uint16_t cDelay,String cCommandAfter){
  18.     theCommand = cCMD;
  19.     description = cDescription;
  20.     canFrame.id = cID;
  21.     canFrame.extended = cExtended;
  22.     canFrame.length = cLength;
  23.     canFrame.data.byte[0] = cD0;
  24.     canFrame.data.byte[1] = cD1;
  25.     canFrame.data.byte[2] = cD2;
  26.     canFrame.data.byte[3] = cD3;
  27.     canFrame.data.byte[4] = cD4;
  28.     canFrame.data.byte[5] = cD5;
  29.     canFrame.data.byte[6] = cD6;
  30.     canFrame.data.byte[7] = cD7;
  31.     timesToSend = cTTS;
  32.     delayBetweenSends = cDelay;
  33.     commandAfter = cCommandAfter;
  34.   }
  35. };
  36.  
  37. /*
  38.  * Bunch of data structures to hold the various frames sent to/from the xbee cell modem
  39.  * This isn't all of them, just the ones I'm using.
  40.  */
  41.  
  42. typedef struct{
  43. /*
  44.  * TX SMS Frame      BYTE
  45.  * Start Delimiter | 1   | 0x7E
  46.  * Length          | 2-3 |
  47.  * Frame Type      | 4   | 0x1F for TX SMS
  48.  * Frame ID        | 5   | Reference identifier used to match status responses. 0 disables the TX Status frame.
  49.  * Options         | 6   | "Reserved for future use."
  50.  * Phone Number    | 7-27| 20 bytes
  51.  * Message         | 28-n| 160 max for SMS
  52.  * Checksum        | n-1 |
  53.  */
  54.   const uint8_t startDelimiter = 0x7E;
  55.   uint8_t frameLengthLow = 0;
  56.   uint8_t frameLengthHigh= 0;
  57.   const uint8_t frameType = 0x1F;
  58.   uint8_t frameID = 0;//Reference identifier used to match status responses. 0 disables the TX Status frame.
  59.   const uint8_t options = 0;//"reserved for future use."
  60.   char phoneNumber[20] = {};
  61.   char payload[160] = {};
  62.   uint8_t checksum = 0;
  63. } frameTX_SMS;
  64.  
  65. //Transmit (TX) Status - 0x89
  66. //Indicates the success or failure of a transmit operation.
  67. typedef struct{
  68.   const uint8_t frameType = 0x89;
  69.   uint8_t frameID = 0;//Refers to the frame ID specified in a previous transmit frame
  70.   uint8_t status;
  71. /*
  72.  * Code  Description
  73.  * 0x00   Successful transmit
  74.  * 0x21  Failure to transmit to cell network
  75.  * 0x22  Not registered to cell network
  76.  * 0x2c  Invalid frame values (check the phone number)
  77.  * 0x31  Internal error
  78.  * 0x32  Resource error (retry operation later)
  79.  * 0x74  Message too long
  80.  * 0x78  Invalid UDP port
  81.  * 0x79  Invalid TCP port
  82.  * 0x7A  Invalid host address
  83.  * 0x7B  Invalid data mode
  84.  * 0x80  Connection refused
  85.  * 0x81  Socket connection lost
  86.  * 0x82  No server
  87.  * 0x83  Socket closed
  88.  * 0x84  Unknown server
  89.  * 0x85  Unknown error
  90.  */
  91. } frameTX_SMS_Status;
  92.  
  93. typedef struct{
  94.   const uint8_t frameType = 0x9F;
  95.   uint8_t phoneNumber[20] = {}
  96.   uint8_t payload[160] = {};//Body of the received SMS message.
  97. } frameRX_SMS;
  98.  
  99. typedef struct{
  100.   const uint8_t startDelimiter = 0x7E;
  101.   uint8_t frameLengthLow = 0;
  102.   uint8_t frameLengthHigh= 0;
  103.   uint8_t frameType = 0x08;
  104.   uint8_t frameID = 0x01;//Identifies the data frame for the host to correlate with a subsequent ACK. If set to 0, the device does not send a response.
  105.   uint8_t ATcommand[2];
  106.   uint8_t checksum = 0x00;
  107. } frameTX_AT_Command;
  108.  
  109. typedef struct{
  110.   const uint8_t frameType = 0x88;
  111.   uint8_t frameID = 0;//Identifies the data frame for the host to correlate with a subsequent ACK. If set to 0, the device does not send a response.
  112.   char ATcommand[2];//Command name: two ASCII characters that identify the AT command.
  113.   uint8_t status; //0x00 = OK, 0x01 = ERROR, 0x02=Invalid Command, 0x03=Invalid Parameter, 0x04=Tx Failure.
  114.   uint8_t parameterValue[256] = {};//Register data in binary format. If the register was set, then this field is not returned.
  115. } frameRX_AT_Command;
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122. //if you want to use the digi XCTU software, uncomment this
  123. //#define XCTU
  124.  
  125. #define DELAY 2 //delay when reading from the serial
  126.  
  127. #define redLED DS2
  128. #define grnLED DS6
  129.  
  130. //This made it easier to tell which serial I was writing to.
  131. #define digiSerial Serial
  132.  
  133. //SMS commands to the CANBUS will be this many characters only.
  134. #define CMDLENGTH 5
  135.  
  136. //cell number for M2 to send SMS
  137. //"Use numbers and the + symbol only, no other symbols or letters."
  138. const String MYCELL = "+14508088900";
  139.  
  140. /*
  141.  * An array of the Command struct I created. Contains the CAN_FRAME
  142.  * struct as well as a bunch of other info.
  143.  * These are all the commands that it would be possible to excute via SMS.
  144.  */
  145. const int numCommands = 4;
  146. Command cbCommands[numCommands] = {
  147.   Command("START", "Start Truck",  0x111,false,6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,4,1500,"RAOFF"),
  148.   Command("RAOFF", "Radio Off",    0x222,false,8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,1,10,""),
  149.   Command("HFULL", "Heat on full", 0x333,false,5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,1,1,""),
  150.   Command("CLOFF", "Climate Off",  0x444,false,5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,1,1,"")
  151.                                   };
  152.  
  153. void setup() {
  154.   //Initialize and turn on the LEDs until setup complete
  155.   for(int x=14;x<=18;x++){
  156.     pinMode(x,OUTPUT);
  157.     digitalWrite(x,LOW);
  158.   }
  159.  
  160.   digiSerial.begin(9600);          // Serial port for XBEE socket
  161.   SerialUSB.begin(9600);           // Native USB port
  162.  
  163.   pinMode(XBEE_MULT2, INPUT);      // DIGI Associate PIN
  164.   pinMode(XBEE_RST, OUTPUT);
  165.   digitalWrite(XBEE_RST, HIGH);    // Make sure RESET is HIGH
  166.  
  167.   Can0.begin(CAN_BPS_500K);
  168.  
  169.   //Setup complete, turn off the LEDs
  170.   for(int x=14;x<=18;x++){
  171.     digitalWrite(x,HIGH);
  172.   }
  173.   //leave the red LED on so I know there is power.
  174.   digitalWrite(DS2,LOW);
  175. }
  176.  
  177. /**
  178.  * Sends a CANBUS message.
  179.  *
  180.  * @param command The command to send of type Command
  181.  * @return nothing
  182.  */
  183. void txCANBUS(Command cmd){
  184.   char str[1];
  185.   String message = "";
  186.   for(unsigned int x=0;x<sizeof(cmd);x++){
  187.     sprintf(str,"%.2X",*((char *)(&cmd)+x));
  188.     message = message + str + " ";
  189.   }
  190.   SerialUSB.println(message);
  191.   for(int x=0;x<cmd.timesToSend;x++){
  192.     SerialUSB.print("Sending: ");SerialUSB.println(cmd.description);
  193. /***********
  194.  *This line sends the actual CANBUS message. Comment out as required.
  195.  ************/
  196. //    Can0.sendFrame(cmd.canFrame);
  197.     SerialUSB.print("Waiting (ms): ");SerialUSB.println(cmd.delayBetweenSends);
  198.     delay(cmd.delayBetweenSends);
  199.   }
  200.   if(cmd.commandAfter != ""){
  201.     //If the current command has a command to run right after
  202.     SerialUSB.print("Running right after: ");SerialUSB.println(cmd.commandAfter);
  203.     delay(1000);
  204.     txCANBUS(cbCommands[findCommandIndex(cmd.commandAfter)]);
  205.   }
  206. }
  207.  
  208. /**
  209.  * Finds the index of the given command in the global array of commands
  210.  *
  211.  * @param command The command name to find to find as type String.
  212.  * @return The index number when found. -1 for not found.
  213.  */
  214. int findCommandIndex(String str){
  215.   int index = -1;
  216.   for(int x=0;x<numCommands;x++){
  217.     if(cbCommands[x].theCommand == str){
  218.       index = x;
  219.       break;
  220.     }
  221.   }
  222.   return index;
  223. }
  224.  
  225. /*  
  226.  * Calculate the checksum for the digi xbee modem frames
  227.  *
  228.  * To calculate checksum of digi xbee frame:
  229.  * Add all bytes of the packet, except the start delimiter 0x7E and the length (the second and third bytes).
  230.  * Keep only the lowest 8 bits from the result.
  231.  * Subtract this quantity from 0xFF.
  232.  *
  233.  * @param frame A character array containing all the frame data
  234.  * @param length the length of the frame
  235.  */
  236. uint8_t calculateChecksum(char * frame, unsigned int l){
  237.   unsigned int total = 0;
  238.   //since I'm sending the whole frame, skip the first three bytes
  239.   for(unsigned int x=3;x<l+3;x++){
  240.     total += frame[x];
  241.   }
  242.   unsigned char low8bits = total & 0xFF;
  243.   char checksum = 0xFF - low8bits;
  244.   return checksum;
  245. }
  246.  
  247. /**
  248.  * Sends an SMS text message.
  249.  *
  250.  * @param message The text message to send
  251.  * @param messageLength The length of the message
  252.  * @param phoneNumber The phone number to send to
  253.  * @return nothing
  254.  */
  255. void txSMS(char * msg,int msgLength,String phoneNumber){
  256.   if(msgLength == 0){//no message
  257.     return;
  258.   }
  259.   frameTX_SMS frame;
  260.   //need to make sure phoneNumber isn't > 20
  261.   strcpy(frame.phoneNumber, phoneNumber.c_str());
  262.   //should verify this size too...
  263.   strcpy(frame.payload, msg);
  264.   frame.frameLengthHigh = 20 + msgLength + 1 + 1 + 1;//1 FrameType, 1 FrameID, 1 Options.
  265.   frame.checksum = calculateChecksum((char *)(&frame),frame.frameLengthHigh);
  266.   //Since SMS can be 160 characters and I read dynamically allocating memory in arduino should be avoided,
  267.   //the struct has an array of 160 chars initialized to 0x00. Put the checksum as the last "character" of that
  268.   //string so as not to TX 160 characters, mostly nulls, everytime.
  269.   frame.payload[strlen(frame.payload)] = frame.checksum;
  270.  
  271.   int frameTotalLength = 3 + frame.frameLengthHigh + 1;
  272. /***********
  273.  *This line sends the actual SMS message. Comment out as required.
  274.  ************/
  275. //  digiSerial.write((char*)(&frame), frameTotalLength); delay(100);
  276.  
  277.   //print out what's going on to the console
  278.   char str[1];
  279.   String message = "";
  280.   for(int x=0;x<frameTotalLength;x++){
  281.     sprintf(str,"%.2X",*((char *)(&frame)+x));
  282.     message = message + str + " ";
  283.   }
  284.   SerialUSB.print("\nTX SMS (HEX): ");
  285.   SerialUSB.println(message);
  286.   SerialUSB.println((char*)frame.phoneNumber);
  287.   frame.payload[strlen(frame.payload)-1] = 0x00;//remove the checksum before printing
  288.   SerialUSB.println((char*)frame.payload);
  289. }
  290.  
  291. void loop() {
  292.   while (SerialUSB.available()) {     // read from port 1, send to port 0:
  293.     int inByte = SerialUSB.read();
  294.     digiSerial.write(inByte);
  295.     delay(DELAY);
  296.   }
  297.  
  298.   if(digiSerial.available()){
  299. #ifdef XCTU
  300.     while (digiSerial.available()) {        // read from port 0, send to port 1:
  301.       char inByte = digiSerial.read();
  302.       SerialUSB.write(inByte);
  303.       delay(DELAY);
  304.     }
  305. #else
  306.     //Read the first byte. If it's not 0x7E, skip.
  307.     //All frames start with 0x7E
  308.     if(digiSerial.read() == 0x7E){
  309.       delay(DELAY);
  310.       //read the next 3 bytes of the header. 2 bytes for size and 1 for frame type
  311.       uint16_t lengthOfFrame;
  312.       lengthOfFrame = digiSerial.read(); delay(DELAY); //Size 1/2
  313.       lengthOfFrame <<= 8;
  314.       lengthOfFrame |= digiSerial.read(); delay(DELAY); //Size 2/2
  315.       byte frameType = digiSerial.read(); delay(DELAY); //Frame Type
  316.  
  317.       //What frame type are we dealing with?
  318.       if(frameType == 0x8A){//Modem Status
  319.         byte status   = digiSerial.read(); delay(DELAY); //status
  320.         digiSerial.read(); delay(DELAY); //read and discard the checksum.
  321.         String message = "Modem Status: ";
  322.         char str[2];
  323.         switch(status){
  324.           case 0x00: message += "0x00 - Hardware reset or power up";         break;
  325.           case 0x01: message += "0x01 - Watchdog timer reset";               break;
  326.           case 0x02: message += "0x02 - Registered with cellular network";   break;
  327.           case 0x03: message += "0x03 - Unregistered with cellular network"; break;
  328.           case 0x0E: message += "0x0E - Remote Manager connected";           break;
  329.           case 0x0F: message += "0x0F - Remote Manager disconnected";        break;
  330.           default:   message += "Unknown Modem Status Value: ";
  331.                      sprintf(str,"0x%.2X",status);
  332.                      message+= str;
  333.         }
  334.         SerialUSB.println(message);
  335.       }else if(frameType == 0x89){//TX Status
  336.         //not sure what to do with this. Perhaps save to SD card log?
  337.         //When the frameID field of the TX_SMS frame is set to 0 (default), this status message
  338.         //will not even be generated.
  339.         frameTX_SMS_Status frame;
  340.         frame.frameID = digiSerial.read(); delay(DELAY);
  341.         frame.status  = digiSerial.read(); delay(DELAY);
  342.         digiSerial.read(); delay(DELAY); //read and discard the checksum.
  343.       }else if(frameType == 0x88){ //AT Command Response - 0x88
  344.         frameRX_AT_Command frame;
  345.         frame.frameID = digiSerial.read(); delay(DELAY);
  346.         frame.ATcommand[0] = digiSerial.read(); delay(DELAY);
  347.         frame.ATcommand[1] = digiSerial.read(); delay(DELAY);
  348.         frame.status = digiSerial.read(); delay(DELAY);
  349.  
  350.         //next read in the data
  351.         int payloadLength = lengthOfFrame - 1 - 1 - 2 - 1;//1 FrameType, 1 FrameID, 2 AT command, 1 status
  352.         for(int x=0;x<payloadLength;x++){
  353.           frame.parameterValue[x] = digiSerial.read(); delay(DELAY);
  354.         }
  355.         byte checksum = digiSerial.read(); delay(DELAY);
  356.  
  357.         //Print the frame out to the console.
  358.         char str[1];
  359.         String message = "7E ";
  360.         sprintf(str,"%.2X",lengthOfFrame & 0xFF00);
  361.         message = message + str + " ";
  362.         sprintf(str,"%.2X",lengthOfFrame & 0x00FF);
  363.         message = message + str + " ";
  364.         for(int x=0;x<lengthOfFrame;x++){
  365.           sprintf(str,"%.2X",*((char *)(&frame)+x));
  366.           message = message + str + " ";
  367.         }
  368.         sprintf(str,"%.2X",checksum);
  369.         message += str;
  370.         SerialUSB.println("\nAT Command Response");
  371.         SerialUSB.println(message);
  372.         SerialUSB.print("AT ");
  373.         SerialUSB.write(frame.ATcommand[0]);
  374.         SerialUSB.write(frame.ATcommand[1]);
  375.         SerialUSB.print(" response from modem: ");
  376.         SerialUSB.println((char*)frame.parameterValue);
  377.  
  378.         //Send the reply out as SMS
  379.         SerialUSB.println("\nForwarding AT reply out by SMS");
  380.         txSMS((char*)frame.parameterValue,strlen((char*)frame.parameterValue),MYCELL);
  381.       }else if(frameType == 0x9F){//RX SMS
  382.         frameRX_SMS frame;
  383.         //read in the phone number. 20 bytes.
  384.         for(int x=0;x<20;x++){
  385.           frame.phoneNumber[x] = digiSerial.read(); delay(DELAY);
  386.         }
  387.         //next read in the data
  388.         int payloadLength = lengthOfFrame - 1 - 20;//1 for frame type, 20 for PH.
  389.         for(int x=0;x<payloadLength;x++){
  390.           frame.payload[x] = digiSerial.read(); delay(DELAY);
  391.         }
  392.         //lastly read in the checksum. I'm going to wrongly assume all the frames are good to go
  393.         //because I can't be bothered to write a verrify checksum function at the moment. But I
  394.         //think the cellular modem should reject it if the checksum is invalid.
  395.         byte checksum = digiSerial.read(); delay(DELAY);
  396.  
  397.         char str[1];
  398.         String message = "7E ";
  399.         sprintf(str,"%.2X",lengthOfFrame & 0xFF00);
  400.         message = message + str + " ";
  401.         sprintf(str,"%.2X",lengthOfFrame & 0x00FF);
  402.         message = message + str + " ";
  403.         for(int x=0;x<lengthOfFrame;x++){
  404.           sprintf(str,"%.2X",*((char *)(&frame)+x));
  405.           message = message + str + " ";
  406.         }
  407.         sprintf(str,"%.2X",checksum);
  408.         message += str;
  409.         SerialUSB.print("\nRX SMS: "); SerialUSB.println(message);
  410.         SerialUSB.print("From: ");     SerialUSB.println((char*)frame.phoneNumber);
  411.         SerialUSB.print("Message: ");  SerialUSB.println((char*)frame.payload);
  412.  
  413.         if(frame.payload[0] == 'D' && frame.payload[1] == 'S'){//toggle an LED
  414.           //no real practical use for this I suppose. Just helpful for testing.
  415.           //Send the pin name (ex DS2), take the 3rd character(ascii value), subtract 0x30, and add 12 to get the M2 board pindescription value.
  416.           byte led = frame.payload[2] - 0x30 + 12;
  417.           if(led >= 14 && led <= 18){
  418.             digitalWrite(led,((digitalRead(led) == HIGH) ? LOW : HIGH));
  419.           }
  420.         }else if(frame.payload[0] == 'A' && frame.payload[1] == 'T'){//send an AT command
  421.           frameTX_AT_Command ATframe;
  422.           unsigned short len = 4;//AT frames are 4 bytes
  423.           ATframe.frameLengthHigh = len & 0xFF;
  424.           len <<= 8;
  425.           ATframe.frameLengthLow =len & 0xFF;
  426.           ATframe.ATcommand[0] = frame.payload[2];
  427.           ATframe.ATcommand[1] = frame.payload[3];
  428.           ATframe.checksum = calculateChecksum((char*)(&ATframe),4);
  429.  
  430.           //length is 1 start delimiter, 2 size,
  431.           //1 frame type, 1 frame id, 2 AT command, 1 cksum.
  432.           //1 + 2 + 1 + 1 + 2 + 1 = 8
  433.           const int l = 8;
  434.           String message2 = "";
  435.           for(int x=0;x<l;x++){
  436.             sprintf(str,"%.2X",*((char *)(&ATframe)+x));
  437.             message2 = message2 + str + " ";
  438.           }
  439.           SerialUSB.print("\nAT ");SerialUSB.write(frame.payload[2]);SerialUSB.write(frame.payload[3]);
  440.           SerialUSB.println(" Command received from SMS, forwarding to modem.");
  441.           SerialUSB.println(message2);
  442.  
  443.           //Send the AT command to the modem.
  444.           digiSerial.write((char*)(&ATframe), l); delay(100);
  445.         }else if(strstr((char *)frame.payload,"CMD:") != 0){
  446.           //Command being sent.
  447.           String cmdFromSMS = "";
  448.           //copy the command to the new string, ignoring the "CMD:" header
  449.           for(int x=0;x<CMDLENGTH;x++){
  450.             cmdFromSMS += (char)frame.payload[x+4];
  451.           }
  452.  
  453.           //find the command in our list
  454.           int index = findCommandIndex(cmdFromSMS);
  455.           if(index == -1){//command not found
  456.             SerialUSB.print("Command not found: ");
  457.             SerialUSB.println(cmdFromSMS);
  458.           }else{
  459.             SerialUSB.print("Sending command to CANBUS: ");SerialUSB.println(cmdFromSMS);
  460.             txCANBUS(cbCommands[index]);
  461.           }
  462.         }
  463.       }else{
  464.         //other frame types need to be read and ignored I suppose...
  465.       }
  466.     }
  467. #endif
  468.   }
  469.  
  470.   //toggle one of the LEDs while the xbee is associated
  471.   digitalWrite(DS3,((digitalRead(XBEE_MULT2) == HIGH) ? LOW : HIGH));
  472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement