// TITLE     : Scilab driver for ThermaSnap infrared thermographic camera (Inframetrics) 
// AUTHOR (C): Samuel GOUGEON - Université du Maine / ENSIM (France)
// LICENSE   : CeCILL-C
//   http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
// SOFTWARE  : for Scilab > 5.0  http://www.scilab.org/
// DEPENDENCY: http://atoms.scilab.org/toolboxes/serial must be loaded
// RELEASE   : 1.1 (2012-04-11)
// DISCLAIMER : No warranty of any kind is provided. The driver is available 
//              "as is". Be aware and use it to your own risks & responsability
// HISTORY   : 
//   2009-04-12 : Creation
//   2009-06-23 : 
//      help added
//      'getImage': Detramming option removed
//      'getSet'  : Image's timestamping improved
//                  Number of images recorded as the first field of the
//                   returned struct: Removed
//      thermaPlot function: Separated definition
//   2012-03-27 : 
//      'getImage' : [, newShot..] reformulated
//                   [, display..] added
//                   [, colormap ] added
//      'getSet','all' : added
//      'delete',i<0   : added (replaces foreseen implementation of 'cleandir')
//      thermaPlot: isoview added. 
//                  fixed title removed: main & colorbar titles added as input arg
//                  initial clf removed (in order to allow external subplot())
//      coding style: tabs replaced with spaces. gettext() corrected.
//                   Scilab coding style applied (loops, assignments, etc)
//   2012-04-06 : 
//      DateTime extracted from header. 'getimage' now returns a struct 
//       out.image, out.datetime = ['YYYY-MM-DD' 'HH:MN:SS'] and out.utime,
//       instead of the only matrix image
//     'getSet' now returns out.images, out.datetimes and out.utimes
//        (instead of only an hypermat images of thermograms)
//      getimage/Plot: Add the possibility to add xlabel and ylabel. 
//        default xlabel set to Date Time.

// ===========================================================================

function [cf,ca] = thermaPlot(image, varargin)
    // Function called by thermaSnap() to display a thermogram
    // The display is done in the current figure, with no previous clearing.
    //
    // image: matrix of reals (usual size = 120x120x1)
    // varargin(1) : vector S of strings 
    //               S(1) = colorbar's title (usually = temperature unit)
    //               S(2) = thermogram's title
    // varargin(2) : colormap
    //    scalar integer: number of colors in default = jetcolormap
    //    string: colormap name (with default = 100 colors)
    //    (Nx3) matrix of reals: if max>1 : RGB indices in [0, 255]
    //                           else: RGB indices in [0,1]
    // clear_thermaPlot: Boolean external variable. If %T, the figure is
    //                   cleared before displaying the thermogram.

    show_window()
    cf = gcf()
    // colormap
    if argn(2)>2 then
        cmap = varargin(2)
        if typeof(cmap)=='string' then
            cmap = evstr(cmap+"colormap(100)")
        elseif type(cmap)==1    // number of colors (in default jetcolormap)
            if size(cmap,'*')==1 then
                cmap = evstr("jetcolormap("+string(ceil(abs(cmap)))+")")
            elseif size(cmap,2)==3
                if max(cmap)>1, cmap = cmap/255, end
            else
                error(_('thermaPlot: The colormap must be a Nx3 matrix'))
            end
        end
        cf.color_map = cmap;
    // else the current colormap is used
    end
    Ncolors = size(cf.color_map,1)
    cf.background = -2    // force background color to white despite white may not be in colormap
    image = squeeze(image)
    m = min(image)
    M = max(image)
    // Display the raw thermogram (e=1, T_back=0K):
    if clear_thermaPlot, clf, end
    Matplot((image-m)/(M-m)*Ncolors, rect=[1,1,120,120]);	
    ca = gca()
    if argn(2)>1
        titres = varargin(1)
        s = size(titres,"*")
        if s>1, ca.title.text = titres(2), end
        if s>2, ca.x_label.text = titres(3), end
        if s>3, ca.y_label.text = titres(4), end
    end
    ca.title.font_size = 3
    ca.isoview = 'on'
    // Display the colorbar
    colorbar(m, M, [1 Ncolors], fmt="%.1f")
    cf = gcf(); ca = cf.children(1)
    if argn(2)>1 then
        ca.title.text = titres(1) + ascii(13)
        ca.title.font_size = 2
    end
endfunction

// ===========================================================================

function sortie = thermaSnap(command, varargin)
// INFRARED CAMERA THERMASNAP
// ==========================
// * STARTING the CAMERA
//   - by hand. Remote starting is not supported
//   - Sometimes the camera freezes during the boot. It is then impossible
//     to restart it, even with the power button. In this case, unplug and 
//     replug the power cable in order to stop, and then reboot.
//
//  * CONNEXION : The camera must be connected to a serial port through its
//     dedicated data cable (LEMO connector on the camera side, sub-D9 on the
//     computer side). The initial data rate must be tuned to 115200 bauds
//     (menu SETUP/BAUD RATE on the firmware inboard).
//
// * COMMANDS
//    . Command names are case-unsensitive
//    . There is no command to query the camera parameters
//     (=> settings go to a bound and then increment by the desired quantity)
//
// * DATA
//   Data delivered through the serial connexion are radiometric ones:
//     . They do not depend on the emissivity tuned on the camera
//     . They do not depend on the background temperature tuned on the camera
//     . Their variations are ~4 times larger than the observed variations
//        of temperatures.
//
//  * DEPENDENCIES
//   - This driver may be used with Scilab > 5.0
//   - Required module: http://atoms.scilab.org/toolboxes/serial must be loaded
//
// ========================================================================
// 
// out = thermaSnap(command, data)
//
// command  : String specifying action to be done. Case doesn't mind.
//             For available commands : See table hereafter.
// data     : Parameter(s), according to command. See below for details
//
// COMMANDS       DATA & ACTION
// --------       -------------
// (none)         thermaSnap without argument displays this help
// 'open',port#   Open the RS-232 connexion to the camera.
//                The given serial port number is used. The default temperature
//                unit is set to °C.
//                Return the handle of the serial communication (string),  
//                whether the connexion is set without error.
// 'close'        Close the RS-232 connexion & clear related data. Data ignored.
// 'shoot'        Trigger the shoot. The thermogram is not returned.  Data ignored
// 'save'         Record the current image onto the memory card. Data ignored. 
// 'recall',i     i = rank of the image to be recall & displayed, among the full
//                  list of stored images. First = 1. Default = first.
//                  i > total number of stored images => last is displayed
// 'delete',i     i>0 = rank of the image to be deleted, among the full
//                  list of stored images. First = 1. Default = first.
//                  i > total number of stored images => last is deleted.
//                  After deletion, the first remaining image is displayed.
//                i<0 = number of stored images to be deleted, starting from
//                  the first (oldest) one. If |i|>total number of stored
//                  images, all images are deleted (except the last one)
//
// 'getImage' [, newShot [, display [,colormap]]] :
//                 newShot: boolean. 
//                   If true, a new shot is triggered before being got
//                   Else, the last image is got
//                 display : boolean. %T to display the thermogram after 
//                           recovering it. default is %F (false).
//                 colormap: may be
//                   . a positive integer   = number of colors (in jet colormap)
//                   . a Nx3 matrix of reals = the colormap to be used.
//                      If it contains at least one value>255, it is initially
//                      divided by 255 (values must be in [0,255]. 
//                      Otherwise, it is used as is (values in [0, 1])
//                   . a string = name of the colormap to be used (100 colors)
//                     Existing colormaps are: autumn, bone, cool, copper, gray,
//                     hot, hsv, [jet], ocean, pink, rainbow, spring, summer,
//                     winter.
//                 out.image   : Radiometric image = 120x120 of uint16()
//                 out.datetime: datetime of the shoot.
//                               Format: [ 'YYYY-MM-DD' 'HH:MN:SS' ]
//                 out.utime   : unix time of the shoot = number of seconds 
//                               elapsed since 1/1/1970 00:00:00
//
// 'getSet', n, Dt : Return a set of n thermograms shot every Dt seconds
//                 (minimal sampling period)
//                 out = struct('n','cube','dates')  where
//                  out.images   : (n,120,120) hypermat of reals
//                                 the ith thermogram is in out.radiograms(i,:,:)
//                  out.datetimes: (n,2) column (text) of dates of recorded images
//                  out.utimes   : unix times of returned images:
//                                 (1,n) line-vector of reals. 
// 'getSet','all' :
//               Return all images stored in the memory card.
//               out.images out.datetimes out.utimes: As for 'getSet' hereabove
//
// 'getAverage', n : Shot n consecutive thermograms (as fast as possible)
//                 out.average: Average thermogram (120x120 matrix of reals)
//                 out.sigma  : Standard deviation for each pixel (idem)
//
// 'focus'        Start / stop narrow sweep for tuning the focus (by hand)
// 'focusWidth', width: 0 <  width <=  1          (= fraction) or
//                      1 <  width <= 100   (= %)
//                   out: focusing width actually set
// 'setEmissiv', e  Set the emissivity e:  0.01 <= e <= 1.00
// 'T_backgrd', Tb  Set the Background temperature Tb (in current unit). 
//                  Tb must be in [-20, 150-300[°C  
//                             =  [-4, 302-572[°F  =  [253, 323-573[ K
// 'T_unit', Tu     Set the Temperature unit: Tu = 'C' (default) | 'K' | 'F'
// 'setVideoOut'  'OFF' | 'PAL' | 'NTSC'   Set the video format
// 'setBaud'       rate: 300 1200 2400 4800 9600 19200 38400 57600 115200
// 'setDate' [,[YYYY MM DD HH MN]]. Default date = now.
// 'APM', [Type, Duration]  Advanced Power Management :
//                 Type = 1  : set Display diminution time (default)
//                        2  : set Display off time
//                        3  : set camera  off time
//                      else : default = 1
//                 Duration  : Duration = 0 : OFF (default)
//                             0 < Duration < 256 (unit = s ?)

devName = "thermaSnap";
if argn(2)==0
    head_comments thermaSnap
    sortie = 0
    return
end
command = convstr(command,'l');

tmp = "save,recall,delete,focus,focuswidth,shoot,getimage,"+..
      "setemissiv,t_unit,t_backgrd,setvideoout,apm,setbaud,setdate";
if ( strstr(tmp,command)~='' & ~exists('writeserial'))
    tmp = _("%s: writeserial() from SERIAL TCL toolbox is missing\n");
    error(msprintf(tmp, devName));
end

if (command <> 'open') 
    h = TCL_GetVar("thermaSnapHandle")
    baud = strtod(TCL_GetVar("thermaSnap.Baud"))
end

data = varargin
if length(data)==1, data = data(1), end

select command
    case 'open'
        if (~exists('openserial'))
            tmp = _("%s: openserial() from SERIAL TCL toolbox is missing\n")
            error(msprintf(tmp, devName))
        else
            data = data(1)
            if typeof(data)=='string' & isnum(data) then
                data = evstr(data)
            end
            h = openserial(data,"115200,n,8,1")
            TCL_EvalStr("fconfigure "+h+" -buffersize 30000 -sysbuffer 30000")
            TCL_SetVar("thermaSnapHandle",h)
            TCL_SetVar("thermaSnap.Baud",115200)
            thermaSnap('T_unit','C')
            sortie = h
        end
    // ==========================================================================

    case 'close'
        if (~exists('closeserial'))
            tmp = _("%s: closeserial() from SERIAL toolbox by Enrico Segre is missing\n")
            error(msprintf(tmp, devName))
        else
            thermaSnap('setBaud',115200)
            sortie = -closeserial(h)
            TCL_UnsetVar('thermaSnapHandle')
            TCL_UnsetVar('thermaSnap.Baud')
        end

    // ==========================================================================

    case 'save'
        sortie = -writeserial(h,'R')    // Recording on the card
        sleep(3000)
    
        // ==========================================================================
    
    case 'recall'
        s = writeserial(h,'L')
        sleep(500)
        s = s + writeserial(h,'1')
        sleep(500);
        if ~exists('data','l'), data=1; end
        if data==1, s = s + writeserial(h,'e')
        else s = s + writeserial(h,ascii(ones(1,data-1)*117)+'e')  // u <--> 117
        end
        sortie = -s
        sleep(4000)

    // ==========================================================================

    case 'delete',
        if data>0 then    // deletion of the image #i
            s = writeserial(h,'L');     sleep(500)
            s = s + writeserial(h,'L'); sleep(500)
            s = s + writeserial(h,'1'); sleep(500)
            if ~exists('data','l'), data = 1; end
            if data==1
                s = s + writeserial(h,'e')
            else 
                s = s + writeserial(h, ascii(ones(1,data-1)*117)+'e') // u <--> 117
            end
            sleep(5000)
            sortie = -s
        else    // Deletion of the i first (oldest) images
            s = 0
            for i=1:abs(data), s = s+thermaSnap('delete',1), end
            sortie = s
        end

    // ==========================================================================

    case 'focus'
        sortie = -writeserial(h,'f');			

    // ==========================================================================

    case 'shoot'
        sortie = -writeserial(h,'s');
        sleep(6000);

    // ==========================================================================

    case 'getimage'
        nb = -1		// Total number of bytes read
        duree = 6.5 + 232000.0 / baud 
        while nb~=14500	// Loop securing the acquisition (incorrect transfer)...
            if nb==-1
                if length(data)>0 & data(1), Mode = 'i'; else Mode = 't'; end
                // 8 s(= shot) +  29000/(flow rate(bauds)/8) (= transfer)
            else
                tmp = _("thermaSnap(getImage): Mis-recovered image (%d bytes). Restarting transfer...")
                warning(msprintf(tmp, nb))
                Mode = 't'             // No new shot. Just return the current one
                duree = duree*1.1      // Previous waiting time for transfer : +10 %
            end
            TCL_EvalStr("set ttybuf [read "+h+"]")    // Cleans the buffer
            writeserial(h,Mode)     // Starts the transfer from device to buffer
            sleep(duree*1000)
            TCL_EvalStr("set ttybuf [read "+h+"]")
            
            TCL_EvalStr("set fid [open thermaSnap.img w]")
            TCL_EvalStr("fconfigure $fid -translation binary")
            TCL_EvalStr("puts -nonewline $fid $ttybuf")
            TCL_EvalStr("close $fid")
            
            fid   = mopen("thermaSnap.img",'rb')
            rawIm = mgeti(29000,'us',fid)     // us = unsigned short (2bytes)
            mseek(0)    // rewind
            header = double(mgeti(200,'uc',fid))      // uc = 1 byte
            mclose(fid);
            
            nb = length(rawIm)        // Must be == 14500 if transfer OK
        end
        image = uint16(zeros(120,120))    // Déclare the format of image + header
        image(:) = rawIm(101:$)    // Remove the header and assigns the image
        image = double(image)/16   // Manufacturer factor => K
        
        year = header(9)+256*header(10)
        Date = msprintf("%d-%02d-%02d",year, header(8), header(7))
        Time = msprintf("%02d:%02d:%02d",header(12),header(13),header(14))
        tmp = datenum(year,header(8),header(7),header(12),header(13),header(14))
        utime = (tmp - 719529)*86400 // Unix time= [s] since 1/1/1970 00:00:00
 
        T_unit = TCL_GetVar(h+'.T_unit')
        T_unit = "°" + T_unit
        if (T_unit~='°K'), image = image - 273.15; end
        if (T_unit=='°F')  image = image*1.8+32; end
        
        if length(data)>1 & data(2)
            titres = [T_unit,_("Apparent temperatures (e=1)"), Date+" "+Time]
            if length(data)>2
                [cf,ca] = thermaPlot(image,titres,data(3))
            else
                [cf,ca] = thermaPlot(image,titres)
            end
        end
        sortie.image = image
        sortie.datetime = [ Date Time ]
        sortie.utime = utime

        // ==========================================================================

    case 'getset'
        clear_thermaPlot = %T  // To erase the previous thermogram before each display
        if type(data(1))==1    // 'getSet', n [, Dt]
            n = data(1);
            dTransmit = 232000.0/baud
            dtmin = 8.5 + dTransmit
            dt = max(data(2),dtmin)
            write(%io(2),"Période effective = "+string(dt)+' s')
            images = zeros(n,120,120)
            tic()
            datetimes = []
            utimes = []
            for i = 1:n
                tmp = thermaSnap('getimage',%t,%t,'jet')
                images(i,:,:) = tmp.image
                datetimes = [ datetimes ; tmp.datetime ]
                utimes = [ utimes tmp.utime ]
                write(%io(2),string(i)+'/'+string(n)+"  ")
                while toc()<i*dt, ; end
            end
            sortie = struct('images',images, 'datetimes',datetimes, 'utimes',utimes)
        else    // 'getSet','all'   
            tmp = _("%s: ''getSet'', arg: arg must be ''all'' or an integer\n")
            if typeof(data(1))=="string" then
                if convstr(data(1),'l')=='all'
                    i = 1
                    thermaSnap('recall',i)
                    tmp = thermaSnap('getimage',%f,%t,'jet')
                    a = gca(), a.x_label.text = "#1)   "+a.x_label.text
                    imOld = tmp.image
                    if length(imOld)==14400
                        images = hypermat([1,120,120],imOld)
                        datetimes = tmp.datetime
                        utimes = tmp.utime
                        i = 2
                        thermaSnap('recall',i)
                        tmp = thermaSnap('getimage',%f,%t,'jet')
                        a = gca(), a.x_label.text = "#2)   "+a.x_label.text
                        im = tmp.image
                        while or(im~=imOld)
                            images($+1,:,:) = im
                            datetimes = [ datetimes ; tmp.datetime ]
                            utimes = [ utimes  tmp.utime ]
                            imOld = im
                            i = i+1
                            thermaSnap('recall',i)
                            tmp = thermaSnap('getimage',%f,%t,'jet')
                            a = gca()
                            a.x_label.text = "#"+string(i)+")   "+a.x_label.text
                            im = tmp.image
                        end
                        sortie = struct('images',images, 'datetimes',datetimes, 'utimes',utimes)
                        disp(msprintf(_("%d images loaded\n"),size(images,1)))
                    else
                        disp(_("No available images on the card"))
                        sortie = []
                    end
                else
                    error(msprintf(tmp, devName));
                end
            else
                error(msprintf(tmp, devName));
            end
        end
    
    // ==========================================================================

    case 'getaverage',
        // data=n;
        n = data;
        tmp = thermaSnap('getset',n,0)
        cube = tmp.cube;
        S1 = squeeze(cube(1,:,:)); S2=S1.*S1;
        for i = 2:n
            S = squeeze(cube(i,:,:))
            S1 = S1+S
            S2 = S2+S.*S; 
        end
        S1 = S1/n;
        sortie = struct('average',S1,'sigma',sqrt(S2/n-S1.*S1));

    // ==========================================================================

    case 'focuswidth'
        // focusWidth(width) : scanning width for the focusing
        // Any value of data = width > 1 is considered as a pourcentage, else as a fraction
        width = abs(data);
        if width <= 1
            width=max(round(width*100),1)
        else 
            width=min(round(width),100)
        end
        valeur = 0 
        str = ''
        while valeur < width, str=[str '7']; valeur=valeur+10 ; end
        while valeur > width, str=[str 'd']; valeur=valeur-1 ; end
        T = 500  // Temporisation : Do not modify !!
        s =     writeserial(h,'o'); sleep(T);     // Menu setup n°2
        s = s + writeserial(h,'e'); sleep(T);     // Validation. Arrives on Focus width
        s = s + writeserial(h,'e'); sleep(T);     // Selection Focus width 
        for i=1:12, s = s + writeserial(h,'2'); sleep(400);end	// Mise à 0 du focus width
        s = s + writeserial(h,[str 'e']); sleep(1000)  // Setting the width, validation
        s = s + writeserial(h,'u'); sleep(T);     // Go to "Save & exit"
        s = s + writeserial(h,'e'); sleep(T);     // Validate "Save & exit"
        sortie = -s;

    // ==========================================================================

    case 'setemissiv'
        e = min(1,data)
        e = max(0.01,e)
        E = 100*e
        T = 150
        s = 0
        for i=1:99
            s = s+writeserial(h,'+')
            sleep(T)
        end
        valeur = 100;
        while valeur > E
            s = s + writeserial(h,'-')
            valeur = valeur-1
            sleep(T)
        end
        sortie = -s;

    // ==========================================================================

    case 't_unit',
        // data = unit = 'C', 'K', ou 'F'
        T = 300 ;
        sortie = writeserial(h,'m'); sleep(1300)	// Menu setup n°1 = "Measurement setup", rubrique T.unit
        sortie = sortie + writeserial(h,'e'); sleep(T);   // Validate
        for i=1:2             // Go to °C (bound)
            sortie = sortie + writeserial(h,'l')
            sleep(T)
        end 
        T_unit = 'C'; 
        if ~exists('data','l'), data = 'C'; end
        if convstr(data,'u') == 'F'
            sortie = sortie + writeserial(h,'r')        // Sets °F  unit
            sleep(T)
            T_unit = 'F'
        elseif convstr(data,'u') == 'K'  
            for i = 1:2
                sortie = sortie + writeserial(h,'r')     // Sets K  unit
                sleep(T)
            end  
            T_unit = 'K'
        end
        TCL_SetVar(h+".T_unit",T_unit)         // Recording in the TCL session
        sortie = sortie + writeserial(h,'e')   // Validation
        sleep(T)
        sortie = sortie + writeserial(h,'z')   // Recording + back to the image
        sleep(T)
        sleep(1500)

    // ==========================================================================

    case 't_backgrd'
        // data = Background temperature Tb (in current unit): 
        T = 150;  // Temporisation : Do not modify !!
        s =     writeserial(h,'m'); sleep(1600);    // Menu setup n°1. item "Measurement setup"
        s = s + writeserial(h,'d'); sleep(T);       // Go to "Background temperature" + validation
        s = s + writeserial(h,'e'); sleep(T);       // Go to "Background temperature" + validation
        for i=1:8, s = s + writeserial(h,'11111111111'); sleep(200); end	// Go to T(background) min
        // 
        T_unit = TCL_GetVar(h+".T_unit");      // Retrieving T_unit from TCL session
        if T_unit == 'C', valeur = -20; data = min(data,300); end    // max = 300 °C
        if T_unit == 'F', valeur = -4 ; data = min(data,572); end    // max = 572 °F
        if T_unit == 'K', valeur = 253; data = min(data,573); end    // max = 573 K
        while valeur < data-10
            s = s + writeserial(h,'3')
            valeur = valeur+10
            sleep(T)
        end
        while valeur < data
            s = s + writeserial(h,'r')
            valeur = valeur+1
            sleep(T)
        end
        s = s + writeserial(h,'e'); sleep(T);        //  Validation
        s = s + writeserial(h,'z'); sleep(1500);     //  Back to the menu
        s = s + writeserial(h,'z'); sleep(400);      //  Back to the image
        sortie = -s;

    // ==========================================================================

    case 'setvideoout',
        // Execution time : ~ 5.5 s
        // data = mode = 'OFF' | 'PAL' | 'NTSC'
        T = 400;  // Temporisation : Do not modify !!
        s = writeserial(h,'m'); sleep(1500);        // Menu setup n°1
        s = s + writeserial(h,'m'); sleep(1500);    // sub-menu "User interface setup"
        s = s + writeserial(h,'dde'); sleep(T);     // Go to "External video" + validation
        s = s + writeserial(h,'ll'); sleep(T);      // Go to OFF (limit, by default)
        if data=='PAL'
            s = s + writeserial(h,'re')            // Validate
            sleep(T)
        end 
        if data=='NTSC'
            s = s + writeserial(h,'rre')           // Validate
            sleep(T)
        end 
        s = s + writeserial(h,'uuue'); sleep(T)   // Go to "Save & exit" + validation
        s = s + writeserial(h,'z'); sleep(T)      // Recording + back to the image
        sortie = -s;

    // ==========================================================================

    case 'apm'
        // Advanced Power Management: Data=[type,duree]
        // Type : 1  : set Display diminution time
        //        2  : set Display off time
        //        3  : set camera  off time
        //		 else   Type 1 is considered
        //
        //   Duration [s] : 0 < Duration < 256
        //   Duration = 0 : OFF (default)
        action = floor(data(1))
        duree = 0
        if length(data)>1, 
            duree = min([data(2) 255])
            duree = round(max([0,duree]))
            duree = min([duree 255])
        end
        T = 400;  // Temporisation : Do not modify !!
        s = writeserial(h,'o'); sleep(1500)    // Menu setup n°2. item "Modes"
        //¨Go to "Advanced" + validation :
        s = s + writeserial(h,'uuue'); sleep(T)
        // Go to "Power Saving" + validation : Display dim time :
        s = s + writeserial(h,'ddde'); sleep(T)
        // Go to "Display off time" :
        if action > 1 , s = s + writeserial(h,'d'); sleep(T); end
        // Go to "Camera off time" :
        if action == 3, s = s + writeserial(h,'d'); sleep(T); end
        s = s + writeserial(h,'e'); sleep(T) ;		// Validation
        // Go to duration=0 (step by 10) :
        for i=1:6, s = s + writeserial(h,'111111111'); sleep(1000); end
        valeur = 0;
        while valeur<duree-10
            s = s+writeserial(h,'8')
            valeur = valeur+10
            sleep(200)
        end
        while valeur<duree
            s = s + writeserial(h,'u')
            valeur = valeur+1
            sleep(200)
        end
        s = s + writeserial(h,'e')              //  Validation
        s = s + writeserial(h,'z'); sleep(T)    //  Back to the menu
        s = s + writeserial(h,'z'); sleep(T)    //  Back to the image
        sortie = -s;

    // ==========================================================================

    case 'setbaud'
        rates = [300 1200 2400 4800 9600 19200 38400 57600 115200];
        i = 1
        while (data>rates(i) & i<9), i = i+1; end
        T = 100;  // Temporisation
        s = writeserial(h,'m'); sleep(1500);        // Menu setup n°1
        s = s + writeserial(h,'m'); sleep(1500);    // Sub-menu "User interface setup"
        s = s + writeserial(h,'uuuue'); sleep(5*T); // Go to "Baud rate" + validation
        for j=1:8             // Go to last value (115200 bauds)
            s = s + writeserial(h,'r')
            sleep(T)
        end
        for j=9:-1:i+1
            s = s + writeserial(h,'l')
            sleep(T)
        end
        // writeserial(h,'e'); sleep(T); // Valider
        for j=1:3
            s = s + writeserial(h,'d')  // validate + Go to "Save & exit" 
            sleep(T)
        end
        s = s + writeserial(h,'e'); sleep(T); // + validation 
        s = s + writeserial(h,'e'); sleep(T); // Sub-menu "User interface setup"		
        // Setting + recording accordingly the transfer rate of the serial port:
        TCL_EvalStr("fconfigure "+h+" -mode "+string(rates(i))+",n,8,1")
        TCL_SetVar("thermaSnap.Baud",string(rates(i)));
        sortie = -s;

    // ==========================================================================

    case 'setdate'        // (takes from 12 to 22 s ...)
        T = 200;
        s = writeserial(h,'o'); sleep(1000)         // Menu setup n°2
        s = s + writeserial(h,'uuue'); sleep(1500)  // Sous-menu "Advanced"
        s = s + writeserial(h,'de'); sleep(1000)    // Rubrique Set date/title
        if exists('data','l')
            D = data
        else
            D = clock()
        end
        sleep(1000)

        // Setting the date:month:
        mois = D(2);
        s = s + writeserial(h,'e'); sleep(500)    // sub-item "Month"
        s = s + writeserial(h,'111'); sleep(T)    // setting month=1 (reference)
        i = 1
        if mois > 10
            s = s + writeserial(h,'7')
            sleep(T)
        end
        while i<mois
            s = s + writeserial(h,'u')
            i = i+1
            sleep(250)
        end
        s = s + writeserial(h,'e'); sleep(300)    // Validating the Month
   
        // Setting the date:day
        jour=D(3);
        s = s + writeserial(h,'de'); sleep(500)        // sub-item "Day"
        s = s + writeserial(h,'11111111'); sleep(500)  // setting day=1 (lower bound = ref)
        i = 1
        while (jour-i)>= 10
            s = s + writeserial(h,'7')
            sleep(T)
            i = i+10
        end
        while i<jour
            s = s + writeserial(h,'u')
            i = i+1
            sleep(T)
        end
        s = s + writeserial(h,'e'); sleep(300)        // Validating the Day

        // Ajustement ANNEE
        annee = D(1);
        s = s + writeserial(h,'de'); sleep(500)           // sub-item "Year"
        s = s + writeserial(h,'11111111111'); sleep(500)  // Sets year=1980 (lower bound = ref)
        i = 1980
        while (annee-i)>= 10             // Setting the tens
            s = s + writeserial(h,'7')
            sleep(2000)
            i = i+10
        end
        while i<annee                    // setting the unit year
            s = s + writeserial(h,'u')
            i = i+1
            sleep(T)
        end

        s = s + writeserial(h,'e'); sleep(300)      // Validating Year

        // Ajustement Heures
        H = D(4);
        s = s + writeserial(h,'de'); sleep(500)   // sub-item "Hour"
        for i = 1:2                               // setting hour=0 (reference)
            s = s + writeserial(h,'111')
            sleep(300)
        end
        i = 0
        while (H-i)>= 10
            s = s + writeserial(h,'7')
            sleep(T)
            i = i+10
        end
        while i<H
            s = s + writeserial(h,'u')
            i = i+1
            sleep(T)
        end
        s = s + writeserial(h,'e'); sleep(300)        // Validating Hour
   
        // Ajustement Minutes
        s = s + writeserial(h,'de'); sleep(500)       // sub-item "Minute"
        mn = D(5);
        for i = 1:4                            // setting mn=0 (reference)
            s = s + writeserial(h,'111')
            sleep(T)
            end
        i = 0
        while (mn-i)>= 10
            s = s + writeserial(h,'7')
            sleep(T)
            i = i+10
        end
        while i<mn
            s = s + writeserial(h,'u')
            i = i+1
            sleep(T)
        end
        s = s + writeserial(h,'e'); sleep(300)        // Validating Minutes
        s = s + writeserial(h,'z'); sleep(300)        // Save & exit

        sortie = -s;
    else
        error(msprintf(_("%s: Command %s unknown\n"),devName,command))
    end

endfunction
