ublox_device.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "ublox_device.h"
  2. #define TAG "ublox_device"
  3. UbloxMessage* ublox_frame_to_bytes(UbloxFrame* frame) {
  4. uint32_t message_size = 8 + frame->len;
  5. // Found the issue! frame_bytes isn't being freed. This function
  6. // should always have returned a pointer.
  7. uint8_t* frame_bytes = malloc(message_size);
  8. frame->sync1 = 0xb5;
  9. frame->sync2 = 0x62;
  10. frame_bytes[0] = frame->sync1;
  11. frame_bytes[1] = frame->sync2;
  12. frame_bytes[2] = frame->class;
  13. frame_bytes[3] = frame->id;
  14. frame_bytes[4] = frame->len & 0xff;
  15. frame_bytes[5] = (frame->len & 0xff) >> 8;
  16. if(frame->len != 0) {
  17. for(int i = 0; i < frame->len; i++) {
  18. frame_bytes[6 + i] = frame->payload[i];
  19. }
  20. }
  21. frame->ck_a = 0;
  22. frame->ck_b = 0;
  23. // checksum is calculated over class, id, length, and payload
  24. for(int i = 2; i < 2 + (frame->len + 4); i++) {
  25. frame->ck_a = frame->ck_a + frame_bytes[i];
  26. frame->ck_b = frame->ck_b + frame->ck_a;
  27. }
  28. frame_bytes[message_size - 2] = frame->ck_a;
  29. frame_bytes[message_size - 1] = frame->ck_b;
  30. UbloxMessage* m = malloc(sizeof(UbloxMessage));
  31. m->message = frame_bytes;
  32. m->length = message_size;
  33. return m;
  34. }
  35. void ublox_message_free(UbloxMessage* message) {
  36. if(message != NULL) {
  37. if(message->message != NULL) {
  38. free(message->message);
  39. } /*else {
  40. FURI_LOG_I(TAG, "message free: message->message == NULL");
  41. }*/
  42. free(message);
  43. } /*else {
  44. FURI_LOG_I(TAG, "message free: message == NULL");
  45. }*/
  46. }
  47. // Pointer, because we are assigning a pointer in the returned frame.
  48. UbloxFrame* ublox_bytes_to_frame(UbloxMessage* message) {
  49. if(message->length < 8) {
  50. FURI_LOG_I(TAG, "message length in bytes_to_frame < 8, = 0x%x", message->length);
  51. // minimum 8 bytes in a message (message with no payload)
  52. return NULL;
  53. }
  54. UbloxFrame* frame = malloc(sizeof(UbloxFrame));
  55. if(message->message[0] != 0xb5) {
  56. FURI_LOG_E(TAG, "message[0] != 0xb5, = 0x%x", message->message[0]);
  57. free(frame);
  58. return NULL;
  59. }
  60. frame->sync1 = message->message[0];
  61. if(message->message[1] != 0x62) {
  62. FURI_LOG_E(TAG, "Message[1] != 0x62, = 0x%x", message->message[1]);
  63. free(frame);
  64. return NULL;
  65. }
  66. frame->sync2 = message->message[1];
  67. frame->class = message->message[2];
  68. frame->id = message->message[3];
  69. // little-endian
  70. frame->len = (message->message[5] << 8) | (message->message[4]);
  71. // frame->len must be initialized before malloc (duh, but I made that mistake...)
  72. frame->payload = malloc(frame->len);
  73. //FURI_LOG_I(TAG, "frame->len: %d", frame->len);
  74. for(int i = 6; i < 6 + frame->len; i++) {
  75. frame->payload[i - 6] = message->message[i];
  76. }
  77. frame->ck_a = message->message[6 + frame->len];
  78. frame->ck_b = message->message[6 + frame->len + 1];
  79. // Test checksum
  80. uint8_t ck_a = 0, ck_b = 0;
  81. for(int i = 2; i < 2 + (frame->len + 4); i++) {
  82. ck_a = ck_a + message->message[i];
  83. ck_b = ck_b + ck_a;
  84. }
  85. if(ck_a != frame->ck_a) {
  86. FURI_LOG_E(TAG, "checksum A doesn't match! expected 0x%x, got 0x%x", ck_a, frame->ck_a);
  87. free(frame);
  88. free(frame->payload);
  89. return NULL;
  90. }
  91. if(ck_b != frame->ck_b) {
  92. FURI_LOG_E(TAG, "checksum B doesn't match! expected 0x%x, got 0x%x", ck_b, frame->ck_b);
  93. free(frame);
  94. free(frame->payload);
  95. return NULL;
  96. }
  97. return frame;
  98. }
  99. void ublox_frame_free(UbloxFrame* frame) {
  100. if(frame != NULL) {
  101. if(frame->payload != NULL) {
  102. free(frame->payload);
  103. } /* else {
  104. FURI_LOG_I(TAG, "frame free: frame->payload == NULL");
  105. }*/
  106. free(frame);
  107. } /* else {
  108. FURI_LOG_I(TAG, "frame free: frame == NULL");
  109. }*/
  110. }
  111. UbloxMessage* ublox_i2c_transfer(UbloxMessage* message_tx, uint8_t read_length) {
  112. if(!furi_hal_i2c_is_device_ready(
  113. &furi_hal_i2c_handle_external,
  114. UBLOX_I2C_ADDRESS << 1,
  115. furi_ms_to_ticks(I2C_TIMEOUT_MS))) {
  116. FURI_LOG_E(TAG, "device not ready");
  117. return NULL;
  118. }
  119. // Either our I2C implementation is broken or the GPS's is, so we
  120. // end up reading a lot more data than we need to. That means that
  121. // the I2C comm code for this app is a little bit of a hack, but
  122. // it works fine and is fast enough, so I don't really care. It
  123. // certainly doesn't break the GPS.
  124. if(!furi_hal_i2c_tx(
  125. &furi_hal_i2c_handle_external,
  126. UBLOX_I2C_ADDRESS << 1,
  127. message_tx->message,
  128. message_tx->length,
  129. furi_ms_to_ticks(I2C_TIMEOUT_MS))) {
  130. FURI_LOG_E(TAG, "error writing message to GPS");
  131. return NULL;
  132. }
  133. uint8_t* response = malloc((size_t)read_length);
  134. // The GPS sends 0xff until it has a complete message to respond
  135. // with. We have to wait until it stops sending that. (Why this
  136. // works is a little bit...uh, well, I don't know. Shouldn't reading
  137. // more bytes make it so that the data is completely read out and no
  138. // longer available?)
  139. //FURI_LOG_I(TAG, "start ticks at %lu", furi_get_tick()); // returns ms
  140. while(true) {
  141. if(!furi_hal_i2c_rx(
  142. &furi_hal_i2c_handle_external,
  143. UBLOX_I2C_ADDRESS << 1,
  144. response,
  145. 1,
  146. furi_ms_to_ticks(I2C_TIMEOUT_MS))) {
  147. FURI_LOG_E(TAG, "error reading first byte of response");
  148. free(response);
  149. return NULL;
  150. }
  151. // checking with 0xb5 prevents strange bursts of junk data from becoming an issue.
  152. if(response[0] != 0xff && response[0] == 0xb5) {
  153. //FURI_LOG_I(TAG, "read rest of message at %lu", furi_get_tick());
  154. if(!furi_hal_i2c_rx(
  155. &furi_hal_i2c_handle_external,
  156. UBLOX_I2C_ADDRESS << 1,
  157. &(response[1]),
  158. read_length - 1, // first byte already read
  159. furi_ms_to_ticks(I2C_TIMEOUT_MS))) {
  160. FURI_LOG_E(TAG, "error reading rest of response");
  161. free(response);
  162. return NULL;
  163. }
  164. break;
  165. }
  166. furi_delay_ms(1);
  167. }
  168. UbloxMessage* message_rx = malloc(sizeof(UbloxMessage));
  169. message_rx->message = response;
  170. message_rx->length = read_length;
  171. return message_rx; // message_rx->message needs to be freed later
  172. }