From 9d4f383421836dff5bc62acc47dd240bfa623485 Mon Sep 17 00:00:00 2001
From: kaltenbe <florian.kaltenberger@eurecom.fr>
Date: Thu, 28 Jan 2016 20:21:38 +0100
Subject: [PATCH] first integration. doesn't compile.

---
 .../ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp  | 210 +++++++++++++++---
 1 file changed, 185 insertions(+), 25 deletions(-)

diff --git a/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp b/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp
index 5914ff5be6..e5b9107251 100644
--- a/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp
+++ b/targets/ARCH/SODERA/USERSPACE/LIB/sodera_lib.cpp
@@ -68,6 +68,8 @@ int num_devices=0;
 /*These items configure the underlying asynch stream used by the the sync interface. 
  */
 
+#define BUFFERSIZE 65536
+#define BUFFERSCOUNT 16  // must be a power of 2
 typedef struct
 {
 
@@ -80,10 +82,16 @@ typedef struct
   LMS7002M lmsControl;
   LMS_StreamBoard *lmsStream;
 
+  uint8_t buffers_rx[BUFFERSIZE*BUFFERSCOUNT];
+  int handles[BUFFERSCOUNT];
+  int last_handle;
+  int samples_left_buffer;
+
   double sample_rate;
   // time offset between transmiter timestamp and receiver timestamp;
   double tdiff;
 
+  int channelscount;
   // --------------------------------
   // Debug and output control
   // --------------------------------
@@ -97,17 +105,86 @@ typedef struct
 
 } sodera_t;
 
+typedef struct {
+  uint8_t reserved[8];
+  uint64_t counter;
+  uint8_t data[4080];
+} StreamPacket_t;
+
 sodera_t sodera_state;
 
+enum STATUS {
+  SUCCESS,
+  FAILURE
+};
+
+STATUS SPI_write(LMScomms* dataPort, uint16_t address, uint16_t data)
+{
+  assert(dataPort != nullptr);
+  LMScomms::GenericPacket ctrPkt;
+  ctrPkt.cmd = CMD_BRDSPI_WR;
+  ctrPkt.outBuffer.push_back((address >> 8) & 0xFF);
+  ctrPkt.outBuffer.push_back(address & 0xFF);
+  ctrPkt.outBuffer.push_back((data >> 8) & 0xFF);
+  ctrPkt.outBuffer.push_back(data & 0xFF);
+  dataPort->TransferPacket(ctrPkt);
+  return ctrPkt.status == 1 ? SUCCESS : FAILURE;
+}
+
+uint16_t SPI_read(LMScomms* dataPort, uint16_t address)
+{
+  assert(dataPort != nullptr);
+  LMScomms::GenericPacket ctrPkt;
+  ctrPkt.cmd = CMD_BRDSPI_RD;
+  ctrPkt.outBuffer.push_back((address >> 8) & 0xFF);
+  ctrPkt.outBuffer.push_back(address & 0xFF);
+  dataPort->TransferPacket(ctrPkt);
+  if (ctrPkt.inBuffer.size() > 4)
+    return ctrPkt.inBuffer[2] * 256 + ctrPkt.inBuffer[3];
+  else
+    return 0;
+}
+
 static int trx_sodera_start(openair0_device *device)
 {
   sodera_t *s = (sodera_t*)device->priv;
 
+  const int buffersCountMask = buffersCount-1;
+
   // init recv and send streaming
 
   s->rx_count = 0;
   s->tx_count = 0;
   s->rx_timestamp = 0;
+  s->current_handle = 0;
+
+  // switch off RX
+  uint16_t regVal = SPI_read(s->Port,0x0005);
+  SPI_write(s->port,0x0005,regVal & ~0x6);
+
+  if (s->channelscount==2) {
+    SPI_write(s->Port,0x0001,0x0003);
+    SPI_write(s->Port,0x0007,0x000A);
+  }
+  else {
+    SPI_write(s->Port,0x0001,0x0001);
+    SPI_write(s->Port,0x0007,0x0008);
+  }
+
+  // USB FIFO reset
+  LMScomms::GenericPacket ctrPkt;
+  ctrPkt.cmd = CMD_USR_FIFO_RST;
+  ctrPkt.outBuffer.push_back(0x01);
+  s->Port.TransferPacket(ctrPkt);
+  ctrPkt.outBuffer[0]=0x00;
+  s->Port.TransferPacket(ctrPkt);
+  
+  uint16_t regVal = SPI_read(s->Port,0x0005);
+  // provide timestamp, set streamTXEN, set TX/RX enable 
+  SPI_write(s->port,0x0005,(regVal & ~0x20) | 0x6);
+
+  for (int i=0; i< BUFFERSCOUNT ; i++) 
+    s->handles[i] = s->Port.BeginDataReading(&s->buffers[i*BUFFERSIZE],BUFFERSIZE);
 
   return 0;
 }
@@ -117,7 +194,10 @@ static void trx_sodera_end(openair0_device *device)
   sodera_t *s = (sodera_t*)device->priv;
 
 
-  
+  // stop TX/RX if they were active
+  regVal = SPI_read(s->Port,0x0005);
+  SPI_write(s->Port,0x0005,regVal & ~0x6);
+
 }
 
 static int trx_sodera_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
@@ -138,36 +218,114 @@ static int trx_sodera_read(openair0_device *device, openair0_timestamp *ptimesta
    sodera_t *s = (sodera_t*)device->priv;
    int samples_received=0,i,j;
    int nsamps2;  // aligned to upper 32 or 16 byte boundary
-#if defined(__x86_64) || defined(__i386__)
-#ifdef __AVX2__
-   __m256i buff_tmp[2][nsamps>>3];
-   nsamps2 = (nsamps+7)>>3;
-#else
-   __m128i buff_tmp[2][nsamps>>2];
-   nsamps2 = (nsamps+3)>>2;
-#endif
-#elif defined(__arm__)
-   int16x8_t buff_tmp[2][nsamps>>2];
-   nsamps2 = (nsamps+3)>>2;
-#endif
-
-
-   if (cc>1) {
-     // receive multiple channels (e.g. RF A and RF B)
-     
-   } else {
-     // receive a single channel (e.g. from connector RF A)
+   StreamPacket_t *p;
+   int16_t sampleI,sampleQ;
+   uint8_t *pktStart;
+   int offset = 0;
+   int num_p;
+   int ind=0;
+
+   // this assumes that each request is of size 4096 bytes (spp = 4080/4/channelscount)
+   
+   // first get rid of remaining samples
+   if (s->samples_left_buffer > 0) {
+     buffsize = min(s->samples_left_buffer,nsamps);
+     pktStart = &s->buffers_rx[(s->last_handle-1)*BUFFERSIZE].data;
+     pktStart -= (spp-s->samples_left_buffer);
+     const int stepSize = s->channelscount * 3;
+
+     for (int b=0;b<buffsize<<2;b+=stepSize) {
+       for (int ch=0;ch<s->channelscount;ch++) {
+	 // I sample
+	 sampleI = (pktStart[b + 1 + 3*ch]&0x0F)<<8;
+	 sampleI |= (pktStart[b + 3*ch]&0xFF);
+	 sampleI = (sampleI<<4)>>4;
+	 // Q sample
+	 sampleQ = (pktStart[b + 2 + 3*ch]&0x0F)<<8;
+	 sampleQ |= (pktStart[b + 1 + 3*ch]&0xFF);
+	 sampleQ = (sampleQ<<4)>>4;
+	 ((uint32_t*)buff[ch])[ind] = ((uint32_t)sampleI) | (((uint32_t)sampleQ)<<16);
+       }
+       ind++;
+     }
+   }
+   if (ind == nsamps) {
+     s->samples_left_buffer -= nsamps;
+     s->rx_count += nsamps;
+     s->rx_timestamp += s->last_transfer;
+     *ptimestamp = s->rx_timestamp;
+     s->last_transfer = nsamps;
      
+     return(nsamps);
+   }
+   else {
+     s->samples_left_buffer = 0;
+     nsamps -= ind;
+     samples_received = ind;
    }
+
+   // This is for the left-over part => READ from USB
+
+
+   spp = sizeof(p->data)>>2; // spp = size of payload in samples  
+   spp /= s->channelscount;
+
+   num_p = nsamps / spp;
+   if ((nsamps%spp) > 0)
+     num_p++;
+   s->samples_left_buffer = (num_p*spp)-nsamps;
+   for (int i=0;i<num_p;i++)
+     s->handles[i] = s->Port.BeginDataReading(&buffers_rx[i*BUFFERSIZE],BUFFERSIZE);
+   s->last_handle = num_p;
    
-  if (samples_received < nsamps) {
-    printf("[recv] received %d samples out of %d\n",samples_received,nsamps);
+
+   const int stepSize = s->channelscount * 3;
+
+   for (i=0;i<num_p;i++) {
+
+     if (s->Port.WaitForReading(s->handles[i],1000) == false) {
+       printf("[recv] Error: request %d samples (%d/%d) WaitForReading timed out\n",nsamps,i,num_p);
+       return(samples_received);
+     }
+     if ((ret=Port.FinishDataReading(&s->buffers_rx[i*BUFFERSIZE],BUFFERSIZE,s->handles[i])) != BUFFERSIZE) {  
+       printf("[recv] Error: request %d samples (%d/%d) WaitForReading timed out\n",nsamps,i,num_p);
+       return(samples_received);
+     }
     
-  }
+     p = (StreamPacket_t*)&s->buffers_rx[i*BUFFERSIZE];
+     // handle timestamp
+     if ((i==0) & (ind==0)) { // grab the timestamp from HW
+       s->rx_timestamp = p->counter;
+     }
+     else { // check the timestamp
+       if (i==0) {
+	 if ((s->rx_timestamp + ind) != p->counter) {
+	   printf("Error, RX timestamp error, got %llu, should be %llu\n",p->counter,s->rx_timestamp+ind);
+	   return(ind);
+	 }
+       }
+     }
+     pktStart = &p->data;
+     for (uint16_t b=0;b<sizeof(p->data);n+=stepSize) {
+       for (int ch=0;ch < s->channelscount;ch++) {
+	 // I sample
+	 sampleI = (pktStart[b + 1 + 3*ch]&0x0F)<<8;
+	 sampleI |= (pktStart[b + 3*ch]&0xFF);
+	 sampleI = (sampleI<<4)>>4;
+	 // Q sample
+	 sampleQ = (pktStart[b + 2 + 3*ch]&0x0F)<<8;
+	 sampleQ |= (pktStart[b + 1 + 3*ch]&0xFF);
+	 sampleQ = (sampleQ<<4)>>4;
+	 ((uint32_t*)buff[ch])[ind] = ((uint32_t)sampleI) | (((uint32_t)sampleQ)<<16);
+       }
+       ind++;	        
+     }
+     samples_received+=spp;
+   }   
 
   //handle the error code
 
-  s->rx_count += nsamps;
+  s->rx_count += samples_received;
   //  s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
   *ptimestamp = s->rx_timestamp;
 
@@ -531,7 +689,9 @@ int openair0_dev_init_sodera(openair0_device* device, openair0_config_t *openair
   device->trx_set_freq_func = trx_sodera_set_freq;
   device->trx_set_gains_func   = trx_sodera_set_gains;
   
-  s->sample_rate = openair0_cfg[0].sample_rate;
+  s->sample_rate   = openair0_cfg[0].sample_rate;
+  s->channelscount = openair0_cfg[0].rx_num_channels;
+
   // TODO:
   exit(-1);
   return 0;
-- 
GitLab