<? /*!*************************************************************************** *! FILE NAME : camogmgui.php *! DESCRIPTION: command interface for the camogm recorder and camogm GUI *! Copyright (C) 2008 Elphel, Inc *! -----------------------------------------------------------------------------** *! *! 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 3 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, see <http://www.gnu.org/licenses/>. *! -----------------------------------------------------------------------------** *! $Log: camogm_interface.php,v $ *! Revision 1.23 2013/05/28 01:49:19 dzhimiev *! 1. fixed list-command *! *! Revision 1.22 2013/05/26 04:41:32 dzhimiev *! 1. minor changes to avoid php hanging when not communicating with camogm *! *! Revision 1.21 2012/04/14 01:25:12 dzhimiev *! 1. added 'list' - shows files at the specified path *! *! Revision 1.20 2011/06/02 12:29:07 oneartplease *! added new option to set_start_after_timestamp to allow setting record start time in the future without first having to read current camera time "p5" as parameter will start recording at camera time "p"lus 5 seconds *! *! Revision 1.19 2011/04/04 20:19:36 dzhimiev *! 1. added frame skipping option *! *! Revision 1.18 2011/01/01 13:04:47 oneartplease *! added commands to set frameskipping and secondsskipping (timelapse) *! *! Revision 1.17 2010/08/20 20:16:55 oneartplease *! cleaned up setcookie commands *! *! Revision 1.16 2010/08/08 20:19:46 dzhimiev *! 1. added write/read elphel parameters *! 2. camogm: debuglev , start_after_timestamp *! *! Revision 1.15 2010/06/24 17:31:55 dzhimiev *! 1. added camogm process run check (ps | grep camogm) *! *! Revision 1.14 2010/01/19 10:07:20 oneartplease *! added unmounting command *! *! Revision 1.12 2009/10/13 12:42:31 oneartplease *! moved save_gp=1 command *! *! Revision 1.11 2009/06/24 15:20:04 oneartplease *! file renaming works with absolute paths now as preparation for mounting multiple devices *! *! Revision 1.5 2009/03/26 12:20:40 oneartplease *! audio and geotagging updates, both are not fully working yet though *! *! Revision 1.9 2009/01/14 08:26:19 oneartplease *! minor updates *! *! *! Revision 1.0 2008/09/21 Sebastian Pichelhofer *! start and stop commands for ajax execution *! */ $cmd = $_GET['cmd']; $debug = $_GET['debug']; $debuglev = $_GET['debuglev']; $cmd_pipe = "/var/state/camogm_cmd"; $cmd_state = "/var/state/camogm.state"; $cmd_port = "3456"; $default_state = "/home/root/camogm.disk"; $start_str = "camogm -n " . $cmd_pipe . " -p " . $cmd_port; if ($cmd == "run_camogm") { $camogm_running = false; exec('ps | grep "camogm"', $arr); function low_daemon($v) { return (substr($v, -1) != ']'); } $p = (array_filter($arr, "low_daemon")); $check = implode("<br />",$p); $state_file = get_state_path(); $start_str = $start_str . " -s " . $state_file; if (strstr($check, $start_str)) $camogm_running = true; else $camogm_running = false; if(!$camogm_running) { exec("rm " . $cmd_pipe); exec("rm " . $cmd_state); if (!$debug) exec($start_str.' > /dev/null 2>&1 &'); // "> /dev/null 2>&1 &" makes sure it is really really run as a background job that does not wait for input else exec($start_str.$debug.' 2>&1 &'); for($i=0;$i<5;$i++) { if (file_exists($cmd_pipe)) break; sleep(1); } if ($debug) { $fcmd = fopen($cmd_pipe, "w"); fprintf($fcmd,"debuglev=$debuglev"); fclose($fcmd); } // set fast recording mode if there is at least one suitable partition or revert to legacy 'mov' mode $partitions = get_raw_dev(); if (!empty($partitions)) { reset($partitions); $cmd_str = 'format=jpeg;' . 'rawdev_path=' . key($partitions) . ';'; write_cmd_pipe($cmd_str); } else { $cmd_str = 'format=mov;save_gp=1;'; write_cmd_pipe($cmd_str); } } } else if ($cmd == "status") { $pipe="/var/state/camogm.state"; $mode=0777; if(!file_exists($pipe)) { umask(0); posix_mkfifo($pipe,$mode); } $fcmd=fopen($cmd_pipe,"w"); fprintf($fcmd, "xstatus=%s\n",$pipe); fclose($fcmd); $status=file_get_contents($pipe); header("Content-Type: text/xml"); header("Content-Length: ".strlen($status)."\n"); header("Pragma: no-cache\n"); printf("%s", $status); } else if ($cmd == "run_status") { // is camogm running $camogm_running = "not running"; exec('ps | grep "camogm"', $arr); function low_daemon($v) { return (substr($v, -1) != ']'); } $p = (array_filter($arr, "low_daemon")); $check = implode("<br />",$p); if (strstr($check, $start_str)) $camogm_running = "on"; else $camogm_running = "off"; $status="<?xml version='1.0'?><camogm_state>\n<state>".$camogm_running."</state>\n</camogm_state>"; header("Content-Type: text/xml"); header("Content-Length: ".strlen($status)."\n"); header("Pragma: no-cache\n"); printf("%s", $status); } else if ($cmd=="get_hdd_space"){ if (isset($_GET['mountpoint'])) $mountpoint = $_GET['mountpoint']; else $mountpoint = '/mnt/sda1'; xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo disk_free_space($mountpoint); echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="mount") { // mount media like HDD if (isset($_GET['partition'])) $partition = $_GET['partition']; else $partition = '/dev/sda1'; //$partition = '/dev/hda1'; if (isset($_GET['mountpoint'])) $mountpoint = $_GET['mountpoint']; else $mountpoint = '/var/hdd'; exec('mkdir '.$mountpoint); //exec('mkdir /var/hdd'); exec('mount '.$partition." ".$mountpoint); //exec('mount /dev/hda1 /var/hdd'); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo "done"; echo "</".$cmd.">"; xml_footer(); } else if (($cmd=="umount") || ($cmd=="unmount")) { // unmount media like HDD $message = ""; if (isset($_GET['mountpoint'])) { $mountpoint = $_GET['mountpoint']; exec('umount '.$mountpoint); $message = "done"; } else { $message = "missing argument: mountpoint"; } xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo $message; echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="set_quality") { $quality = $_GET['quality']; $sensor_port = $_GET['sensor_port']; $thisFrameNumber=elphel_get_frame($sensor_port); elphel_set_P_value($sensor_port,ELPHEL_QUALITY,$quality+0,$thisFrameNumber); //$thisFrameNumber=elphel_get_frame(); //elphel_wait_frame_abs($thisFrameNumber+3); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo elphel_get_P_value($sensor_port,ELPHEL_QUALITY); echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="get_quality") { $sensor_port = $_GET['sensor_port']; xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo elphel_get_P_value($sensor_port,ELPHEL_QUALITY); echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="set_parameter") { $pname = $_GET['pname']; $pvalue = $_GET['pvalue']; $sensor_port = $_GET['sensor_port']; $thisFrameNumber=elphel_get_frame($sensor_port); $constant=constant("ELPHEL_$pname"); elphel_set_P_value($sensor_port,$constant,$pvalue+0,$thisFrameNumber); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo elphel_get_P_value($sensor_port,$constant); echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="get_parameter") { $pname = $_GET['pname']; $sensor_port = $_GET['sensor_port']; $constant=constant("ELPHEL_$pname"); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo elphel_get_P_value($sensor_port,$constant); echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="set_skip") { $skipping_mask = $_GET['skip_mask']; //!!!sub!!! //exec("fpcf -w 4d $skipping_mask"); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo "done"; echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="list") { if (isset($_GET['path'])) $path = $_GET['path']; else { $message = "the path is not set"; break; } if (is_dir($path)) { $files = scandir($path); foreach ($files as $file){ if (is_file("$path/$file")) $message .= "<f>$path/$file</f>\n"; } }else{ $message = "directory not found"; break; } xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; echo $message; echo "</".$cmd.">"; xml_footer(); } else if ($cmd=="list_raw_devices"){ $devices = get_raw_dev(); foreach ($devices as $device => $size) { echo "<item>"; echo "<raw_device>" . $device . "</raw_device>"; echo "<size>" . round($size / 1048576, 2) . "</size>"; echo "</item>"; } } else if ($cmd=="list_partitions"){ $partitions = get_partitions(); foreach ($partitions as $device=>$size) { echo "<item>"; echo " <device>" . $device . "</device>"; echo " <size>" . round($size / 1048576, 2) . "</size>"; echo "</item>"; } } else { $fcmd = fopen($cmd_pipe, "w"); xml_header(); echo "<command>".$cmd."</command>"; echo "<".$cmd.">"; switch ($cmd) { case "start": fprintf($fcmd,"start;\n"); break; case "stop": fprintf($fcmd,"stop;\n"); exec('sync'); break; case "exit": fprintf($fcmd,"exit;\n"); exec('sync'); break; case "file_rename": // Now requires full path (like "/var/hdd/test1.mov") for file_old // and either a full path or just a filename for file_new if ((!isset($_GET['file_old'])) || (!isset($_GET['file_new']))) { echo "wrong arguments"; break; } $old_name = $_GET['file_old']; $new_name = $_GET['file_new']; if (!strrpos($new_name, "/")) { $new_name = substr($old_name, 0, strrpos($old_name, "/")+1).$new_name; } if ($old_name == $new_name) { echo "filenames match"; break; } if (file_exists($new_name)) { echo "file_new already exists"; break; } if (!file_exists($old_name)) { echo "file_old does not exist"; break; } // no errors found, so do the rename if (rename($old_name, $new_name)) echo "done"; else echo "undefined error"; break; case "listdevices": exec ("cat /proc/partitions", $arr1); exec ("cat /proc/mounts", $arr2); $ret = get_mnt_dev(); $mnt_dev = $ret["devices"]; $j = 0; // first two lines are header and empty line separator, skip them $i = 2; while($i < count($arr1)) { // skip flash and RAM disk partitions if (!strpos($arr1[$i], "mtdblock") && !strpos($arr1[$i], "ram")) { $temp = $arr1[$i]; while(strstr($temp, " ")) { $temp = str_replace(chr(9), " ", $temp); $temp = str_replace(" ", " ", $temp); } if (preg_match_all('/ +[a-z]{3,3}[0-9]{1,1}$/', $temp, $available_partitons) > 0) { // remove leading spaces $partitions[$j] = preg_replace("/^ +/", "", $available_partitons[0][0]); $parts = explode(" ", $temp); $size[$j] = $parts[3]; $j++; } } $i++; } $j = 0; foreach ($partitions as $partition) { $include = false; foreach ($mnt_dev as $dev) { if (strpos($dev, $partition)) $include = true; } if ($include) { echo "<item>"; echo "<partition>/dev/".$partition."</partition>"; echo "<size>".round($size[$j]/1024/1024, 2) ." GB</size>"; $j++; $i = 0; while($i < count($arr2)) { if(strpos($arr2[$i], $partition)) { $parts = explode(" ", $arr2[$i]); $mountpoint = $parts[1]; $filesystem = $parts[2]; } $i++; } if ($mountpoint != "") { echo "<mountpoint>".$mountpoint."</mountpoint>"; $mountpoint = ""; } else { echo "<mountpoint>none</mountpoint>"; } if ($filesystem != "") { echo "<filesystem>".$filesystem."</filesystem>"; $filesystem = ""; } else { echo "<filesystem>none</filesystem>"; } echo "</item>"; } } break; case "mkdir": $dir_name = $_GET['name']; if (isset($dir_name) && (($dir_name != "") || ($dir_name != " "))) { exec('mkdir /var/hdd/'.$dir_name); echo "done"; break; } else break; case "is_hdd_mounted": if (isset($_GET['partition'])) $partition = $_GET['partition']; else $partition = '/dev/sda1'; //$partition = '/dev/hda1'; exec('mount', $arr); $mounted = implode("", $arr); if (strstr($mounted, $partition)) echo substr($mounted, strpos($mounted, $partition),22); else echo "no HDD mounted"; break; case "create_symlink": //exec('ln -s /var/hdd /mnt/flash/html/hdd'); if (isset($_GET['mountpoint'])) $mountpoint = $_GET['mountpoint']; else $mountpoint = "/mnt/sda1"; exec("rm /www/pages/hdd"); exec("ln -sf $mountpoint /www/pages/hdd"); break; // case "list": // if (isset($_GET['path'])) $path = $_GET['path']; // else { // echo "the path is not set"; // break; // } // // if (is_dir($path)) { // $files = scandir($path); // foreach ($files as $file){ // if (is_file("$path/$file")) echo "<f>$path/$file</f>"; // } // }else{ // echo "directory not found"; // break; // } // // break; case "list_files": if (!file_exists('/www/pages/hdd')) { echo "no webshare found"; break; } $dir = $_GET["dir"]; if (isset($dir) && ($dir != "") && ($dir != "/./") && ($dir != "/")) // show "one level up" item if we are not in "home" directory { echo "<file>"; echo "<type>updir</type>"; echo "<name>..</name>"; $file_remove_last_slash = substr($dir, 0, strlen($dir)-1); $file_pos_of_second_last_slash = strrpos($file_remove_last_slash, "/"); $up_file = substr($dir, 0, $file_pos_of_second_last_slash+1); while(strpos($up_file, "//")) { $up_file = str_replace("//", "/", $up_file); } if ($up_file == "") echo "<path>/</path>"; else echo "<path>".$up_file."</path>"; echo "<size>0</size>"; echo "<date>0</date>"; echo "</file>"; } if ($handle = opendir('/www/pages/hdd/'.$dir)) { while ($file = readdir($handle)) { if ($file != "." && $file != "..") { echo "<file>"; echo "<type>"; if (is_dir("/www/pages/hdd/".$dir.$file)) echo "dir"; else echo $extension = substr($file, strrpos($file, '.')+1, strlen($file)); echo "</type>"; echo "<name>".$file."</name>"; echo "<path>".substr($dir, 1).$file."</path>"; $size = filesize("/www/pages/hdd/".$dir.$file); echo "<size>".$size."</size>"; if(!ini_get('date.timezone')){ date_default_timezone_set('GMT'); } $date = date ("d M Y H:i:s", filectime("/www/pages/hdd/".$dir.$file)); echo "<date>".$date."</date>"; echo "</file>"; } } closedir($handle); }else{ echo "no webshare found<br>"; } break; case "set_prefix": $prefix = $_GET['prefix']; fprintf($fcmd, "prefix=%s;\n", $prefix); setcookie("directory", $prefix); break; case "set_debuglev": $debuglev = $_GET['debuglev']; fprintf($fcmd, "debuglev=%s;\n", $debuglev); break; case "set_duration": $duration = $_GET['duration']; fprintf($fcmd, "duration=%s;\n", $duration); break; case "set_size": $size = $_GET['size']; fprintf($fcmd, "length=%s;\n", $size); break; case "set_max_frames": $max_frames = $_GET['max_frames']; fprintf($fcmd, "max_frames=%s;\n", $max_frames); break; case "set_frames_per_chunk": $frames_per_chunk = $_GET['frames_per_chunk']; fprintf($fcmd, "frames_per_chunk=%s;\n", $frames_per_chunk); break; case "set_start_after_timestamp": $start_after_timestamp = $_GET['start_after_timestamp']; // Allow setting start timestamp as relative time with "p3" = plus 3 second // This allows triggering recording in the future without first reading current camera time if (substr($start_after_timestamp, 0, 1) == "p") { $start_after_timestamp = elphel_get_fpga_time() + substr($start_after_timestamp, 1) ; //echo "now: ".elphel_get_fpga_time()." relative: ".$start_after_timestamp; //debug } fprintf($fcmd, "start_after_timestamp=%s;\n", $start_after_timestamp); break; case "set_frameskip": $frameskip_value = $_GET['frameskip']; fprintf($fcmd, "frameskip=%s;\n", $frameskip_value); break; case "set_timelapse": $timelapse_value = $_GET['timelapse']; fprintf($fcmd, "timelapse=%s;\n", $timelapse_value); break; case "init_compressor": $sensor_port = $_GET['sensor_port']; elphel_compressor_run($sensor_port); break; case "check_audio_hardware": exec('arecord -l', $arr1); $audio_hardware = implode("", $arr1); if ($audio_hardware == "") echo "no Audio Hardware detected"; else { $message = substr($audio_hardware, strpos($audio_hardware, "],")+2); $message = substr($message, 1, strpos($message, "[")-2); echo $message; } break; case "test_audio_playback": $soundfile = $_GET['soundfile']; exec('aplay '.$soundfile); break; case "setmov": exec('echo "format=mov;" > /var/state/camogm_cmd'); // Set quicktime *.mov as default format after startup. exec('echo "save_gp=1;\n" > /var/state/camogm_cmd'); // enable calculation of free/used buffer space break; case "setjpeg": exec('echo "format=jpg;" > /var/state/camogm_cmd'); // Set quicktime *.mov as default format after startup. exec('echo "save_gp=1;\n" > /var/state/camogm_cmd'); // enable calculation of free/used buffer space break; case "setrawdevpath": $rawdev_path = $_GET['path']; exec('echo "rawdev_path='.$rawdev_path.';" > /var/state/camogm_cmd'); case "gettime": echo elphel_get_fpga_time(); break; } if ($fcmd) fclose($fcmd); echo "</".$cmd.">"; xml_footer(); } function xml_header() { header("Content-type: text/xml"); header("Pragma: no-cache\n"); echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; echo "<camogm_interface>\n"; } function xml_footer() { echo "</camogm_interface>\n"; } /** Get a list of suitable partitions. The list will contain SATA devices only and * will have the following format: "name" => "size_in_blocks". */ function get_partitions() { $names = array(); $regexp = '/([0-9]+) +(sd[a-z0-9]+$)/'; exec("cat /proc/partitions", $partitions); // the first two elements of an array are table header and empty line delimiter, skip them for ($i = 2; $i < count($partitions); $i++) { // select SATA devices only if (preg_match($regexp, $partitions[$i], $name) == 1) { $names[$name[2]] = $name[1]; $j++; } } return $names; } /** Get a list of disk devices which have file system and can be mounted. This function * uses 'blkid' command from busybox. */ function get_mnt_dev() { $partitions = get_partitions(); foreach ($partitions as $partition => $size) { $res = array(); $dev = "/dev/" . $partition; exec("blkid " . $dev, $res); if (!empty($res)) { $devices[$i] = preg_replace('/: +.*/', "", $res[0]); if (preg_match('/(?<=TYPE=")[a-z0-9]+(?=")/', $res[0], $fs) == 1) $fs_types[$i] = $fs[0]; else $fs_types[$i] = "none"; $i++; } } return array("devices" => $devices, "types" => $fs_types); } /** Get a list of devices whithout file system which can be used for raw disk storage from camogm. */ function get_raw_dev() { $j = 0; $ret = get_mnt_dev(); $devices = $ret["devices"]; $types = $ret["types"]; $names = get_partitions(); // filter out partitions with file system $i = 0; $raw_devices = array(); foreach ($names as $name => $size) { $found = false; foreach ($devices as $device) { if (strpos($device, $name) !== false) $found = true; } if ($found === false) { // current partition is not found in the blkid list, add it to raw devices $raw_devices["/dev/" . $name] = $size; $i++; } } return $raw_devices; } /** Check if camera was booted from NAND or SD card and modify the path where camogm will save * disk write pointer. */ function get_state_path() { global $default_state; $prefix = '/tmp/rootfs.ro'; if (file_exists($prefix)) { $ret = $prefix . $default_state; } else { $ret = $default_state; } return $ret; } /** Write command to camogm command pipe */ function write_cmd_pipe($cmd_str) { global $cmd_pipe; $fcmd = fopen($cmd_pipe, 'w'); if ($fcmd !== false) { fprintf($fcmd, $cmd_str); fflush($fcmd); fclose($fcmd); } } ?>