diff --git a/conf/modules/gps_i2c.xml b/conf/modules/gps_i2c.xml
new file mode 100644
index 0000000000..69b1197a21
--- /dev/null
+++ b/conf/modules/gps_i2c.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/modules/gps_i2c/gps_i2c.c b/sw/airborne/modules/gps_i2c/gps_i2c.c
new file mode 100644
index 0000000000..f49bd72a5d
--- /dev/null
+++ b/sw/airborne/modules/gps_i2c/gps_i2c.c
@@ -0,0 +1,88 @@
+#include "gps_i2c.h"
+#include "i2c.h"
+
+uint8_t gps_i2c_buf[GPS_I2C_BUF_SIZE];
+uint8_t gps_i2c_insert_idx, gps_i2c_extract_idx;
+
+
+/* u-blox5 protocole, page 4 */
+#define GPS_I2C_SLAVE_ADDR 0x42
+#define GPS_I2C_ADDR_NB_AVAIL_BYTES 0xFD
+#define GPS_I2C_ADDR_DATA 0xFF
+
+#define GPS_I2C_STATUS_IDLE 0
+#define GPS_I2C_STATUS_ASKING_DATA 1
+#define GPS_I2C_STATUS_ASKING_NB_AVAIL_BYTES 2
+#define GPS_I2C_STATUS_READING_NB_AVAIL_BYTES 3
+#define GPS_I2C_STATUS_READING_DATA 4
+
+static uint8_t gps_i2c_status;
+static bool_t gps_i2c_done;
+static uint8_t gps_i2c_nb_avail_bytes;
+static uint8_t data_buf_len;
+
+void
+gps_i2c_init(void) {
+ gps_i2c_status = GPS_I2C_STATUS_IDLE;
+ gps_i2c_done = TRUE;
+}
+
+static inline void
+gps_i2c_ask_read(uint8_t addr) {
+ i2c0_buf[0] = addr;
+ i2c0_transmit(GPS_I2C_SLAVE_ADDR, 1, &gps_i2c_done);
+ gps_i2c_done = FALSE;
+}
+
+static inline void
+continue_reading(void) {
+ if (gps_i2c_nb_avail_bytes > 0) {
+ gps_i2c_ask_read(GPS_I2C_ADDR_DATA);
+ gps_i2c_status = GPS_I2C_STATUS_ASKING_DATA;
+ } else {
+ gps_i2c_status = GPS_I2C_STATUS_IDLE;
+ }
+}
+
+void
+gps_i2c_periodic(void) {
+ // We should check gps_i2c_done == true
+ gps_i2c_ask_read(GPS_I2C_ADDR_NB_AVAIL_BYTES);
+ gps_i2c_status = GPS_I2C_STATUS_ASKING_NB_AVAIL_BYTES;
+}
+
+void
+gps_i2c_event(void) {
+ if (gps_i2c_done) {
+ switch (gps_i2c_status) {
+ case GPS_I2C_STATUS_ASKING_NB_AVAIL_BYTES:
+ i2c0_receive(GPS_I2C_SLAVE_ADDR, 2, &gps_i2c_done);
+ gps_i2c_done = FALSE;
+ gps_i2c_status = GPS_I2C_STATUS_READING_NB_AVAIL_BYTES;
+ break;
+
+ case GPS_I2C_STATUS_READING_NB_AVAIL_BYTES:
+ gps_i2c_nb_avail_bytes = (i2c0_buf[0]<<8) | i2c0_buf[1];
+ continue_reading();
+ break;
+
+ case GPS_I2C_STATUS_ASKING_DATA:
+ data_buf_len = Min(gps_i2c_nb_avail_bytes, I2C0_BUF_LEN);
+ gps_i2c_nb_avail_bytes -= data_buf_len;
+
+ i2c0_receive(GPS_I2C_SLAVE_ADDR, data_buf_len, &gps_i2c_done);
+ gps_i2c_done = FALSE;
+ gps_i2c_status = GPS_I2C_STATUS_READING_DATA;
+ break;
+
+ case GPS_I2C_STATUS_READING_DATA: {
+ uint8_t i;
+ for(i = 0; i < data_buf_len; i++) {
+ gps_i2c_AddCharToBuf(i2c0_buf[i]);
+ }
+ continue_reading();
+ break;
+ }
+ }
+ }
+}
diff --git a/sw/airborne/modules/gps_i2c/gps_i2c.h b/sw/airborne/modules/gps_i2c/gps_i2c.h
new file mode 100644
index 0000000000..16f78c015d
--- /dev/null
+++ b/sw/airborne/modules/gps_i2c/gps_i2c.h
@@ -0,0 +1,19 @@
+#ifndef GPS_I2C
+#define GPS_I2C
+
+#include
+
+#define GPS_I2C_BUF_SIZE 256
+extern uint8_t gps_i2c_buf[GPS_I2C_BUF_SIZE];
+extern uint8_t gps_i2c_insert_idx, gps_i2c_extract_idx;
+
+void gps_i2c_init(void);
+void gps_i2c_event(void);
+void gps_i2c_periodic(void);
+
+#define gps_i2c_AddCharToBuf(_x) { \
+ gps_i2c_buf[gps_i2c_insert_idx] = _x; \
+ gps_i2c_insert_idx++; /* size=256, No check for buf overflow */ \
+}
+
+#endif // GPS_I2C