Semana 14

Esta semana vamos a continuar la exploración del paquete Ardity.

Sesión 1

Ejercicio 1

¿Qué excepciones se están considerando en el código?

Ejercicio 2

¿Qué pasa si no reciben datos por el puerto serial durante 100ms?

Ejercicio 3

¿Qué pasa si el cable serial se desconecta de manera inesperada?

Ejercicio 4

¿Cómo se reestablece el funcionamiento de la aplicación?

Ejercicio 5

¿Qué modificación tendríamos que hacer a la aplicación de arduino para reestablecer la comunicación?

Sesión 2

Ejercicio 1

¿Qué modificación debemos realizar en el paquete Ardity si queremos soportar un nuevo protocolo de comunicación?

RETO

En la semana 11 trabajamos con un sensor que utilizaba un protocolo binario. Este era el sensor. Y su manual del fabricante se encuentra aquí. Adicionalmente usamos este archivo de prueba enviado por el fabricante del sensor.

El siguiente código simula el funcionamiento del sensor RFID para poder probar una aplicación interactiva que se conecte al sensor.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 #include <Arduino.h>
 //#define DEBUG
 #ifdef DEBUG
 #define DEBUG_PRINT(msg,value) Serial.print(msg); Serial.println(value)
 #else
 #define DEBUG_PRINT(msg,value)
 #endif

 void TaskReadCommand();
 unsigned int uiCrc16Cal(unsigned char const *, unsigned char);
 void parseCommad(uint8_t *);

 void setup()
 {
   Serial.begin(57600);
 }

 void loop()
 {
   TaskReadCommand();
 }

 void TaskReadCommand()
 {
   enum class serialStates {
     waitLen,
     waitData
   };

   static auto state = serialStates::waitLen;
   static uint8_t buffer[32] = {0};
   static uint8_t dataCounter = 0;

   switch (state)
   {
     case serialStates::waitLen: // wait for the first byte: len

       if (Serial.available())
       {
         buffer[dataCounter] = Serial.read();
         dataCounter++;
         state = serialStates::waitData;
         DEBUG_PRINT("Go to rx data", "");
       }
       break;

     case serialStates::waitData: // read data
       while (Serial.available())
       {
         buffer[dataCounter] = Serial.read();
         dataCounter++;

         if (dataCounter == (buffer[0] + 1))
         { // if all bytes arrived
           // verify the checksum
           DEBUG_PRINT("Verify the checksum", "");
           DEBUG_PRINT("dataCount: ",´ dataCounter);
           if (dataCounter >= 5)
           {
             unsigned int checksum = uiCrc16Cal(buffer, dataCounter - 2);
             uint8_t lsBChecksum = (uint8_t)(checksum & 0x000000FF);
             uint8_t msBChecksum = (uint8_t)((checksum & 0x0000FF00) >> 8);
             if ((lsBChecksum == buffer[dataCounter - 2]) && (msBChecksum == buffer[dataCounter - 1]))
             {
               DEBUG_PRINT("ChecksumOK", "");
               parseCommad(buffer);
             }
           }
           dataCounter = 0;
           state = serialStates::waitLen;
           DEBUG_PRINT("Go to rx len", "");
         }
       }
       break;
   }
 }

 void parseCommad(uint8_t *pdata)
 {
   uint8_t command = pdata[2];
   static uint8_t command21[] = {0x0D, 0x00, 0x21, 0x00, 0x02, 0x44, 0x09, 0x03, 0x4E, 0x00, 0x1E, 0x0A, 0xF2, 0x16};
   static uint8_t command24[] = {0x05, 0x00, 0x24, 0x00, 0x25, 0x29};
   static uint8_t command2F[] = {0x05, 0x00, 0x2F, 0x00, 0x8D, 0xCD};
   static uint8_t command22[] = {0x05, 0x00, 0x22, 0x00, 0xF5, 0x7D};
   static uint8_t command28[] = {0x05, 0x00, 0x28, 0x00, 0x85, 0x80};
   static uint8_t command25[] = {0x05, 0x00, 0x25, 0x00, 0xFD, 0x30};


   switch (command)
   {
     case 0x21:
       Serial.write(command21, sizeof(command21));
       break;
     case 0x24:
       Serial.write(command24, sizeof(command24));
       break;

     case 0x2F:
       Serial.write(command2F, sizeof(command2F));
       break;

     case 0x22:
       Serial.write(command22, sizeof(command22));
       break;

     case 0x28:
       Serial.write(command28, sizeof(command28));
       break;

     case 0x25:
       Serial.write(command25, sizeof(command25));
       break;
   }
 }

 unsigned int uiCrc16Cal(unsigned char const *pucY, unsigned char ucX)
 {
   const uint16_t PRESET_VALUE = 0xFFFF;
   const uint16_t POLYNOMIAL = 0x8408;


   unsigned char ucI, ucJ;
   unsigned short int uiCrcValue = PRESET_VALUE;

   for (ucI = 0; ucI < ucX; ucI++)
   {
     uiCrcValue = uiCrcValue ^ *(pucY + ucI);
     for (ucJ = 0; ucJ < 8; ucJ++)
     {
       if (uiCrcValue & 0x0001)
       {
         uiCrcValue = (uiCrcValue >> 1) ^ POLYNOMIAL;
       }
       else
       {
         uiCrcValue = (uiCrcValue >> 1);
       }
     }
   }
   return uiCrcValue;
 }

La semana 12 presentamos una solución a los retos de la semana 11 que buscaban conectar el sensor a una aplicación de consola usando C#.

El siguiente código muestra cómo interactuar con el sensor desde una aplicación C#.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
 using System;
 using System.IO.Ports;

 namespace sem11Reto1
 {
     class Program
     {
         private static SerialPort _serialPort = new SerialPort();
         private static readonly byte[] q_commnad = new byte[] { 0x04, 0xFF, 0x21, 0x19, 0x95 };
         private static readonly byte[] w_commnad = new byte[] { 0x05, 0x00, 0x24, 0x00, 0x25, 0x29 };
         private static readonly byte[] e_commnad = new byte[] { 0x05, 0x00, 0x2F, 0x1E, 0x72, 0x34 };
         private static readonly byte[] r_commnad =  new byte[] { 0x06, 0x00, 0x22, 0x31, 0x80, 0xE1, 0x96 };
         private static readonly byte[] t_commnad =  new byte[] { 0x05, 0x00, 0x28, 0x05, 0x28, 0xD7 };
         private static readonly byte[] y_commnad = new byte[] { 0x05, 0x00, 0x25, 0x00, 0xFD, 0x30 };
         private static byte[] buffer = new byte[32];

         static void Main(string[] args)
         {
             // Allow the user to set the appropriate properties.
             _serialPort.PortName = "COM4";
             _serialPort.BaudRate = 57600;
             _serialPort.DtrEnable = true;
             _serialPort.Open();

             while (true)
             {
                 Console.WriteLine();
                 Console.WriteLine("Commands available: Q: 0x21, W: 0x24, E: 0x2F, R: 0x22, T: 0x28, Y: 0x25");
                 switch (Console.ReadKey(true).Key)
                 {
                     case ConsoleKey.Q:
                         sendCommand(q_commnad);
                         readData();
                         break;
                     case ConsoleKey.W:
                         sendCommand(w_commnad);
                         readData();
                         break;

                     case ConsoleKey.E:
                         sendCommand(e_commnad);
                         readData();
                         break;
                     case ConsoleKey.R:
                         sendCommand(r_commnad);
                         readData();
                         break;

                     case ConsoleKey.T:
                         sendCommand(t_commnad);
                         readData();
                         break;

                     case ConsoleKey.Y:
                         sendCommand(y_commnad);
                         readData();
                         break;

                     default:
                         break;
                 }


             }
         }

         private static void sendCommand(byte[] data)
         {
             Console.Write("Send this packet: ");
             for(int i = 0; i < data.Length; i++)
             {
                 Console.Write("{0:X2}",data[i]);
                 Console.Write(' ');
             }
             Console.WriteLine();
             _serialPort.Write(data, 0, data.Length);
         }

         private static void readData()
         {
             // 1. Este llamado bloque completamente el hilo
             // esperando a que lleguen datos por el puerto serial
             while (_serialPort.BytesToRead == 0) ;

             // 2. Leo el primer byte que me dice la longitud
             _serialPort.Read(buffer, 0, 1);
             // 3. Espero el resto de datos
             while (_serialPort.BytesToRead < buffer[0]) ;

             // 4. Leo los datos
             _serialPort.Read(buffer, 1, buffer[0]);

             // 5. Verifica el checksum
             bool checksumOK = verifyChecksum(buffer);
             Console.Write("Packet received: ");
             for(int i = 0; i < (buffer[0] + 1); i++)
             {
                 Console.Write("{0:X2}", buffer[i]);
                 Console.Write(' ');

             }
             if(checksumOK == false)
             {
                 Console.WriteLine(" Checksum Fails");
             }
             else
             {
                 Console.WriteLine();
             }

         }

         private static bool verifyChecksum(byte[] packet)
         {
             bool checksumOK = false;
             byte ucI, ucJ;

             int uiCrcValue = 0x0000FFFF;
             int len = packet[0] + 1;

             for (ucI = 0; ucI < (len - 2); ucI++)
             {
                 uiCrcValue = uiCrcValue ^ packet[ucI];
                 for (ucJ = 0; ucJ < 8; ucJ++)
                 {
                     if ((uiCrcValue & 0x00000001) == 0x00000001)
                     {
                         uiCrcValue = (uiCrcValue >> 1) ^ 0x00008408;
                     }
                     else
                     {
                         uiCrcValue = (uiCrcValue >> 1);
                     }
                 }
             }

             int LSBCkecksum = uiCrcValue & 0x000000FF;
             int MSBCkecksum = (uiCrcValue & 0x0000FF00) >> 8;

             if ((packet[len - 2] == LSBCkecksum) && (packet[len - 1] == MSBCkecksum)) checksumOK = true;
             return checksumOK;
         }

     }
 }

El reto entonces consiste en realizar la integración del sensor, pero esta vez al motor Unity, modificando el paquete Ardity para que pueda soportar este nuevo protocolo.