いしばらく時間が開きましたが、SkymemoSにエンコーダが取り付け終わったので、Indiに戻ります。これまでIndiからNJPに取り付けたエンコーダの値をとって表示するところまで作りました。次はIndi経由で撮影を行います。

その前にちょっと気になっていたことが。Indiからニコンのカメラで撮影するときに選択できるフォーマットはJPEGもしくはRAW(NEF)のみです。カメラ自体はJPEGとNEFを両方保存するモードを持っているのですが、Indiではそれが選べません。後で写真を選ぶときなどJPEGのほうが軽くて便利なので、自分はいつもJPEG+NEFで撮影しているのでこれはちょっと困ります。

Indiのバージョンはv1.8.5。いまはv1.8.7がリリースされているようですが、修正されているんですかね。

カメラでJPEG+NEFの設定にしてIndiをつなぐとこんなエラーが出ます。
Screenshot_2020-11-28_09-53-26

また、フォーマットをJPEG+NEFに選び直すとこんなエラーが出ます。これらを直してみます。
Screenshot_2020-11-28_09-59-08

Indi driverはデフォルトではすべて
/usr/bin
の下にあります。ニコンのカメラのIndi driverは、このようにgphotoのIndi driverへのスタティックリンクとなっています。
Screenshot_2020-11-28_09-56-17

gphotoのIndi driverは indi-3rdparty の中に含まれています。いじるのはこの中のgphoto関連、
indi-gphoto/gphoto_ccd.cpp
indi-gphoto/gphoto_driver.cpp
の2つ。上がIndiとのインタフェース、下がgphotoとのインタフェースになります。
まず上記のエラーを出しているところを見ます。
自分が持っているニコンD5500で選択できるフォーマットは以下の7つ。下の3つが一度の撮影でJPEGとRAWの2つのファイルを保存します。

JPEG Basic
JPEG Normal
JPEG Fine
NEF (Raw)
NEF+Basic
NEF+Normal
NEF+Fine

接続時にエラーを出しているのはここ。gphoto_ccd.cppの中のConnect()関数。これはIndi driverにデバイスが接続されたときに呼ばれる関数です。その中でフォーマットをチェックしています。チェックする方法はフォーマット名に"+"が含まれるかどうか。
bool GPhotoCCD::Connect()
{
    int setidx;
    char ** options;
    int max_opts;

	<略>
	
    if (max_opts > 0)
    {
        mFormatS      = create_switch("FORMAT", options, max_opts, setidx);
        mFormatSP.sp  = mFormatS;
        mFormatSP.nsp = max_opts;

        ISwitch * sp = IUFindOnSwitch(&mFormatSP);
        if (sp && strstr(sp->label, "+")) // <- ここから
        {
            IUResetSwitch(&mFormatSP);
            int i = 0;

            // Prefer RAW format in case selected format is not supported.
            for (i = 0; i < mFormatSP.nsp; i++)
            {
                // Make sure the new selection does not include the problematic label with the +
                // also also contains the string RAW in it.
                if (strcmp(sp->label, mFormatSP.sp[i].label) && strcasestr("RAW", mFormatSP.sp[i].label))
                {
                    mFormatS[i].s = ISS_ON;
                    break;
                }
            }

            if (i == mFormatSP.nsp)
            {
                LOGF_ERROR("%s format is not supported. Please select another format.", sp->label);
                mFormatSP.s = IPS_ALERT;
            }

            IDSetSwitch(&mFormatSP, nullptr);
        } // <- ここまで
    }

    if (mIsoS)
        free(mIsoS);

    <略>
次にIndiのGUIでフォーマットを変えたとき。 同じくgphoto_ccd.cppの、ISNewSwich()関数の中です。この関数はIndiのUIでボタンが変化したときに呼ばれる関数。判断する方法は同じく"+"があるかどうか。
bool GPhotoCCD::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
{
	<略>
        // Formats
        if (!strcmp(name, mFormatSP.name))
        {
            int prevSwitch = IUFindOnSwitchIndex(&mFormatSP);
            if (IUUpdateSwitch(&mFormatSP, states, names, n) < 0)
                return false;

            ISwitch * sp = IUFindOnSwitch(&mFormatSP);
            if (sp)
            {
                if (strstr(sp->label, "+"))	// <-ここから
                {
                    LOGF_ERROR("%s format is not supported.", sp->label);
                    IUResetSwitch(&mFormatSP);
                    mFormatSP.s                = IPS_ALERT;
                    mFormatSP.sp[prevSwitch].s = ISS_ON;
                    IDSetSwitch(&mFormatSP, nullptr);
                    return false;
                }	// <-ここまで
            }
            for (int i = 0; i < mFormatSP.nsp; i++)
            {
	<略>

まずはRAW+JPEGフォーマットを選択できるようにこの条件文をコメントアウトします。それで撮影してみます。こんな感じで撮影しています。
PXL_20201129_062628709

ここでカメラの向きを振りながら撮影すると・・・
一枚目
Screenshot_2020-11-29_15-24-51

二枚目。あれ?位置が変わっていません。その代わりなんか色が淡い。
Screenshot_2020-11-29_15-25-29

三枚目。今度は位置が変わりました。
Screenshot_2020-11-29_15-25-58

この理由は、一枚目撮影したときにJPEGとNEFの2つのファイルが保存されるので、1枚目撮影時は1枚目のJPEG、2枚目撮影したときには1枚目のNEFがカメラからダウンロードされてしまうため。3枚目の撮影では、2枚目のJPEGがダウンロードされてやっと位置が変化した、という具合です。

さてこれをどう修正するか。今回はJPEG+NEFで保存した場合は必ずJPEGをダウンロードするようにします。そのほうがファイルが小さくてレスポンスも良くなります。

修正するところはここ。gphoto_driver.cppの gphoto_read_exposure_fd()関数。撮影した画像をカメラからダウンロードする関数です。
int gphoto_read_exposure_fd(gphoto_driver *gphoto, int fd)
{
    CameraFilePath *fn;
    CameraEventType event;
    void *data = nullptr;
    int result;
	<略>
    //Bulb mode
    int timeoutCounter = 0;
    gphoto->command    = 0;

    while (1)
    {
		<略>
        switch (event)
        {
            case GP_EVENT_CAPTURE_COMPLETE:
                DEBUGDEVICE(device, INDI::Logger::DBG_DEBUG, "Capture event completed.");
                break;
            case GP_EVENT_FILE_ADDED:	// <- ここ
                DEBUGDEVICE(device, INDI::Logger::DBG_DEBUG, "File added event completed.");
                fn     = static_cast(data);
                result = download_image(gphoto, fn, fd);
                //Set exposure back to original value

                // JM 2018-08-06: Why do we really need to reset values here?
                //reset_settings(gphoto);

                pthread_mutex_unlock(&gphoto->mutex);
                return result;
            case GP_EVENT_UNKNOWN:
                //DEBUGDEVICE(device, INDI::Logger::DBG_DEBUG, "Unknown event.");
                break;

		<略>
この中でカメラから届くイベントを見ていますが、GP_EVENT_FILE_ADDED イベントが届いたところでカメラからファイルをダウンロードしています。GP_EVENT_FILE_ADDEDイベントはカメラで撮影した画像がファイルとして書き込みが完了したことを通知するイベントです。
JPEG+NEFフォーマットの場合はJPEGファイルが書き込み終了したときとNEFファイルが書き込み終了したときの2回イベントが飛んでくるのですが、現状のソースでは一回GP_EVENT_FILE_ADDEDイベントを受信するとファイルをダウンロードして終了してしまいます。そのため次の撮影をすると、その前の2つ目のGP_EVENT_FILE_ADDEDイベントでファイルを取ってきてしまう、という具合。

ここをこんなふうに直します。

①まず現在設定されているフォーマットを取得して、JPEG+NEFの場合はGP_EVENT_FILE_ADDED イベントを受信する回数を2回に設定
②次にGP_EVENT_FILE_ADDEDイベントを発生させたファイルがNEFの場合 かつ GP_EVENT_FILE_ADDEDイベント受信回数が2回の場合はスキップ


int gphoto_read_exposure_fd(gphoto_driver *gphoto, int fd)
{
	<略>
    int format = gphoto->format;
    int max_opts;
    char **options = gphoto_get_formats(gphoto, &max_opts);
    int capImgNum = 1;
    if(format < max_opts){
        //if current format is JPEG + NEF, receive GP_EVENT_FILE_ADDED two times.
        capImgNum = strstr(options[format], "+") != NULL ? 2 : 1;	//<- ここ①
        DEBUGFDEVICE(device, INDI::Logger::DBG_DEBUG, "Current Format = No %d %s. Receive image %d times", format, options[format], capImgNum);
    }
    else{
        DEBUGFDEVICE(device, INDI::Logger::DBG_DEBUG, "Invlid Format = %d  ", format);
    }
    int currentCap = 0;
    while (1)
    {

			<略>
        switch (event)
        {
            case GP_EVENT_CAPTURE_COMPLETE:
                DEBUGDEVICE(device, INDI::Logger::DBG_DEBUG, "Capture event completed.");
                break;
            case GP_EVENT_FILE_ADDED:
                fn     = static_cast(data);
                DEBUGFDEVICE(device, INDI::Logger::DBG_DEBUG, "File added event completed. Filename = %s", fn->name);
                if(capImgNum == 2 && strcasestr(fn->name, ".NEF") != NULL){ //<-ここ②
                    DEBUGDEVICE(device, INDI::Logger::DBG_DEBUG, "NEF file is skipped bacause format is JPEG + NEF");
                    //if format is jpeg+NEF and saved file is NEF, it is ignored.
                }
                else{
                    result = download_image(gphoto, fn, fd);
                }
                currentCap++;
                if(currentCap == capImgNum) {
                    pthread_mutex_unlock(&gphoto->mutex);
                    return result;
                }
                break;
さて、動かしてみると、まずは一枚目。
Screenshot_2020-11-29_15-28-06


向きを変えて二枚目。ちゃんと新しい向きの画像が撮影できています。
Screenshot_2020-11-29_15-28-41


というわけでJPEG+NEFファイル両方保存することができるようになりました。次はリモートで撮影できるようにしてみます。