// // Retrieve a recors from disk and check it's CRC // void dvb_config_retrieve_from_disk( sys_config *cfg ) { FILE *fp; SysConfigRecord rd; int success = -1; dvb_config_create(); if((fp=fopen(dvb_config_get_path("datvexpress.cfg"),"r")) > 0) { size_t size = fread( &rd, 1, sizeof(SysConfigRecord), fp ); if( size == sizeof(SysConfigRecord)) { // Check the CRC to make sure it is valid unsigned long crc = dvb_crc32_calc((unsigned char*)&rd.cfg, sizeof(sys_config)); if( crc == rd.crc.crc ) { memcpy( cfg, &rd.cfg, sizeof(sys_config)); success = 0; } } //cfg->dvbs2_fmt.constellation = M_QPSK; //cfg->dvb_mode = MODE_DVBS; fclose(fp); } if( success != 0 ) { loggerf("Using default Settings"); dvb_default_configuration( cfg ); dvb_config_save_to_disk( cfg ); } }
int serOpenDev ( serDevT* dev ) { #ifdef ENABLE_TIMEPPS pps_params_t ppsparams; int ppsmode; #endif dev->fd = open ( dev->dev, O_RDONLY|O_NOCTTY ); switch ( dev->mode ) { #ifdef ENABLE_TIMEPPS case SERPORT_MODE_TIMEPPS: if ( time_pps_create ( dev->fd, &dev->ppshandle ) == -1 ) return -1; if ( time_pps_getparams ( dev->ppshandle, &ppsparams ) == -1 ) return -1; ppsparams.mode |= PPS_TSFMT_TSPEC | PPS_CAPTUREBOTH; if ( time_pps_setparams ( dev->ppshandle, &ppsparams ) == -1 ) return -1; if ( time_pps_getcap ( dev->ppshandle, &ppsmode ) == -1 ) return -1; //NOTE: these should probably be error cases, but the code is still experimental and //the PPS support I've used also seems to have problems if ( ! (ppsmode | PPS_CAPTUREASSERT) ) loggerf ( LOGGER_NOTE, "Warning: PPS_CAPTUREASSERT not supported\n" ); if ( ! (ppsmode | PPS_CAPTURECLEAR) ) loggerf ( LOGGER_NOTE, "Warning: PPS_CAPTURECLEAR not supported\n" ); //!!! no point using this - too many problems //1. linux doesn't report PPS_CANWAIT, but can //2. FreeBSD does report PPS_CANWAIT, but can't //(unless its me reading the docs backwards?) // if ( ! (ppsmode | PPS_CANWAIT) ) // loggerf ( LOGGER_NOTE, "Warning: PPS_CANWAIT not supported (linux lies)\n" ); #endif } return dev->fd; }
int wwvbDecode ( clkInfoT* clock, time_f minstart ) { struct tm dectime; time_t dectimet; wwvbDump ( clock ); if ( !DATA_OK(1) ) return -1; memset ( &dectime, 0, sizeof(dectime) ); dectime.tm_year = wwvbGetBCD ( clock, 44, 10 ) + CENTURY - 1900; dectime.tm_mon = 1; dectime.tm_mday = wwvbGetBCD ( clock, 22, 12 ); dectime.tm_hour = wwvbGetBCD ( clock, 12, 7 ); dectime.tm_min = wwvbGetBCD ( clock, 1, 8 ); dectime.tm_sec = 0; dectime.tm_isdst = 0; //time is always UTC... (although there are bits for summer time) //NOTE: decoding this depends on a mktime() which will normalize day numbers correctly if ( (dectime.tm_mday < 1) || (dectime.tm_mday > 366) ) return -1; if ( dectime.tm_hour > 23 ) return -1; if ( dectime.tm_min > 60 ) return -1; loggerf ( LOGGER_DEBUG, "WWVB time: %04d-%03d %02d:%02d %s%s\n", dectime.tm_year+1900, dectime.tm_mday, dectime.tm_hour, dectime.tm_min, GET(55)?" leap year":"", GET(56)?" leap second soon":"" ); // setenv ( "TZ", "", 1 ); // // dectimet = mktime ( &dectime ); dectimet = UTCtime ( &dectime ); if ( dectimet == (time_t)(-1) ) return -1; clock->pctime = minstart; clock->radiotime = dectimet + clock->fudgeoffset; clock->radioleap = GET(56) ? LEAP_ADDSECOND : LEAP_NOWARNING; clock->secondssincetime = 0; return 0; }
int serStoreDevStatusLines ( serDevT* dev, int lines, time_f timef ) { time_f diff = timef - dev->eventtime; if (diff < 0.05) { loggerf ( LOGGER_DEBUG, "serStoreDevStatusLines: pulse too short %f, filtering!\n", diff); return 0; } if ( lines != dev->curlines ) { dev->prevlines = dev->curlines; dev->curlines = lines; dev->eventtime = timef; return 1; } return 0; }
void wwvbDump ( clkInfoT* clock ) { int i; loggerf ( LOGGER_TRACE, "WWVB : " ); for ( i=0; i<60; i+=5 ) loggerf ( LOGGER_TRACE, "|%-4d", i ); loggerf ( LOGGER_TRACE, "\n" ); loggerf ( LOGGER_TRACE, "WWVB : " ); for ( i=0; i<60; i++ ) loggerf ( LOGGER_TRACE, "%c", DATA_OK(i)?(GET(i)?'1':'.'):' ' ); loggerf ( LOGGER_TRACE, "\n" ); }
void dvb_config_save_to_disk(sys_config *cfg) { FILE *fp; SysConfigRecord record; dvb_config_create(); if((fp=fopen(dvb_config_get_path("datvexpress.cfg"),"w"))>0) { // Create a CRC of the data and sve it along with the data record.crc.crc = dvb_crc32_calc((unsigned char*)cfg, sizeof(sys_config)); // Copy the cfg into the disk record structure memcpy( &record.cfg, cfg, sizeof(sys_config)); // Save fwrite(&record,sizeof(SysConfigRecord), 1, fp ); fclose(fp); } else { loggerf("Cannot save configuration file (check owner)"); } }
void shmStore ( shmTimeT* volatile shm, time_f radioclock, time_f localrecv, time_f time_err, int leap ) { struct timeval radioclocktv,localrecvtv; loggerf ( LOGGER_DEBUG, "shm: storing time "TIMEF_FORMAT" local "TIMEF_FORMAT" err "TIMEF_FORMAT" leap %d\n", radioclock, localrecv, time_err, leap ); time_f2timeval ( radioclock, &radioclocktv ); time_f2timeval ( localrecv, &localrecvtv ); shm->valid = 0; shm->mode = 1; shm->count++; shm->clockTimeStampSec = radioclocktv.tv_sec; shm->clockTimeStampUSec = radioclocktv.tv_usec; shm->receiveTimeStampSec = localrecvtv.tv_sec; shm->receiveTimeStampUSec = localrecvtv.tv_usec; shm->leap = leap; shm->precision = log(time_err)/log(2); shm->count++; shm->valid = 1; }
serLineT* serAddLine ( char* dev, int line, int mode ) { char fulldev[64]; serDevT* serdev; serLineT* serline; //allow for either full paths or /dev relative paths... if ( dev[0] == '/' ) { if ( strlen(dev) >= 64 ) { loggerf ( LOGGER_NOTE, "serAddLine(): dev too long\n" ); return NULL; } strcpy ( fulldev, dev ); } else { strcpy ( fulldev, "/dev/" ); if ( strlen(dev)+strlen(fulldev) >= 64 ) { loggerf ( LOGGER_NOTE, "serAddLine(): dev too long\n" ); return NULL; } strcat ( fulldev, dev ); } //make sure only one line bit is set... if ( line & (line-1) ) { loggerf ( LOGGER_NOTE, "serAddLine(): more than one line bit set\n" ); return NULL; } //try and find an existing device in the list... serdev = serDevHead; while ( serdev != NULL ) { if ( strcmp ( serdev->dev, fulldev ) == 0 ) break; serdev = serdev->next; } if ( serdev == NULL ) { //no existing device - create a new one.. serdev = safe_mallocz ( sizeof(serDevT) ); serdev->next = serDevHead; serDevHead = serdev; strcpy ( serdev->dev, fulldev ); serdev->mode = mode; serdev->modemlines = 0; serdev->fd = -1; } //make sure we're using it in the same mode... if ( serdev->mode != mode ) { loggerf ( LOGGER_NOTE, "serAddLine(): cannot add line for same device with different mode\n" ); return NULL; } //make sure we're not already monitoring this line... if ( serdev->modemlines & line ) { loggerf ( LOGGER_NOTE, "serAddLine(): cannot add modem status line more than once\n" ); return NULL; } //ok - we've got a valid device/line/mode combo... serdev->modemlines |= line; //create a new line entry... serline = safe_mallocz ( sizeof(serLineT) ); serline->next = serLineHead; serLineHead = serline; serline->dev = serdev; serline->line = line; return serline; }
int serWaitForSerialChange ( serDevT* dev ) { struct timeval tv; time_f timef; int i,ret; #ifdef ENABLE_TIMEPPS struct timespec timeout; pps_info_t ppsinfo; int ppslines; #endif #ifdef ENABLE_GPIO struct pollfd pollfds[1]; #endif if ( dev->modemlines == 0 ) return -1; switch ( dev->mode ) { case SERPORT_MODE_POLL: for ( i=0; i<10*1000; i++ ) { gettimeofday ( &tv, NULL ); timeval2time_f ( &tv, timef ); ret = serGetDevStatusLines ( dev, timef ); if ( ret < 0 ) return -1; if ( ret == 1 ) return 0; usleep ( 1000 ); } //timeout return -1; break; #ifdef ENABLE_GPIO case SERPORT_MODE_GPIO: pollfds[0].fd = dev->fd; pollfds[0].events = POLLERR; i = poll(pollfds, 1, 10000); /* timeout 10 seconds */ if (i != 1 && !(pollfds[0].revents & POLLERR) ) return -1; gettimeofday ( &tv, NULL ); timeval2time_f ( &tv, timef ); if ( serGetDevStatusLines ( dev, timef ) < 0 ) return -1; return 0; break; #endif #ifdef ENABLE_TIOCMIWAIT case SERPORT_MODE_IWAIT: signal ( SIGALRM, sigalrm ); alarm ( 10 ); if ( ioctl ( dev->fd, TIOCMIWAIT, dev->modemlines) != 0 ) return -1; gettimeofday ( &tv, NULL ); timeval2time_f ( &tv, timef ); signal ( SIGALRM, SIG_DFL ); alarm ( 0 ); if ( serGetDevStatusLines ( dev, timef ) < 0 ) return -1; return 0; break; #endif #ifdef ENABLE_TIMEPPS case SERPORT_MODE_TIMEPPS: timeout.tv_sec = 0; timeout.tv_nsec = 0; for ( i=0; i<10*100; i++ ) { if ( time_pps_fetch ( dev->ppshandle, PPS_TSFMT_TSPEC, &ppsinfo, &timeout ) == -1 ) { loggerf ( LOGGER_NOTE, "ppsfetch failed: %d\n", errno ); return -1; } if ( ppsinfo.assert_sequence != dev->ppslastassert ) { timespec2time_f ( &ppsinfo.assert_timestamp, timef ); ppslines = TIOCM_CD; //NOTE: assuming that pps support is on the DCD line dev->ppslastassert = ppsinfo.assert_sequence; if ( serStoreDevStatusLines ( dev, ppslines, timef ) < 0 ) return -1; return 0; } else if ( ppsinfo.clear_sequence != dev->ppslastclear ) { timespec2time_f ( &ppsinfo.clear_timestamp, timef ); ppslines = 0; dev->ppslastclear = ppsinfo.clear_sequence; if ( serStoreDevStatusLines ( dev, ppslines, timef ) < 0 ) return -1; return 0; } usleep ( 10000 ); } return -1; break; #endif } loggerf ( LOGGER_NOTE, "Error: serWaitForSerialChange(): mode not supported\n" ); //unknown serial port mode !! return -1; }
// // Set up both the audio and video capturing on the card // void an_configure_capture_card( void ) { struct v4l2_cropcap cropcap; struct v4l2_crop crop; struct v4l2_format fmt; sys_config info; int input; u32 pix_fmt; dvb_config_get( &info ); CLEAR(cropcap); CLEAR(crop); CLEAR(fmt); m_width = PAL_WIDTH_CAPTURE; m_height = PAL_HEIGHT_CAPTURE; // Set the cropping, ignore any errors cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(m_i_fd, VIDIOC_CROPCAP, &cropcap)==0) { crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; /* reset to default */ ioctl(m_i_fd, VIDIOC_S_CROP, &crop); } // // Analogue Video capture // pix_fmt = V4L2_PIX_FMT_YUV420; m_sws = NULL; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = m_width; fmt.fmt.pix.height = m_height; fmt.fmt.pix.pixelformat = pix_fmt; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(m_i_fd, VIDIOC_S_FMT, &fmt) == 0) { an_set_image_size( AV_PIX_FMT_YUV420P ); } else { pix_fmt = V4L2_PIX_FMT_YUYV; // capture format fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = m_width; fmt.fmt.pix.height = m_height; fmt.fmt.pix.pixelformat = pix_fmt; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(m_i_fd, VIDIOC_S_FMT, &fmt) == 0) { // Format conversion will be required m_sws = sws_getContext( m_width, m_height, AV_PIX_FMT_YUYV422, m_width, m_height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL,NULL, NULL); an_set_image_size( AV_PIX_FMT_YUYV422 ); } else { logger("CAP ANALOGUE FORMAT NOT SUPPORTED"); } } if(ioctl(m_i_fd, VIDIOC_G_FMT, &fmt)<0 ) logger("can't get format"); // input = V4L2_INPUT_TYPE_CAMERA; input = info.video_capture_device_input; if( ioctl( m_i_fd, VIDIOC_S_INPUT, &input) < 0 ) { loggerf("CAP Error VIDIOC_S_INPUT %d",input); } /* v4l2_streamparm parm; memset(&parm,0,sizeof(v4l2_streamparm)); parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; parm.parm.capture.capturemode = 0; parm.parm.capture.readbuffers = 0; if( ioctl( m_i_fd, VIDIOC_S_PARM, &parm) < 0 ) { loggerf("CAP Error VIDIOC_S_PARM"); } */ info.video_bitrate = calculate_video_bitrate(); // // Analogue sound capture // snd_pcm_hw_params_t *hw_params; if(snd_pcm_open(&m_audio_handle, "pulse", SND_PCM_STREAM_CAPTURE, 0)< 0 ) { loggerf("Unable to open sound device"); return; } unsigned int rate = 48000; int r; r = snd_pcm_hw_params_malloc(&hw_params); r = snd_pcm_hw_params_any(m_audio_handle, hw_params); r = snd_pcm_hw_params_set_access(m_audio_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); r = snd_pcm_hw_params_set_format(m_audio_handle, hw_params, SND_PCM_FORMAT_S16_LE); r = snd_pcm_hw_params_set_rate_near(m_audio_handle, hw_params, &rate, 0); r = snd_pcm_hw_params_set_channels(m_audio_handle, hw_params, 2); r = snd_pcm_hw_params(m_audio_handle, hw_params); snd_pcm_hw_params_free(hw_params); r = snd_pcm_prepare(m_audio_handle); an_init_codecs(); m_capturing = true; an_setup_video_capturing( m_i_fd ); an_setup_audio_capturing(); }
// // Initilaise all the software codecs // int an_init_codecs( void ) { sys_config info; av_register_all(); avfilter_register_all(); dvb_config_get( &info ); av_init_packet(&m_avpkt[ENVC]); m_avpkt[ENVC].data = NULL; m_avpkt[ENVC].size = 0; // 25 frames per sec, every 40 ms m_video_timestamp_delta = ((0.04*27000000.0)/300.0); // New audio packet sent every 24 ms m_audio_timestamp_delta = ((0.024*27000000.0)/300.0); AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO); if(codec != NULL) { m_pC[ENVC] = avcodec_alloc_context3(codec); m_pC[ENVC]->bit_rate = info.video_bitrate; m_pC[ENVC]->bit_rate_tolerance = info.video_bitrate/10; m_pC[ENVC]->width = m_width; m_pC[ENVC]->height = m_height; m_pC[ENVC]->gop_size = 12; m_pC[ENVC]->max_b_frames = 0; m_pC[ENVC]->me_method = 5; m_pC[ENVC]->pix_fmt = AV_PIX_FMT_YUV420P; m_pC[ENVC]->time_base = (AVRational){1,25}; m_pC[ENVC]->ticks_per_frame = 2;// MPEG2 & 4 m_pC[ENVC]->profile = FF_PROFILE_MPEG2_MAIN; m_pC[ENVC]->thread_count = 1; if(avcodec_open2(m_pC[ENVC], codec, NULL)<0) { loggerf("Unable to open MPEG2 Codec"); return -1; } } else { loggerf("MPEG2 Codec not found"); return -1; } // // Audio // av_init_packet( &m_avpkt[ENAC] ); // // Must be set to 48000, 2 chan // // Size in bytes 2 channels, 16 bits 1/25 sec codec = avcodec_find_encoder(AV_CODEC_ID_MP2); if( codec != NULL ) { m_pC[ENAC] = avcodec_alloc_context3(codec); m_pC[ENAC]->bit_rate = info.audio_bitrate; m_pC[ENAC]->bit_rate_tolerance = 0; m_pC[ENAC]->bits_per_raw_sample = 16; m_pC[ENAC]->sample_rate = 48000; m_pC[ENAC]->channels = 2; m_pC[ENAC]->sample_fmt = AV_SAMPLE_FMT_S16; m_pC[ENAC]->channel_layout = AV_CH_LAYOUT_STEREO; m_pC[ENAC]->thread_count = 1; if(avcodec_open2(m_pC[ENAC], codec, NULL)<0 ) { loggerf("Unable to open MPEG1 codec"); return -1; } // 16 bit samples & stereo so multiply by 4 m_sound_capture_buf_size = m_pC[ENAC]->frame_size*4; an_set_audio_size(); } return 0; }
// // Start capturing using streaming // void an_start_streaming_capture(int fd) { struct v4l2_requestbuffers req; CLEAR(req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req)<0) { loggerf("CAP does not support MM"); return; } if (req.count < 2) { loggerf("CAP not enough MM buffers"); return; } m_buffers = (struct buffer*)calloc(req.count, sizeof(*m_buffers)); if (!m_buffers) { loggerf("Not enough buffer memory"); return; } for (m_n_buffers = 0; m_n_buffers < req.count; ++m_n_buffers) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = m_n_buffers; if ( ioctl(fd, VIDIOC_QUERYBUF, &buf)<0) { return; } m_buffers[m_n_buffers].length = buf.length; m_buffers[m_n_buffers].start = mmap(NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == m_buffers[m_n_buffers].start) return; } // // Start the capturing // for (unsigned int i = 0; i < m_n_buffers; ++i) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) return; } v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type)<0) return; pthread_create( &an_thread[0], NULL, an_video_mmap_capturing_thread, NULL ); }