Raw File
mlv.c
/*
 * Copyright (C) 2013 Magic Lantern Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */

#include <dryos.h>
#include <stdint.h>
#include <lens.h>
#include <property.h>
#include <picstyle.h>
#include <raw.h>
#include <fps.h>

#include "mlv.h"
#include "../trace/trace.h"

extern uint32_t raw_rec_trace_ctx;

extern uint64_t get_us_clock_value();
extern char *strcpy(char *dest, const char *src);
extern char *strncpy(char *dest, const char *src, int n);
extern const char* get_picstyle_name(int raw_picstyle);

extern struct prop_picstyle_settings picstyle_settings[];

extern int WEAK_FUNC(own_PROPAD_GetPropertyData) PROPAD_GetPropertyData(uint32_t property, void** addr, size_t* len);

static int own_PROPAD_GetPropertyData(uint32_t property, void** addr, size_t* len)
{
    trace_write(raw_rec_trace_ctx, "WARNING: This model doesn't have 'PROPAD_GetPropertyData' defined. Reading properties not possible.");
    return 1;
}

void mlv_fill_lens(mlv_lens_hdr_t *hdr, uint64_t start_timestamp)
{
    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "LENS");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_lens_hdr_t);

    hdr->focalLength = lens_info.focal_len;
    hdr->focalDist = lens_info.focus_dist;
    hdr->aperture = lens_info.aperture * 10;
    hdr->stabilizerMode = lens_info.IS;
    hdr->lensID = lens_info.lens_id;
    hdr->autofocusMode = af_mode;
    hdr->flags = 0;

    strncpy((char *)hdr->lensName, lens_info.name, 32);
    strncpy((char *)hdr->lensSerial, "", 32);
}

void mlv_fill_wbal(mlv_wbal_hdr_t *hdr, uint64_t start_timestamp)
{
    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "WBAL");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_wbal_hdr_t);

    hdr->wb_mode = lens_info.wb_mode;
    hdr->kelvin = lens_info.kelvin;
    hdr->wbgain_r = lens_info.WBGain_R;
    hdr->wbgain_g = lens_info.WBGain_G;
    hdr->wbgain_b = lens_info.WBGain_B;
    hdr->wbs_gm = lens_info.wbs_gm;
    hdr->wbs_ba = lens_info.wbs_ba;
}

void mlv_fill_styl(mlv_styl_hdr_t *hdr, uint64_t start_timestamp)
{
    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "STYL");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_styl_hdr_t);

    hdr->picStyleId = lens_info.raw_picstyle;
    hdr->contrast = lens_get_contrast();
    hdr->sharpness = lens_get_sharpness();
    hdr->saturation = lens_get_saturation();
    hdr->colortone = lens_get_color_tone();

    strncpy((char *)hdr->picStyleName, get_picstyle_name(lens_info.raw_picstyle), sizeof(hdr->picStyleName));
}

void mlv_fill_expo(mlv_expo_hdr_t *hdr, uint64_t start_timestamp)
{
    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "EXPO");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_expo_hdr_t);

    /* iso is zero when auto-iso is enabled */
    if(lens_info.iso == 0)
    {
        hdr->isoMode = 1;
        hdr->isoValue = lens_info.iso_auto;
    }
    else
    {
        hdr->isoMode = 0;
        hdr->isoValue = lens_info.iso;
    }
    hdr->isoAnalog = lens_info.iso_analog_raw;
    hdr->digitalGain = lens_info.iso_digital_ev;
    hdr->shutterValue = (uint32_t)(1000.0f * (1000000.0f / (float)get_current_shutter_reciprocal_x1000()));
}

void mlv_fill_rtci(mlv_rtci_hdr_t *hdr, uint64_t start_timestamp)
{
    struct tm now;
    memset(&now, 0x00, sizeof(struct tm));

    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "RTCI");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_rtci_hdr_t);

    /* get calendar time from real time clock */
    LoadCalendarFromRTC(&now);

    hdr->tm_sec = now.tm_sec;
    hdr->tm_min = now.tm_min;
    hdr->tm_hour = now.tm_hour;
    hdr->tm_mday = now.tm_mday;
    hdr->tm_mon = now.tm_mon;
    hdr->tm_year = now.tm_year;
    hdr->tm_wday = now.tm_wday;
    hdr->tm_yday = now.tm_yday;
    hdr->tm_isdst = now.tm_isdst;
    hdr->tm_gmtoff = now.tm_gmtoff;

    memset(hdr->tm_zone, 0x00, 8);
    strncpy((char *)hdr->tm_zone, now.tm_zone, 8);
}

void mlv_fill_idnt(mlv_idnt_hdr_t *hdr, uint64_t start_timestamp)
{
    char *model_data = NULL;
    uint64_t *body_data = NULL;
    size_t model_len = 0;
    size_t body_len = 0;
    int err = 0;

    /* prepare header */
    mlv_set_type((mlv_hdr_t *)hdr, "IDNT");
    mlv_set_timestamp((mlv_hdr_t *)hdr, start_timestamp);
    hdr->blockSize = sizeof(mlv_idnt_hdr_t);

    /* default values */
    hdr->cameraName[0] = '\000';
    hdr->cameraSerial[0] = '\000';
    hdr->cameraModel = 0;

    /* get camera properties */
    err = PROPAD_GetPropertyData(PROP_CAM_MODEL, (void **) &model_data, &model_len);
    if(err || model_len < 36 || !model_data)
    {
        trace_write(raw_rec_trace_ctx, "[IDNT] err: %d model_data: 0x%08X model_len: %d", err, model_data, model_len);
        snprintf((char*)hdr->cameraName, sizeof(hdr->cameraName), "ERR:%d md:0x%8X ml:%d", err, model_data, model_len);
        return;
    }

    err = PROPAD_GetPropertyData(PROP_BODY_ID, (void **) &body_data, &body_len);
    if(err || !body_data || body_len == 0)
    {
        trace_write(raw_rec_trace_ctx, "[IDNT] err: %d body_data: 0x%08X body_len: %d", err, body_data, body_len);
        snprintf((char*)hdr->cameraSerial, sizeof(hdr->cameraSerial), "ERR:%d bd:0x%8X bl:%d", err, body_data, body_len);
        return;
    }

    /* different camera serial lengths */
    if(body_len == 8)
    {
        snprintf((char *)hdr->cameraSerial, sizeof(hdr->cameraSerial), "%X%08X", (uint32_t)(*body_data & 0xFFFFFFFF), (uint32_t) (*body_data >> 32));
    }
    else if(body_len == 4)
    {
        snprintf((char *)hdr->cameraSerial, sizeof(hdr->cameraSerial), "%08X", *((uint32_t*)body_data));
    }
    else
    {
        snprintf((char *)hdr->cameraSerial, sizeof(hdr->cameraSerial), "(unknown len %d)", body_len);
    }

    /* properties are ok, so read data */
    memcpy((char *)hdr->cameraName, &model_data[0], 32);
    memcpy((char *)&hdr->cameraModel, &model_data[32], 4);

    trace_write(raw_rec_trace_ctx, "[IDNT] cameraName: '%s' cameraModel: 0x%08X cameraSerial: '%s'", hdr->cameraName, hdr->cameraModel, hdr->cameraSerial);
}

uint64_t mlv_prng_lfsr(uint64_t value)
{
    uint64_t lfsr = value;
    int max_clocks = 512;

    for(int clocks = 0; clocks < max_clocks; clocks++)
    {
        /* maximum length LFSR according to http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf */
        int bit = ((lfsr >> 63) ^ (lfsr >> 62) ^ (lfsr >> 60) ^ (lfsr >> 59)) & 1;
        lfsr = (lfsr << 1) | bit;
    }

    return lfsr;
}

uint64_t mlv_generate_guid()
{
    struct tm now;
    uint64_t guid = get_us_clock_value();
    LoadCalendarFromRTC(&now);

    /* now run through prng once to shuffle bits */
    guid = mlv_prng_lfsr(guid);

    /* then seed shuffled bits with rtc time */
    guid ^= now.tm_sec;
    guid ^= now.tm_min << 7;
    guid ^= now.tm_hour << 12;
    guid ^= now.tm_yday << 17;
    guid ^= now.tm_year << 26;
    guid ^= get_us_clock_value() << 37;

    /* now run through final prng pass */
    return mlv_prng_lfsr(guid);
}

void mlv_init_fileheader(mlv_file_hdr_t *hdr)
{
    mlv_set_type((mlv_hdr_t*)hdr, "MLVI");
    hdr->blockSize = sizeof(mlv_file_hdr_t);
    strncpy((char*)hdr->versionString, MLV_VERSION_STRING, sizeof(hdr->versionString));
}

void mlv_set_type(mlv_hdr_t *hdr, char *type)
{
    memcpy(hdr->blockType, type, 4);
}

uint64_t mlv_set_timestamp(mlv_hdr_t *hdr, uint64_t start)
{
    uint64_t timestamp = get_us_clock_value();

    if(hdr)
    {
        hdr->timestamp = timestamp - start;
    }
    return timestamp;
}
back to top