Beispiel #1
0
int sdr_bladerf_file_tx(void *dev, struct complexf *samples, unsigned int count)
{
    int status = 0;
    size_t n;
    unsigned int to_write, total_written;
    struct sdr_bladerf_file *sdr = (struct sdr_bladerf_file *) dev;

    total_written = 0;

    while (status == 0 && total_written< count) {
        to_write = uint_min(sdr->buf_len, count - total_written);

        complexf_to_sc16q11(samples, sdr->buf, to_write);

        log_verbose("Writing'ing %u samples...\n", to_write);

        n = fwrite(sdr->buf, 2 * sizeof(int16_t), to_write, sdr->file);
        if (n != to_write) {
            log_debug("Sample file write was truncated.\n");
            status = -1;
        }

        samples += to_write;
        total_written += to_write;
    }

    return status;
}
Beispiel #2
0
int sdr_bladerf_file_rx(void *dev, struct complexf *samples, unsigned int count)
{
    int status = 0;
    size_t n;
    unsigned int to_read, total_read;
    struct sdr_bladerf_file *sdr = (struct sdr_bladerf_file *) dev;

    total_read = 0;

    while (status == 0 && total_read < count) {
        to_read = uint_min(sdr->buf_len, count - total_read);
        log_verbose("Reading %u samples...\n", to_read);

        n = fread(sdr->buf, 2 * sizeof(int16_t), to_read, sdr->file);
        if (n == 0) {
            status = SDR_FILE_EOF;
        } else if (n < to_read) {
            /* Zero out the remaining samples. We're about to hit an EOF. */
            int16_t *to_zero = sdr->buf + (2 * n);
            memset(to_zero, 0, 2 * sizeof(int16_t) * (to_read - n));
        }

        sc16q11_to_complexf(sdr->buf, samples, to_read);

        samples += to_read;
        total_read += to_read;
    }

    return status;
}
static void * tx_task(void *args)
{
    int status;
    int16_t *samples;
    unsigned int i;
    struct bladerf_metadata meta;
    uint64_t samples_left;
    struct test *t = (struct test *) args;
    bool stop = false;
    int16_t zeros[] = { 0, 0, 0, 0 };

    samples = (int16_t*) malloc(2 * sizeof(samples[0]) * t->params->buf_size);
    if (samples == NULL) {
        perror("malloc");
        return NULL;
    }

    memset(&meta, 0, sizeof(meta));

    for (i = 0; i < (2 * t->params->buf_size); i += 2) {
        samples[i] = samples[i + 1] = TX_MAGNITUDE;
    }

    status = bladerf_get_timestamp(t->dev, BLADERF_MODULE_TX, &meta.timestamp);
    if (status != 0) {
        fprintf(stderr, "Failed to get current timestamp: %s\n",
                bladerf_strerror(status));
    }

    meta.timestamp += 400000;

    for (i = 0; i < t->num_bursts && !stop; i++) {
        meta.flags = BLADERF_META_FLAG_TX_BURST_START;
        samples_left = t->bursts[i].duration;

        assert(samples_left <= UINT_MAX);

        if (i != 0) {
            meta.timestamp += (t->bursts[i-1].duration + t->bursts[i].gap);
        }

        while (samples_left != 0 && status == 0) {
            unsigned int to_send = uint_min(t->params->buf_size,
                                            (unsigned int) samples_left);

            status = bladerf_sync_tx(t->dev, samples, to_send, &meta,
                                     t->params->timeout_ms);

            if (status != 0) {
                fprintf(stderr, "Failed to TX @ burst %-4u with %"PRIu64
                        " samples left: %s\n",
                        i + 1, samples_left, bladerf_strerror(status));

                /* Stop the RX worker */
                pthread_mutex_lock(&t->lock);
                t->stop = true;
                pthread_mutex_unlock(&t->lock);
            }

            meta.flags &= ~BLADERF_META_FLAG_TX_BURST_START;
            samples_left -= to_send;
        }

        /* Flush TX samples by ensuring we have 2 zero samples at the end
         * of our burst (as required by libbladeRF) */
        if (status == 0) {
            meta.flags = BLADERF_META_FLAG_TX_BURST_END;
            status = bladerf_sync_tx(t->dev, zeros, 2, &meta,
                                     t->params->timeout_ms);

            if (status != 0) {
                fprintf(stderr, "Failed to flush TX: %s\n",
                        bladerf_strerror(status));

                /* Stop the RX worker */
                pthread_mutex_lock(&t->lock);
                t->stop = true;
                pthread_mutex_unlock(&t->lock);
            }
        }

        pthread_mutex_lock(&t->lock);
        stop = t->stop;
        pthread_mutex_unlock(&t->lock);
    }

    /* Wait for samples to finish */
    printf("TX: Waiting for samples to finish.\n");
    fflush(stdout);
    status = wait_for_timestamp(t->dev, BLADERF_MODULE_TX,
                                meta.timestamp + t->bursts[i - 1].duration,
                                3000);

    if (status != 0) {
        fprintf(stderr, "Failed to wait for TX to complete: %s\n",
                bladerf_strerror(status));
    }

    free(samples);

    printf("TX: Exiting task.\n");
    fflush(stdout);
    return NULL;
}
Beispiel #4
0
/* FIXME Clean up this function up. It's very unreadable.
 *       Suggestions include moving to switch() and possibly adding some
 *       intermediary states. (More smaller, simpler states);
 */
static void *rx_task(void *arg) {
    int lib_ret, write_ret;
    enum rxtx_state state, prev_state;
    struct cli_state *s = (struct cli_state *) arg;
    struct rx_cfg *rx = &s->rxtx_data->rx;
    unsigned int n_samples_left = 0;
    bool inf = false;
    size_t to_write = 0;

    /* We expect to be in the IDLE state when this task is kicked off */
    state = prev_state = get_state(&rx->common);
    assert(state == RXTX_STATE_IDLE || state == RXTX_STATE_SHUTDOWN);

    while (state != RXTX_STATE_SHUTDOWN) {
        if (state == RXTX_STATE_RUNNING) {

            /* Transitioning from IDLE/ERROR -> RUNNING */
            if (prev_state == RXTX_STATE_IDLE ||
                prev_state == RXTX_STATE_ERROR) {

                pthread_mutex_lock(&rx->common.param_lock);
                n_samples_left = rx->n_samples;
                pthread_mutex_unlock(&rx->common.param_lock);

                inf = n_samples_left == 0;

                /* Task owns file while running */
                pthread_mutex_lock(&rx->common.file_lock);

                /* Flush out any old samples before recording any data */
                /*lib_ret = bladerf_read_c16(s->dev, rx->common.buff,
                                                   rx->common.buff_size / 2);*/
                lib_ret = bladerf_rx(
                            s->dev,
                            BLADERF_FORMAT_SC16_Q12,
                            rx->common.buff,
                            rx->common.buff_size/2,
                            NULL
                          );
                if (lib_ret < 0) {
                    set_last_error(&rx->common.error, ETYPE_BLADERF, lib_ret);
                    state = RXTX_STATE_ERROR;
                }
            } else {
                /*lib_ret = bladerf_read_c16(s->dev, rx->common.buff,
                                           rx->common.buff_size / 2);*/

                lib_ret = bladerf_rx(
                            s->dev,
                            BLADERF_FORMAT_SC16_Q12,
                            rx->common.buff,
                            rx->common.buff_size/2,
                            NULL
                          );
                if (lib_ret < 0) {
                    set_last_error(&rx->common.error, ETYPE_BLADERF, lib_ret);
                    state = RXTX_STATE_ERROR;
                } else {

                    /* Bug catcher */
                    assert((size_t)lib_ret <= (rx->common.buff_size / 2));

                    if (!inf) {
                        to_write = uint_min(n_samples_left, lib_ret);
                    } else {
                        to_write = rx->common.buff_size / 2;
                    }

                    write_ret = rx->write_samples(s, to_write);

                    if (write_ret < 0) {
                        /* write_samples will have set the last error info */
                        state = RXTX_STATE_ERROR;
                    } else if (!inf) {
                        n_samples_left -= to_write;
                        if (n_samples_left == 0) {
                            state = RXTX_STATE_IDLE;
                        }
                    }
                }
            }

        }

        if (state != RXTX_STATE_RUNNING && prev_state == RXTX_STATE_RUNNING) {
            /* Clean up as we transition from RUNNING -> <any other state> */
            lib_ret = bladerf_enable_module(s->dev, BLADERF_MODULE_RX, false);
            close_samples_file(&rx->common, false);
            pthread_mutex_unlock(&rx->common.file_lock);

            if (lib_ret < 0) {
                set_last_error(&rx->common.error, ETYPE_BLADERF, lib_ret);
                state = RXTX_STATE_ERROR;
            }

            set_state(&rx->common, state, false);
        }


        prev_state = state;

        /* Wait here while if we're in the IDLE/ERROR states */
        pthread_mutex_lock(&rx->common.task_lock);
        while (state == RXTX_STATE_IDLE || state == RXTX_STATE_ERROR) {
            pthread_cond_wait(&rx->common.task_state_changed,
                                &rx->common.task_lock);

            state = rx->common.task_state;
        }

        state = rx->common.task_state;
        pthread_mutex_unlock(&rx->common.task_lock);
    }

    return NULL;
}
Beispiel #5
0
int main()
{
    if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK ) < 0 )
    {
        SYS_BREAK( "SDL_Init failed!\n" );
    }

    SDL_SetVideoMode( ScreenWidth, ScreenHeight, 0u, SDL_OPENGL /*| SDL_FULLSCREEN */ );
#ifndef FONT_EDITOR
    SDL_ShowCursor( SDL_DISABLE );
#endif
    SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );

    SDL_AudioSpec audioSpec;
    audioSpec.freq      = SoundSampleRate;
    audioSpec.format    = AUDIO_S16SYS;
    audioSpec.channels  = SoundChannelCount;
    audioSpec.silence   = 0;
    audioSpec.samples   = SoundBufferSampleCount;
    audioSpec.size      = 0;
    audioSpec.callback  = soundCallback;
    audioSpec.userdata  = s_soundBuffer;

    SDL_OpenAudio( &audioSpec, NULL );

    game_init();

    SDL_PauseAudio( 0 );

    uint32 lastTime = SDL_GetTicks();
    uint32 buttonMask = 0u;
    uint32 joystickButtonMask = 0u; 

#ifndef SYS_BUILD_MASTER
    uint32 lastTimingTime = lastTime;
    uint32 timingFrameCount = 0u;
#endif

    SDL_JoystickEventState( SDL_ENABLE );

    SDL_Joystick* pJoystick0 = SDL_JoystickOpen( 0 );
    SYS_USE_ARGUMENT(pJoystick0);

    int16 joystickAxis0 = 0;
    int16 joystickAxis1 = 0;

    float2 mousePos;
    float2_set(&mousePos, 0.0f, 0.0f);

    int leftMouseDown=0;
    int leftMousePressed=0;
    int rightMouseDown=0;
    int rightMousePressed=0u;

    int quit = 0;
    do
    {
        uint32 currentTime = SDL_GetTicks();

        const float timeStep = ( float )( currentTime - lastTime ) / 1000.0f;
        lastTime = currentTime;

#ifndef SYS_BUILD_MASTER
        if( currentTime - lastTimingTime > 500u )
        {
            const float timingTimeSpan = ( float )( currentTime - lastTimingTime ) / 1000.0f;
            const float currentFps = ( float )( timingFrameCount ) / timingTimeSpan;

            char windowTitle[ 100u ];
            sprintf( windowTitle, "fps=%f cb=%i", currentFps, s_callbackCount );
            SDL_WM_SetCaption( windowTitle, 0 );
    
            lastTimingTime = currentTime;
            timingFrameCount = 0u;
        }
#endif

        // get local user input:
        SDL_Event event;
        while( SDL_PollEvent( &event ) )
        {
            switch( event.type )
            {
            case SDL_JOYAXISMOTION:
                if( event.jaxis.axis == 0u )
                {
                    joystickAxis0 = event.jaxis.value;
                }
                else if( event.jaxis.axis == 1u )
                {
                    joystickAxis1 = event.jaxis.value;
                }
                break;

            case SDL_JOYBUTTONDOWN:
                if( event.jbutton.button == 0 )
                {
                    updateButtonMask( &joystickButtonMask, ButtonMask_PlaceBomb, 1 );
                }
                break;

            case SDL_JOYBUTTONUP:
                if( event.jbutton.button == 0 )
                {
                    updateButtonMask( &joystickButtonMask, ButtonMask_PlaceBomb, 0 );
                }
                break;

            case SDL_MOUSEMOTION:
                float2_set(&mousePos, (float)event.motion.x, (float)event.motion.y);
                break;

            case SDL_MOUSEBUTTONDOWN:
            SYS_TRACE_DEBUG("down=%i\n", event.button.button);
                if( event.button.button == 1 )
                {
                    leftMouseDown = 1;
                    leftMousePressed = 1;
                }
                else if( event.button.button == 3)
                {
                    rightMouseDown = 1;
                    rightMousePressed = 1;
                }
                break;

            case SDL_MOUSEBUTTONUP:
                if(event.button.button == 1)
                {
                    leftMouseDown = 0;
                }
                else if(event.button.button == 3)
                {
                    rightMouseDown = 0;
                }
                break;

            case SDL_KEYDOWN:
            case SDL_KEYUP:
				{
					const int ctrlPressed = ( event.key.keysym.mod & KMOD_CTRL ) != 0;

					switch( event.key.keysym.sym )
					{
					case SDLK_ESCAPE:
						quit = 1;
						break;

					case SDLK_LEFT:
						updateButtonMask( &buttonMask, ctrlPressed ? ButtonMask_CtrlLeft : ButtonMask_Left, event.type == SDL_KEYDOWN );
						break;

					case SDLK_RIGHT:
						updateButtonMask( &buttonMask, ctrlPressed ? ButtonMask_CtrlRight : ButtonMask_Right, event.type == SDL_KEYDOWN );
						break;

					case SDLK_UP:
						updateButtonMask( &buttonMask, ctrlPressed ? ButtonMask_CtrlUp : ButtonMask_Up, event.type == SDL_KEYDOWN );
						break;

					case SDLK_DOWN:
						updateButtonMask( &buttonMask, ctrlPressed ? ButtonMask_CtrlDown : ButtonMask_Down, event.type == SDL_KEYDOWN );
						break;

					case SDLK_SPACE:
						updateButtonMask( &buttonMask, ButtonMask_PlaceBomb, event.type == SDL_KEYDOWN );
						break;

					case SDLK_c:
						updateButtonMask( &buttonMask, ButtonMask_Client, event.type == SDL_KEYDOWN );
						break;

					case SDLK_s:
						updateButtonMask( &buttonMask, ButtonMask_Server, event.type == SDL_KEYDOWN );
						break;

					case SDLK_l:
						updateButtonMask( &buttonMask, ButtonMask_Leave, event.type == SDL_KEYDOWN );
						break;

					default:
						break;
					}
				}
                break;

            case SDL_QUIT:
                quit = 1;
                break;
            }
        }
        
        updateButtonMaskFromJoystick( &joystickButtonMask, ButtonMask_Right, joystickAxis0, 16000 );
        updateButtonMaskFromJoystick( &joystickButtonMask, ButtonMask_Left, -joystickAxis0, 16000 );
        updateButtonMaskFromJoystick( &joystickButtonMask, ButtonMask_Down, joystickAxis1, 3200 );
        updateButtonMaskFromJoystick( &joystickButtonMask, ButtonMask_Up, -joystickAxis1, 3200 );

#ifdef FONT_EDITOR
        static uint currentChar = '0';
        static uint dataChar = '\0';
        static float2 charPoints[ 128u ];
        static uint charPointCount = 0u;
        static uint32 lastButtonMask = 0u;
        static int currentPointIndex = -1;
        static float2 oldMousePagePos;

        const uint32 buttonPressMask = buttonMask & ~lastButtonMask;
        lastButtonMask = buttonMask;

        float2 mousePagePos;
        mousePagePos.x=64.0f*mousePos.x/(float)ScreenWidth;
        mousePagePos.y=36.0f+-36.0f*mousePos.y/(float)ScreenHeight;

        if( buttonPressMask & ButtonMask_Right )
        {
            currentChar=font_getNextGlyphCharCode(currentChar,1);
        }
        if( buttonPressMask & ButtonMask_Left )
        {
            currentChar=font_getNextGlyphCharCode(currentChar,-1);
        }

        if( currentChar != dataChar )
        {
            if( dataChar != '\0' )
            {
                char filename[128u];
                sprintf(filename,"./source/font/char_%i.h",dataChar);
                SYS_TRACE_DEBUG("writing char to file '%s'\n", filename);
                FILE* pFile=fopen(filename, "w");
                if(pFile)
                {
                    fprintf(pFile,"static const float2 s_points_%i[] =\n{\n",dataChar);
                    for( uint i=0u;i<charPointCount;++i)
                    {
                        fprintf(pFile,"\t{%ff,%ff},\n",charPoints[i].x,charPoints[i].y);
                    }
                    fprintf(pFile,"};\n\n");
                    fclose(pFile);
                }
                else
                {
                    SYS_TRACE_ERROR("Could not open file '%s'\n", filename);
                }
            }

            const FontGlyph* pGlyph=font_getGlyph((uint)currentChar);
            if(pGlyph)
            {
                charPointCount = uint_min(SYS_COUNTOF(charPoints),pGlyph->pointCount);
                memcpy(charPoints,pGlyph->pPoints,charPointCount*sizeof(float2));
                dataChar = currentChar;
            }
            else
            {
                charPointCount = 0u;
            }
            currentPointIndex = -1;
        }
        if( dataChar && ( buttonPressMask & ButtonMask_Down ) )
        {
            // add a point:
            if(charPointCount>0)
            {
                charPointCount--;
            }
        }
        if( dataChar && ( buttonPressMask & ButtonMask_Up ) )
        {
            // add a point:
            if(charPointCount<SYS_COUNTOF(charPoints))
            {
                float2_set(&charPoints[charPointCount],0.0f,0.0f);
                charPointCount++;
            }
        }

        if( renderer_isPageDone() )
        {
            // new page:
            renderer_flipPage();

            renderer_setPen( Pen_Font );

/*            const float2 worldOffset = { 32.0f, 16.0f };
            const float2 position = { 0.0f, 0.0f };*/
            
            renderer_setVariance( 0.0f );
            renderer_setTransform( 0 );

            const float fontSize=3.0f;

            float2 textPos;
            float2_set(&textPos,32.0f,16.0f);

            if( charPointCount > 0u )
            {
                float2x3 transform;
                float2x2_identity(&transform.rot);
                float2x2_scale1f(&transform.rot,&transform.rot,fontSize);
                transform.pos=textPos;

                renderer_setTransform( &transform );
                renderer_addQuadraticStroke(charPoints,charPointCount);

                transform.pos.x -= 10.0f;
                renderer_setTransform( &transform );
                renderer_addQuadraticStroke(charPoints,charPointCount);
            }

            // draw control points:
            const float cpSize=0.5f;
            int inRangePoint=-1;
            for(uint i = 0u; i < charPointCount; ++i)
            {
                float2 pos;
                float2_set(&pos,32.0f,16.0f);
                float2_addScaled1f(&pos,&pos,&charPoints[i],fontSize);
                
                const int inRange = float2_distance(&mousePagePos,&pos)<cpSize;
                if( inRange && inRangePoint==-1)
                {
                    inRangePoint=(int)i;
                }
                if(currentPointIndex==-1&&inRange&&leftMousePressed)
                {
                    currentPointIndex=(int)i;
                }
                else if(currentPointIndex!=-1)
                {
                    if(!leftMouseDown)
                    {
                        currentPointIndex=-1;
                    }
                    else if( currentPointIndex==(int)i )
                    {
                        // move cp to be under the mouse cursor:
                        float2 newCpPos;
                        float2_sub(&newCpPos,&mousePagePos,&textPos);
                        float2_scale1f(&charPoints[i],&newCpPos,1.0f/fontSize);
                    }
                }

                float3 color;
                if((int)i==currentPointIndex)
                {
                    float3_set(&color,0.2f,1.0f,0.2f);
                }
                else if(inRange)
                {
                    float3_set(&color,0.5f,0.5f,0.2f);
                }
                else
                {
                    float3_set(&color,0.8f,0.2f,0.2f);
                }
                renderer_drawCircle(&pos,cpSize,&color);
            }
            oldMousePagePos=mousePagePos;
            leftMousePressed=0;
            rightMousePressed=0;
            float2_set(&textPos,5.0f,4.0f);
            font_drawText(&textPos,1.0f,0.0f,"0123456789A" );
        }
        renderer_updatePage( timeStep );

        FrameData frame;
        //memset( &frame, 0u, sizeof( frame ) );
        //frame.time = s_game.gameTime;
        //frame.playerPos = s_game.player[ 0u ].position;
        renderer_drawFrame( &frame );
                
#elif defined( TEST_RENDERER )
        if( renderer_isPageDone() )
        {
            // new page:
            renderer_flipPage();

            /*float2 points[] =
            { 
                { -4.0f,  0.0f },
                { -4.0f, -4.0f },
                {  0.0f, -4.0f },
                {  4.0f, -4.0f },
                {  4.0f,  0.0f },
                {  4.0f,  4.0f },
                {  0.0f,  4.0f },
                { -4.0f,  4.0f },
                { -4.0f,  0.0f }
                { -0.2f,  1.0f }
            };*/

            renderer_setPen( Pen_DebugGreen );
            const float2 worldOffset = { 32.0f, 16.0f };
            const float2 position = { 0.0f, 0.0f };

            float2x3 bombTransform;
            float2x2_rotationY( &bombTransform.rot, 0.0f );
            float2x2_scale1f( &bombTransform.rot, &bombTransform.rot, 1.0f );
            float2_add( &bombTransform.pos, &position, &worldOffset );

            renderer_setTransform( &bombTransform );

            //renderer_addQuadraticStroke(&points[0u],&points[1u],&points[2u]);
            //renderer_addQuadraticStroke(points,SYS_COUNTOF(points));

            float2 textPos;
            float2_set(&textPos,5.0f,4.0f); 
            font_drawText(&textPos,2.0f,0.0f,"P");
        }
        renderer_updatePage( timeStep );

        FrameData frame;
        //memset( &frame, 0u, sizeof( frame ) );
        //frame.time = s_game.gameTime;
        //frame.playerPos = s_game.player[ 0u ].position;
        renderer_drawFrame( &frame );
#else
        renderer_setVariance(0.0f);
        GameInput gameInput;
        memset( &gameInput, 0u, sizeof( gameInput ) );
        gameInput.timeStep = timeStep;
        gameInput.buttonMask = buttonMask | joystickButtonMask;

        game_update( &gameInput );

        game_render();
#endif
        SDL_GL_SwapBuffers();

#ifndef SYS_BUILD_MASTER
        timingFrameCount++;
#endif
    }
    while( !quit );

    // :TODO: nicer fade out..
    SDL_PauseAudio( 1 );

    game_done();
}
Beispiel #6
0
int sync_rx(struct bladerf *dev, void *samples, unsigned num_samples,
            struct bladerf_metadata *user_meta, unsigned int timeout_ms)
{
    struct bladerf_sync *s = dev->sync[BLADERF_MODULE_RX];
    struct buffer_mgmt *b;

    int status = 0;
    bool exit_early = false;
    bool copied_data = false;
    unsigned int samples_returned = 0;
    uint8_t *samples_dest = (uint8_t*)samples;
    uint8_t *buf_src = NULL;
    unsigned int samples_to_copy = 0;
    unsigned int samples_per_buffer = 0;
    uint64_t target_timestamp = UINT64_MAX;

    if (s == NULL || samples == NULL) {
        log_debug("NULL pointer passed to %s\n", __FUNCTION__);
        return BLADERF_ERR_INVAL;
    } else if (s->stream_config.format == BLADERF_FORMAT_SC16_Q11_META) {
        if (user_meta == NULL) {
            log_debug("NULL metadata pointer passed to %s\n", __FUNCTION__);
            return BLADERF_ERR_INVAL;
        } else {
            user_meta->status = 0;
            target_timestamp = user_meta->timestamp;
        }
    }

    b = &s->buf_mgmt;
    samples_per_buffer = s->stream_config.samples_per_buffer;

    log_verbose("%s: Requests %u samples.\n", __FUNCTION__, num_samples);

    while (!exit_early && samples_returned < num_samples && status == 0) {

        switch (s->state) {
            case SYNC_STATE_CHECK_WORKER: {
                int stream_error;
                sync_worker_state worker_state =
                    sync_worker_get_state(s->worker, &stream_error);

                /* Propagate stream error back to the caller.
                 * They can call this function again to restart the stream and
                 * try again.
                 */
                if (stream_error != 0) {
                    status = stream_error;
                } else {
                    if (worker_state == SYNC_WORKER_STATE_IDLE) {
                        log_debug("%s: Worker is idle. Going to reset buf "
                                  "mgmt.\n", __FUNCTION__);
                        s->state = SYNC_STATE_RESET_BUF_MGMT;
                    } else if (worker_state == SYNC_WORKER_STATE_RUNNING) {
                        s->state = SYNC_STATE_WAIT_FOR_BUFFER;
                    } else {
                        status = BLADERF_ERR_UNEXPECTED;
                        log_debug("%s: Unexpected worker state=%d\n",
                                __FUNCTION__, worker_state);
                    }
                }

                break;
            }

            case SYNC_STATE_RESET_BUF_MGMT:
                MUTEX_LOCK(&b->lock);
                /* When the RX stream starts up, it will submit the first T
                 * transfers, so the consumer index must be reset to 0 */
                b->cons_i = 0;
                MUTEX_UNLOCK(&b->lock);
                log_debug("%s: Reset buf_mgmt consumer index\n", __FUNCTION__);
                s->state = SYNC_STATE_START_WORKER;
                break;


            case SYNC_STATE_START_WORKER:
                sync_worker_submit_request(s->worker, SYNC_WORKER_START);

                status = sync_worker_wait_for_state(
                                                s->worker,
                                                SYNC_WORKER_STATE_RUNNING,
                                                SYNC_WORKER_START_TIMEOUT_MS);

                if (status == 0) {
                    s->state = SYNC_STATE_WAIT_FOR_BUFFER;
                    log_debug("%s: Worker is now running.\n", __FUNCTION__);
                } else {
                    log_debug("%s: Failed to start worker, (%d)\n",
                              __FUNCTION__, status);
                }
                break;

            case SYNC_STATE_WAIT_FOR_BUFFER:
                MUTEX_LOCK(&b->lock);

                /* Check the buffer state, as the worker may have produced one
                 * since we last queried the status */
                if (b->status[b->cons_i] == SYNC_BUFFER_FULL) {
                    s->state = SYNC_STATE_BUFFER_READY;
                    log_verbose("%s: buffer %u is ready to consume\n",
                                __FUNCTION__, b->cons_i);
                } else {
                    status = wait_for_buffer(b, timeout_ms,
                                             __FUNCTION__, b->cons_i);

                    if (status == 0) {
                        if (b->status[b->cons_i] != SYNC_BUFFER_FULL) {
                            s->state = SYNC_STATE_CHECK_WORKER;
                        } else {
                            s->state = SYNC_STATE_BUFFER_READY;
                            log_verbose("%s: buffer %u is ready to consume\n",
                                        __FUNCTION__, b->cons_i);
                        }
                    }
                }

                MUTEX_UNLOCK(&b->lock);
                break;

            case SYNC_STATE_BUFFER_READY:
                MUTEX_LOCK(&b->lock);
                b->status[b->cons_i] = SYNC_BUFFER_PARTIAL;
                b->partial_off = 0;
                MUTEX_UNLOCK(&b->lock);

                switch (s->stream_config.format) {
                    case BLADERF_FORMAT_SC16_Q11:
                        s->state = SYNC_STATE_USING_BUFFER;
                        break;

                    case BLADERF_FORMAT_SC16_Q11_META:
                        s->state = SYNC_STATE_USING_BUFFER_META;
                        s->meta.curr_msg_off = 0;
                        s->meta.msg_num = 0;
                        break;

                    default:
                        assert(!"Invalid stream format");
                        status = BLADERF_ERR_UNEXPECTED;
                }
                break;

            case SYNC_STATE_USING_BUFFER: /* SC16Q11 buffers w/o metadata */
                MUTEX_LOCK(&b->lock);

                buf_src = (uint8_t*)b->buffers[b->cons_i];

                samples_to_copy = uint_min(num_samples - samples_returned,
                                           samples_per_buffer - b->partial_off);

                memcpy(samples_dest + samples2bytes(s, samples_returned),
                       buf_src + samples2bytes(s, b->partial_off),
                       samples2bytes(s, samples_to_copy));

                b->partial_off += samples_to_copy;
                samples_returned += samples_to_copy;

                log_verbose("%s: Provided %u samples to caller\n",
                            __FUNCTION__, samples_to_copy);

                /* We've finished consuming this buffer and can start looking
                 * for available samples in the next buffer */
                if (b->partial_off >= samples_per_buffer) {

                    /* Check for symptom of out-of-bounds accesses */
                    assert(b->partial_off == samples_per_buffer);

                    advance_rx_buffer(b);
                    s->state = SYNC_STATE_WAIT_FOR_BUFFER;
                }

                MUTEX_UNLOCK(&b->lock);
                break;


            case SYNC_STATE_USING_BUFFER_META: /* SC16Q11 buffers w/ metadata */
                MUTEX_LOCK(&b->lock);

                switch (s->meta.state) {
                    case SYNC_META_STATE_HEADER:

                        assert(s->meta.msg_num < s->meta.msg_per_buf);

                        buf_src = (uint8_t*)b->buffers[b->cons_i];

                        s->meta.curr_msg =
                            buf_src + dev->msg_size * s->meta.msg_num;

                        s->meta.msg_timestamp =
                            metadata_get_timestamp(s->meta.curr_msg);

                        s->meta.msg_flags =
                            metadata_get_flags(s->meta.curr_msg);

                        s->meta.curr_msg_off = 0;

                        /* We've encountered a discontinuity and need to return
                         * what we have so far, setting the status flags */
                        if (copied_data &&
                            s->meta.msg_timestamp != s->meta.curr_timestamp) {

                            user_meta->status |= BLADERF_META_STATUS_OVERRUN;
                            exit_early = true;
                            log_debug("Sample discontinuity detected @ "
                                      "buffer %u, message %u: Expected t=%llu, "
                                      "got t=%llu\n",
                                      b->cons_i, s->meta.msg_num,
                                      (unsigned long long)s->meta.curr_timestamp,
                                      (unsigned long long)s->meta.msg_timestamp);

                        } else {
                            log_verbose("Got header for message %u: "
                                        "t_new=%u, t_old=%u\n",
                                        s->meta.msg_num,
                                        s->meta.msg_timestamp,
                                        s->meta.curr_timestamp);
                        }

                        s->meta.curr_timestamp = s->meta.msg_timestamp;
                        s->meta.state = SYNC_META_STATE_SAMPLES;
                        break;

                    case SYNC_META_STATE_SAMPLES:
                        if (!copied_data &&
                            (user_meta->flags & BLADERF_META_FLAG_RX_NOW) == 0 &&
                            target_timestamp < s->meta.curr_timestamp) {

                            log_debug("Current timestamp is %llu, "
                                      "target=%llu (user=%llu)\n",
                                      (unsigned long long)s->meta.curr_timestamp,
                                      (unsigned long long)target_timestamp,
                                      (unsigned long long)user_meta->timestamp);

                            status = BLADERF_ERR_TIME_PAST;
                        } else if ((user_meta->flags & BLADERF_META_FLAG_RX_NOW) ||
                                   target_timestamp == s->meta.curr_timestamp) {

                            /* Copy the request amount up to the end of a
                             * this message in the current buffer */
                            samples_to_copy =
                                uint_min(num_samples - samples_returned,
                                         left_in_msg(s));

                            memcpy(samples_dest + samples2bytes(s, samples_returned),
                                   s->meta.curr_msg +
                                        METADATA_HEADER_SIZE +
                                        samples2bytes(s, s->meta.curr_msg_off),
                                   samples2bytes(s, samples_to_copy));

                            samples_returned += samples_to_copy;
                            s->meta.curr_msg_off += samples_to_copy;

                            if (!copied_data &&
                                (user_meta->flags & BLADERF_META_FLAG_RX_NOW)) {

                                /* Provide the user with the timestamp at the
                                 * first returned sample when the
                                 * NOW flag has been provided */
                                user_meta->timestamp = s->meta.curr_timestamp;
                                log_verbose("Updated user meta timestamp with: "
                                            "%llu\n", (unsigned long long)
                                            user_meta->timestamp);
                            }

                            copied_data = true;
                            s->meta.curr_timestamp += samples_to_copy;

                            /* We've begun copying samples, so our target will
                             * just keep tracking the current timestamp. */
                            target_timestamp = s->meta.curr_timestamp;

                            log_verbose("After copying samples, t=%llu\n",
                                        (unsigned long long)s->meta.curr_timestamp);

                            if (left_in_msg(s) == 0) {
                                assert(s->meta.curr_msg_off == s->meta.samples_per_msg);

                                s->meta.state = SYNC_META_STATE_HEADER;
                                s->meta.msg_num++;

                                if (s->meta.msg_num >= s->meta.msg_per_buf) {
                                    assert(s->meta.msg_num == s->meta.msg_per_buf);
                                    advance_rx_buffer(b);
                                    s->meta.msg_num = 0;
                                    s->state = SYNC_STATE_WAIT_FOR_BUFFER;
                                }
                            }

                        } else {
                            const uint64_t time_delta =
                                target_timestamp - s->meta.curr_timestamp;

                            uint64_t left_in_buffer =
                                (uint64_t) s->meta.samples_per_msg *
                                    (s->meta.msg_per_buf - s->meta.msg_num);

                            /* Account for current position in buffer */
                            left_in_buffer -= s->meta.curr_msg_off;

                            if (time_delta >= left_in_buffer) {
                                /* Discard the remainder of this buffer */
                                advance_rx_buffer(b);
                                s->state = SYNC_STATE_WAIT_FOR_BUFFER;
                                s->meta.state = SYNC_META_STATE_HEADER;

                                log_verbose("%s: Discarding rest of buffer.\n",
                                            __FUNCTION__);

                            } else if (time_delta <= left_in_msg(s)) {
                                /* Fast forward within the current message */
                                assert(time_delta <= SIZE_MAX);
                                s->meta.curr_msg_off += (size_t) time_delta;
                                s->meta.curr_timestamp += time_delta;

                                log_verbose("%s: Seeking within message (t=%llu)\n",
                                            __FUNCTION__,
                                            s->meta.curr_timestamp);
                            } else {
                                s->meta.state = SYNC_META_STATE_HEADER;

                                s->meta.msg_num += timestamp_to_msg(s, time_delta);

                                log_verbose("%s: Seeking to message %u.\n",
                                            __FUNCTION__, s->meta.msg_num);
                            }
                        }
                        break;

                    default:
                        assert(!"Invalid state");
                        status = BLADERF_ERR_UNEXPECTED;
                }

                MUTEX_UNLOCK(&b->lock);
                break;
        }
    }

    if (user_meta) {
        user_meta->actual_count = samples_returned;
    }

    return status;
}
Beispiel #7
0
static int tx_task_exec_running(struct rxtx_data *tx, struct cli_state *s)
{
    int status = 0;
    unsigned int samples_per_buffer;
    int16_t *tx_buffer;
    struct tx_params *tx_params = tx->params;
    unsigned int repeats_remaining;
    unsigned int delay_us;
    unsigned int delay_samples;
    unsigned int delay_samples_remaining;
    bool repeat_infinite;
    unsigned int timeout_ms;
    unsigned int sample_rate;

    enum state { INIT, READ_FILE, DELAY, PAD_TRAILING, DONE };
    enum state state = INIT;

    /* Fetch the parameters required for the TX operation */
    MUTEX_LOCK(&tx->param_lock);
    repeats_remaining = tx_params->repeat;
    delay_us = tx_params->repeat_delay;
    MUTEX_UNLOCK(&tx->param_lock);

    repeat_infinite = (repeats_remaining == 0);

    MUTEX_LOCK(&tx->data_mgmt.lock);
    samples_per_buffer = (unsigned int)tx->data_mgmt.samples_per_buffer;
    timeout_ms = tx->data_mgmt.timeout_ms;
    MUTEX_UNLOCK(&tx->data_mgmt.lock);

    status = bladerf_get_sample_rate(s->dev, tx->module, &sample_rate);
    if (status != 0) {
        set_last_error(&tx->last_error, ETYPE_BLADERF, status);
        return CLI_RET_LIBBLADERF;
    }

    /* Compute delay time as a sample count */
    delay_samples = (unsigned int)((uint64_t)sample_rate * delay_us / 1000000);
    delay_samples_remaining = delay_samples;

    /* Allocate a buffer to hold each block of samples to transmit */
    tx_buffer = (int16_t*) malloc(samples_per_buffer * 2 * sizeof(int16_t));
    if (tx_buffer == NULL) {
        status = CLI_RET_MEM;
        set_last_error(&tx->last_error, ETYPE_ERRNO,
                       errno == 0 ? ENOMEM : errno);
    }

    /* Keep writing samples while there is more data to send and no failures
     * have occurred */
    while (state != DONE && status == 0) {

        unsigned char requests;
        unsigned int buffer_samples_remaining = samples_per_buffer;
        int16_t *tx_buffer_current = tx_buffer;

        /* Stop stream on STOP or SHUTDOWN, but only clear STOP. This will keep
         * the SHUTDOWN request around so we can read it when determining
         * our state transition */
        requests = rxtx_get_requests(tx, RXTX_TASK_REQ_STOP);
        if (requests & (RXTX_TASK_REQ_STOP | RXTX_TASK_REQ_SHUTDOWN)) {
            break;
        }

        /* Keep adding to the buffer until it is full or a failure occurs */
        while (buffer_samples_remaining > 0 && status == 0 && state != DONE) {
            size_t samples_populated = 0;

            switch (state) {
                case INIT:
                case READ_FILE:

                    MUTEX_LOCK(&tx->file_mgmt.file_lock);

                    /* Read from the input file */
                    samples_populated = fread(tx_buffer_current,
                                              2 * sizeof(int16_t),
                                              buffer_samples_remaining,
                                              tx->file_mgmt.file);

                    assert(samples_populated <= UINT_MAX);

                    /* If the end of the file was reached, determine whether
                     * to delay, re-read from the file, or pad the rest of the
                     * buffer and finish */
                    if (feof(tx->file_mgmt.file)) {
                        repeats_remaining--;

                        if ((repeats_remaining > 0) || repeat_infinite) {
                            if (delay_samples != 0) {
                                delay_samples_remaining = delay_samples;
                                state = DELAY;
                            }
                        }
                        else {
                            state = PAD_TRAILING;
                        }

                        /* Clear the EOF condition and rewind the file */
                        clearerr(tx->file_mgmt.file);
                        rewind(tx->file_mgmt.file);
                    }

                    /* Check for errors */
                    else if (ferror(tx->file_mgmt.file)) {
                        status = errno;
                        set_last_error(&tx->last_error, ETYPE_ERRNO, status);
                    }

                    MUTEX_UNLOCK(&tx->file_mgmt.file_lock);
                    break;

                case DELAY:
                    /* Insert as many zeros as are necessary to realize the
                     * specified repeat delay */
                    samples_populated = uint_min(buffer_samples_remaining,
                                                 delay_samples_remaining);

                    memset(tx_buffer_current, 0,
                           samples_populated * 2 * sizeof(uint16_t));

                    delay_samples_remaining -= (unsigned int)samples_populated;

                    if (delay_samples_remaining == 0) {
                        state = READ_FILE;
                    }
                    break;

                case PAD_TRAILING:
                    /* Populate the remainder of the buffer with zeros */
                    memset(tx_buffer_current, 0,
                            buffer_samples_remaining * 2 * sizeof(uint16_t));

                    state = DONE;
                    break;

                case DONE:
                default:
                    break;
            }

            /* Advance the buffer pointer.
             * Remember, two int16_t's make up 1 sample in the SC16Q11 format */
            buffer_samples_remaining -= (unsigned int)samples_populated;
            tx_buffer_current += (2 * samples_populated);
        }

        /* If there were no errors, transmit the data buffer */
        if (status == 0) {
            bladerf_sync_tx(s->dev, tx_buffer, samples_per_buffer, NULL,
                            timeout_ms);
        }
    }

    free(tx_buffer);
    return status;
}
Beispiel #8
0
static int run(struct bladerf *dev, struct app_params *p,
               const struct test_case *t)
{
    int status, status_out, status_wait;
    unsigned int samples_left;
    size_t i;
    struct bladerf_metadata meta;
    int16_t *samples, *buf;

    samples = calloc(2 * sizeof(int16_t), t->burst_len + 2);
    if (samples == NULL) {
        perror("malloc");
        return BLADERF_ERR_MEM;
    }

    /* Leave the last two samples zero */
    for (i = 0; i < (2 * t->burst_len); i += 2) {
        samples[i] = samples[i + 1] = MAGNITUDE;
    }

    memset(&meta, 0, sizeof(meta));

    status = perform_sync_init(dev, BLADERF_MODULE_TX, t->buf_len, p);
    if (status != 0) {
        goto out;
    }

    status = bladerf_get_timestamp(dev, BLADERF_MODULE_TX, &meta.timestamp);
    if (status != 0) {
        fprintf(stderr, "Failed to get timestamp: %s\n",
                bladerf_strerror(status));
        goto out;
    } else {
        printf("Initial timestamp: 0x%016"PRIx64"\n", meta.timestamp);
    }

    meta.timestamp += 200000;


    for (i = 0; i < t->iterations && status == 0; i++) {
        meta.flags = BLADERF_META_FLAG_TX_BURST_START;
        samples_left = t->burst_len + 2;
        buf = samples;


        printf("Sending burst @ %llu\n", (unsigned long long) meta.timestamp);

        while (samples_left && status == 0) {
            unsigned int to_send = uint_min(p->buf_size, samples_left);

            if (to_send == samples_left) {
                meta.flags |= BLADERF_META_FLAG_TX_BURST_END;
            } else {
                meta.flags &= ~BLADERF_META_FLAG_TX_BURST_END;
            }

            status = bladerf_sync_tx(dev, buf, to_send, &meta, 10000); //p->timeout_ms);
            if (status != 0) {
                fprintf(stderr, "TX failed @ iteration (%u) %s\n",
                        (unsigned int )i, bladerf_strerror(status));
            }

            meta.flags &= ~BLADERF_META_FLAG_TX_BURST_START;
            samples_left -= to_send;
            buf += 2 * to_send;
        }

        meta.timestamp += (t->burst_len + t->gap_len - 2);
    }

    printf("Waiting for samples to finish...\n");
    fflush(stdout);

    /* Wait for samples to be transmitted before shutting down the TX module */
    status_wait = wait_for_timestamp(dev, BLADERF_MODULE_TX,
                                     meta.timestamp - t->gap_len + 2,
                                     3000);
    if (status_wait != 0) {
        status = first_error(status, status_wait);
        fprintf(stderr, "Failed to wait for TX to finish: %s\n",
                bladerf_strerror(status_wait));
    }

out:
    status_out = bladerf_enable_module(dev, BLADERF_MODULE_TX, false);
    if (status_out != 0) {
        fprintf(stderr, "Failed to disable TX module: %s\n",
                bladerf_strerror(status));
    } else {
        printf("Done waiting.\n");
        fflush(stdout);
    }

    status = first_error(status, status_out);

    free(samples);
    return status;
}