Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 1 |
Demonstration How It Works
Read moreThe below demonstration is for Arduino, but it is the same for PHPoC.
1. Login to Google Account via OAuth 2.0 for IoT devices to obtain access_token.
Login process is described in this project on Hackster.
2. When the button is pressed, PHPoC gets picture from camera, and then upload to Google Drive using access_tokenvia Google Drive API.
Google Drive API for uploading file is described in Google document.
How To- Create Google Project from Google Developer Portal and obtain GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET
- Replace GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in task0.php code
- Upload all files to PHPoC Blue. See instruction
- Access Login Page on PHPoC :http://ip_addressand Login to Your Google Account
- Press Button to take Picture
- Check your Google Drive after two second, you will see the taken picture in your Drive.
<html>
<head>
<title>PHPoC / <?echo system("uname -i")?></title>
<meta content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=0.5, width=device-width, user-scalable=yes" name="viewport">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto" type="text/css">
<style>
body { text-align:center; }
.center {
margin: auto;
position: absolute;
-webkit-backface-visibility: hidden;
left:0;
right:0;
text-align: center;
top: 20%;
}
.hearder {
width: 100%;
max-width:400px;
color: #008B8B;
padding: 5px;
border-bottom: solid;
margin-bottom: 5px;
font-size: 200%;
display: inline-block;
}
.wc_text, .loader {
display: inline-block;
width: 100%;
max-width:300px;
line-height: 150%;
}
.code {
font-family: "Courier New", Courier, monospace;
font-size: 150%;
font-weight: bold;
color: #A52A2A;
}
.success {font-weight: bold; color: #A52A2A;}
/*loading icon*/
.lds-roller {
display: inline-block;
position: relative;
width: 64px;
height: 64px;
}
.lds-roller div {
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
transform-origin: 32px 32px;
}
.lds-roller div:after {
content: " ";
display: block;
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
background: #A52A2A;
margin: -3px 0 0 -3px;
}
.lds-roller div:nth-child(1) {animation-delay: -0.036s;}
.lds-roller div:nth-child(1):after {top: 50px;left: 50px;}
.lds-roller div:nth-child(2) {animation-delay: -0.072s;}
.lds-roller div:nth-child(2):after {top: 54px;left: 45px;}
.lds-roller div:nth-child(3) {animation-delay: -0.108s;}
.lds-roller div:nth-child(3):after {top: 57px;left: 39px;}
.lds-roller div:nth-child(4) {animation-delay: -0.144s;}
.lds-roller div:nth-child(4):after {top: 58px;left: 32px;}
.lds-roller div:nth-child(5) {animation-delay: -0.18s;}
.lds-roller div:nth-child(5):after {top: 57px;left: 25px;}
.lds-roller div:nth-child(6) {animation-delay: -0.216s;}
.lds-roller div:nth-child(6):after {top: 54px;left: 19px;}
.lds-roller div:nth-child(7) {animation-delay: -0.252s;}
.lds-roller div:nth-child(7):after {top: 50px;left: 14px;}
.lds-roller div:nth-child(8) {animation-delay: -0.288s;}
.lds-roller div:nth-child(8):after {top: 45px;left: 10px;}
@keyframes lds-roller {0% {transform: rotate(0deg);}100% {transform: rotate(360deg);}}
</style>
<script>
var ws;
function init()
{
ws = new WebSocket("ws://<?echo _SERVER("HTTP_HOST")?>/login", "text.phpoc");
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
function ws_onopen()
{
if(ws && (ws.readyState == 1))
ws.send('google\r\n');
}
function ws_onclose()
{
alert('CANNOT connect to device. Please reload webpage');
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
var obj = JSON.parse(e_msg.data);
var wc_text = document.getElementById('wc_text');
if(obj.action == 'LOGIN')
{
wc_text.innerHTML = 'Next, visit <a href="' + obj.verification_url + '" target="_blank">' + obj.verification_url + '</a> and enter this code:<br>';
wc_text.innerHTML += '<span class="code">' + obj.user_code + '</span>';
}
else
if(obj.action == 'SUCCESS')
{
document.getElementById('loader').style.display = 'none';
wc_text.innerHTML = '<span class="success">Success!</span><br>';
wc_text.innerHTML += 'You are now logged in from PHPoC';
}
}
window.onload = init;
</script>
</head>
<body>
<div class="center">
<div class="hearder">
<div style="font-size: 150%">
<span style="color:#4285F4">G</span>
<span style="color:#EA4335;">o</span>
<span style="color:#FBBC05;">o</span>
<span style="color:#4285F4;">g</span>
<span style="color:#34A853;">l</span>
<span style="color:#EA4335;">e</span>
</div>
Login for PHPoC
</div>
<br><br>
<div class="wc_text" id="wc_text"></div><br><br>
<div class="loader" id="loader">
<div class="lds-roller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
</div>
</div>
</body>
</html>
<?php
if(_SERVER("REQUEST_METHOD"))
exit; // avoid php execution via http request
include_once "/lib/sn_tcp_ws.php";
include_once "/lib/sn_http_b2_2.php";
include_once "/lib/sn_json_b1.php";
include_once "/lib/sd_340.php";
include_once "/lib/sc_envu.php";
include_once "/lib/vd_uart_camera.php";
// Replace your GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET here
define("GOOGLE_CLIENT_ID", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com");
define("GOOGLE_CLIENT_SECRET", "xxxxxxxxxxxxxxxxxxxxxxxx");
function http($method, $url, $body)
{
http_req_header("Accept: */*");
http_req_header("Content-Type: application/x-www-form-urlencoded");
$resp_head = http_request($method, $url, $body);
$resp_body = "";
if($resp_head !== "")
$rlen = http_read_sync($resp_body);
http_close();
//echo "HTTP RESPONSE HEADER:\r\n$resp_head";
//echo "HTTP RESPONSE BODY:\r\n$resp_body\r\n\r\n\r\n";
return $resp_body;
}
function upload_file($access_token)
{
if($picture_len = camera_get_picture())
{
$file_name = "PHPoC_" . date("YmdHis");
$boundary = "foo_bar_baz";
$metadata = "--$boundary\r\n";
$metadata .= "Content-Type: application/json; charset=UTF-8\r\n\r\n";
$metadata .= "{\"title\": \"$file_name\"}\r\n\r\n";
$jpeg_boundary = "--$boundary\r\n";
$jpeg_boundary .= "Content-Type: image/jpeg\r\n\r\n";
$end_boundary = "\r\n--$boundary--";
$body_len = strlen($metadata) + strlen($jpeg_boundary) + $picture_len + strlen($end_boundary);
http_req_header("Accept: */*");
http_req_header("Content-Type: multipart/related; boundary=$boundary");
http_req_header("Authorization: Bearer $access_token");
$url = "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart";
http_start("POST", $url, $body_len);
while(1)
{
$resp_head = http_loop();
if($resp_head === HTTP_STATE_REQ_BODY)
{
http_req_body($metadata);
http_req_body($jpeg_boundary);
$packet_num = camera_packet_num();
for($i = 0; $i < $packet_num; $i++)
{
$packet = camera_get_packet($i);
http_req_body($packet);
}
$packet = camera_get_packet($i);
http_req_body($end_boundary);
}
else
if(!is_string($resp_head))
usleep(1000);
else
break;
}
$resp_body = "";
if($resp_head !== "")
$rlen = http_read_sync($resp_body);
http_close();
//echo "HTTP RESPONSE HEADER:\r\n$resp_head";
echo "$resp_body";
return $resp_body;
}
}
function google_oauth_login()
{
global $access_token, $refresh_token, $expires_at;
// Step 1: Request device and user codes
$url = "https://accounts.google.com/o/oauth2/device/code";
$body = "client_id=" . GOOGLE_CLIENT_ID;
$body .= "&scope=https://www.googleapis.com/auth/drive.file";
$response = http("POST", $url, $body);
if($response)
{
// Step 2: Handle the authorization server response
$device_code = json_text_value(json_search($response, "device_code"));;
$user_code = json_text_value(json_search($response, "user_code"));
$verification_url = json_text_value(json_search($response, "verification_url"));
$expires_in = json_text_value(json_search($response, "expires_in"));
$interval = json_text_value(json_search($response, "interval"));
// Step 3: Display the user code
$msg = '{"provider": "google",';
$msg .= '"action": "LOGIN",';
$msg .= '"verification_url": "' . $verification_url . '",';
$msg .= '"user_code": "' . $user_code . '"';
$msg .= '}';
ws_write(1, $msg);
echo "Next, visit $verification_url on your desktop or smartphone and enter this code: $user_code\r\n";
// Step 5: Poll authorization server
$url = "https://www.googleapis.com/oauth2/v4/token";
$body = "client_id=" . GOOGLE_CLIENT_ID;
$body .= "&client_secret=" . GOOGLE_CLIENT_SECRET;
$body .= "&code=$device_code";
$body .= "&grant_type=http://oauth.net/grant_type/device/1.0";
$loop_count = (int)$expires_in / (int)$interval;
for($i = 0; $i <= $loop_count; $i++)
{
//if(ws_state(1) != TCP_CONNECTED)
//break;
sleep((int)$interval);
if(($response = http("POST", $url, $body)))
{
$access_token = json_text_value(json_search($response, "access_token"));
$refresh_token = json_text_value(json_search($response, "refresh_token"));
$expires_in = json_text_value(json_search($response, "expires_in"));
if($access_token)
{
echo "access_token:", $access_token, "\r\n";
// Step 6: Upload Image to Google Drive
//echo upload_file($access_token);
$expires_at = time() + (int)$expires_in - 60;
$envu = envu_read("envu");
envu_update($envu, "access_token", $access_token);
envu_update($envu, "expires_at", "$expires_at");
envu_update($envu, "refresh_token", $refresh_token);
envu_write("envu", $envu, strlen($envu), 0);
$msg = '{"provider": "google",';
$msg .= '"action": "SUCCESS"}';
ws_write(1, $msg);
return $access_token;
}
}
}
}
return "";
}
function google_oauth_exchange_token()
{
global $access_token, $refresh_token, $expires_at;
$url = "https://www.googleapis.com/oauth2/v4/token";
$body = "client_id=" . GOOGLE_CLIENT_ID;
$body .= "&client_secret=" . GOOGLE_CLIENT_SECRET;
$body .= "&refresh_token=$refresh_token";
$body .= "&grant_type=refresh_token";
$response_1 = "";
$response_2 = "";
$rlen = http("POST", $url, $body, $response_1, $response_2);
if($rlen <= MAX_STRING_LEN)
{
$access_token = json_text_value(json_search($response_1, "access_token"));
$expires_in = json_text_value(json_search($response_1, "expires_in"));
$expires_at = time() + (int)$expires_in - 60;
envu_update($envu, "access_token", $access_token);
envu_update($envu, "expires_at", "$expires_at");
envu_write("envu", $envu, strlen($envu), 0);
return $access_token;
echo "get NEW access token\r\n";
}
else
echo "exceed MAX_STRING_LEN\r\n";
return "";
}
ws_setup(1, "login", "text.phpoc");
uio_setup(0, 20, "in_pu");
while(!camera_init(0, CT_JPEG, PR_160x120, JR_640x480))
;
$envu = envu_read("envu");
$access_token = envu_find($envu, "access_token");
$refresh_token = envu_find($envu, "refresh_token");
$expires_at = envu_find($envu, "expires_at");
$button_pre_state = uio_in(0, 20);
while(1)
{
if(ws_state(1) == TCP_CONNECTED)
{
$rbuf = "";
$rlen = ws_read_line(1, $rbuf);
if($rlen)
{
$provider = rtrim($rbuf, "\r\n");
if($provider == "google")
google_oauth_login();
}
}
$in_value = uio_in(0, 20);
if($button_pre_state != $in_value && $in_value == 1)
{
if($access_token != "")
{
if((int)$expires_at < time())
{
$access_token = "";
if($refresh_token)
google_oauth_exchange_token();
else
echo "NO refresh_token!!!!!!!!\r\n";
}
if($access_token)
upload_file($access_token);
}
}
$button_pre_state = $in_value;
}
?>
<?php
// $psp_id sn_http.php date 20181004
include_once "/lib/sn_dns.php";
define("HTTP_STATE_CLOSED", 0);
define("HTTP_STATE_RR_A", 1);
define("HTTP_STATE_CONNECT", 2);
define("HTTP_STATE_HEADER", 3);
define("HTTP_STATE_BODY", 4);
define("HTTP_STATE_CHUNK_CRLF", 5);
define("HTTP_STATE_CHUNK_LEN", 6);
define("HTTP_STATE_CHUNK", 7);
define("HTTP_STATE_REQ_BODY", 8);
define("HTTP_VERSION", "HTTP/1.1");
define("HTTP_RECV_TIMEOUT", 10); // receiving header & read_sync timeout
$sn_http_state = 0;
$sn_http_tcp_pid = 0;
$sn_http_ip6 = false;
$sn_http_protocol = "";
$sn_http_method = "";
$sn_http_host = "";
$sn_http_port = 0;
$sn_http_path = "";
$sn_http_req_header = "";
$sn_http_req_body_len = "";
$sn_http_chunk_len = 0;
$sn_http_query_count = 0;
$sn_http_next_tick = 0;
function sn_http_get_tick()
{
while(($pid = pid_open("/mmap/st9", O_NODIE)) == -EBUSY)
usleep(500);
if(!pid_ioctl($pid, "get state"))
pid_ioctl($pid, "start");
$tick = pid_ioctl($pid, "get count");
pid_close($pid);
return $tick;
}
function sn_http_cleanup()
{
global $sn_http_state, $sn_http_tcp_pid;
global $sn_http_req_header;
if($sn_http_tcp_pid)
{
if(pid_ioctl($sn_http_tcp_pid, "get state") != TCP_CLOSED)
pid_ioctl($sn_http_tcp_pid, "close");
}
$sn_http_req_header = "";
$sn_http_chunk_len = 0;
$sn_http_state = HTTP_STATE_CLOSED;
}
function http_setup($udp_id, $tcp_id, $dns_server = "", $ip6 = false)
{
global $sn_http_tcp_pid, $sn_http_ip6;
$sn_http_tcp_pid = pid_open("/mmap/tcp$tcp_id");
$sn_http_ip6 = $ip6;
dns_setup($udp_id, $dns_server, $ip6);
}
// internal function header() is for http response
// http_req_header() is for http request
function http_req_header($field)
{
global $sn_http_state;
global $sn_http_req_header;
if($sn_http_state != HTTP_STATE_CLOSED)
{
echo "http_req_header: session busy\r\n";
return;
}
// don't use explode(). field value may contain ':'
$pos = strpos($field, ":");
if($pos === false)
{
echo "http_req_header: invalid header field $field\r\n";
return;
}
$field_name = ltrim(rtrim(substr($field, 0, $pos)));
if(!$field_name)
{
echo "http_req_header: invalid header field $field\r\n";
return;
}
if(strlen($field) > ($pos + 1))
$field_value = ltrim(rtrim(substr($field, $pos + 1)));
else
$field_value = "";
$sn_http_req_header .= ($field_name . ":");
if($field_value)
$sn_http_req_header .= (" " . $field_value);
$sn_http_req_header .= "\r\n";
}
function http_auth($auth_id, $auth_pwd, $method = "Basic")
{
if($method != "Basic")
{
echo "http_auth: unsupported authorization method \"$method\"\r\n";
return;
}
$enc_id_pwd = system("base64 enc %1", "$auth_id:$auth_pwd");
http_req_header("Authorization: $method $enc_id_pwd");
}
function http_find_header($header, $field_name)
{
$pos = strpos($header, "\r\n");
if($pos === false)
return "";
$status_line = substr($header, 0, $pos);
switch(strtoupper($field_name))
{
case "STATUS-LINE":
return $status_line;
case "HTTP-VERSION":
return substr($status_line, 0, 8);
case "STATUS-CODE":
return substr($status_line, 9, 3);
case "REASON-PHRASE":
return substr($status_line, 13);
}
$header_array = explode("\r\n", $header);
$header_count = count($header_array) - 1;
for($i = 0; $i < $header_count; $i++)
{
$field = $header_array[$i];
$pos = strpos($field, ":");
if($pos === false)
continue;
if(strtoupper(substr($field, 0, $pos)) == strtoupper($field_name))
return ltrim(rtrim(substr($field, $pos + 1)));
}
return false;
}
function sn_http_connect($addr, $port)
{
global $sn_http_state, $sn_http_tcp_pid;
global $sn_http_protocol;
if(!$sn_http_tcp_pid)
$sn_http_tcp_pid = pid_open("/mmap/tcp0");
if($sn_http_protocol == "https")
{
pid_ioctl($sn_http_tcp_pid, "set api ssl");
pid_ioctl($sn_http_tcp_pid, "set ssl method tls1_client");
}
echo "sn_http: connect to $addr:$port...";
pid_bind($sn_http_tcp_pid, "", 0);
pid_connect($sn_http_tcp_pid, $addr, $port);
$sn_http_state = HTTP_STATE_CONNECT;
}
function sn_http_loop_rr()
{
global $sn_http_ip6;
global $sn_http_host, $sn_http_port;
global $sn_http_query_count;
$rr = dns_loop();
if($rr === false)
return false;
if($rr == "")
{
if($sn_http_query_count)
{
echo "sn_http: retry lookup $sn_http_host\r\n";
if($sn_http_ip6)
dns_send_query($sn_http_host, RR_AAAA, 1000);
else
dns_send_query($sn_http_host, RR_A, 1000);
$sn_http_query_count--;
return false;
}
else
{
echo "sn_http: lookup failed\r\n";
return "";
}
}
sn_http_connect($rr, $sn_http_port);
return false;
}
function http_loop()
{
global $sn_http_state, $sn_http_tcp_pid, $sn_http_ip6, $sn_http_protocol;
global $sn_http_method, $sn_http_host, $sn_http_port, $sn_http_path;
global $sn_http_req_header, $sn_http_req_body_len;
global $sn_http_next_tick;
if($sn_http_state == HTTP_STATE_CLOSED)
return "";
switch($sn_http_state)
{
case HTTP_STATE_RR_A:
if(sn_http_loop_rr() === "")
{
sn_http_cleanup();
return "";
}
break;
case HTTP_STATE_CONNECT:
$state = pid_ioctl($sn_http_tcp_pid, "get state");
if($state == TCP_CLOSED)
{
echo "failed\r\n";
sn_http_cleanup();
return "";
}
else
{
$connected = false;
if(($sn_http_protocol == "https") && ($state == SSL_CONNECTED))
$connected = true;
if(($sn_http_protocol == "http") && ($state == TCP_CONNECTED))
$connected = true;
if($connected)
{
echo "ok\r\n";
$sn_http_next_tick = sn_http_get_tick() + HTTP_RECV_TIMEOUT * 1000;
pid_send($sn_http_tcp_pid, $sn_http_method . " ");
pid_send($sn_http_tcp_pid, $sn_http_path . " " . HTTP_VERSION . "\r\n");
pid_send($sn_http_tcp_pid, "Host: $sn_http_host\r\n");
pid_send($sn_http_tcp_pid, "Connection: close\r\n");
if($sn_http_method == "POST")
pid_send($sn_http_tcp_pid, "Content-Length: $sn_http_req_body_len\r\n");
if($sn_http_req_header)
pid_send($sn_http_tcp_pid, $sn_http_req_header);
pid_send($sn_http_tcp_pid, "\r\n");
$sn_http_state = HTTP_STATE_REQ_BODY;
}
}
break;
case HTTP_STATE_REQ_BODY:
if($sn_http_req_body_len <= 0)
$sn_http_state = HTTP_STATE_HEADER;
return $sn_http_state;
case HTTP_STATE_HEADER:
$len = pid_ioctl($sn_http_tcp_pid, "get rxlen \r\n\r\n");
if($len)
{
$resp_head = "";
pid_recv($sn_http_tcp_pid, $resp_head, $len);
if(http_find_header($resp_head, "Transfer-Encoding") === "chunked")
$sn_http_state = HTTP_STATE_CHUNK_LEN;
else
$sn_http_state = HTTP_STATE_BODY;
return $resp_head;
}
$state = pid_ioctl($sn_http_tcp_pid, "get state");
if(($state != TCP_CONNECTED) && ($state != SSL_CONNECTED))
{
echo "sn_http: connection closed\r\n";
sn_http_cleanup();
return "";
}
if(sn_http_get_tick() >= $sn_http_next_tick)
{
echo "sn_http: request timeout\r\n";
sn_http_cleanup();
return "";
}
break;
}
return false;
}
function http_start($method, $uri, $body_len = 0)
{
global $sn_http_state, $sn_http_ip6;
global $sn_http_protocol, $sn_http_method;
global $sn_http_host, $sn_http_port, $sn_http_path;
global $sn_http_req_body_len;
global $sn_http_query_count;
if($sn_http_state != HTTP_STATE_CLOSED)
{
echo "http_start: session busy\r\n";
return;
}
$sn_http_method = strtoupper($method);
$pos = strpos($uri, "://");
if($pos === false)
$sn_http_protocol = "http";
else
{
$sn_http_protocol = strtolower(substr($uri, 0, $pos));
$uri = substr($uri, $pos + 3);
}
$pos = strpos($uri, "/");
if($pos === false)
{
$sn_http_host = $uri;
$sn_http_path = "/";
}
else
{
$sn_http_host = substr($uri, 0, $pos);
$sn_http_path = substr($uri, $pos);
}
$pos = strpos($sn_http_host, ":");
if($pos === false)
{
if($sn_http_protocol == "https")
$sn_http_port = 443;
else
$sn_http_port = 80;
}
else
{
$sn_http_port = (int)substr($sn_http_host, $pos + 1);
$sn_http_host = substr($sn_http_host, 0, $pos);
}
$sn_http_req_body_len = $body_len;
if(inet_pton($sn_http_host) === false)
{
if($sn_http_ip6)
dns_send_query($sn_http_host, RR_AAAA, 500);
else
dns_send_query($sn_http_host, RR_A, 500);
$sn_http_query_count = 2;
$sn_http_state = HTTP_STATE_RR_A;
}
else
sn_http_connect($sn_http_host, $sn_http_port);
}
function http_req_body($body)
{
global $sn_http_tcp_pid, $sn_http_req_body_len;
$sn_http_req_body_len -= strlen($body);
pid_send($sn_http_tcp_pid, $body);
}
function http_request($method, $uri, $body = "")
{
$body_len = strlen($body);
http_start($method, $uri, $body_len);
while(1)
{
$resp_head = http_loop();
if($resp_head === HTTP_STATE_REQ_BODY)
{
http_req_body($body);
}
else
if(!is_string($resp_head))
usleep(1000);
else
return $resp_head;
}
}
function http_state()
{
global $sn_http_state;
return $sn_http_state;
}
function sn_http_rxlen()
{
global $sn_http_state, $sn_http_tcp_pid;
global $sn_http_chunk_len;
if($sn_http_state == HTTP_STATE_BODY)
return pid_ioctl($sn_http_tcp_pid, "get rxlen");
if($sn_http_state == HTTP_STATE_CHUNK_CRLF)
{
if(pid_ioctl($sn_http_tcp_pid, "get rxlen") > 2)
{
$rbuf = "";
pid_recv($sn_http_tcp_pid, $rbuf, 2);
if($rbuf != "\r\n")
echo "sn_http: invalid chunk trailer\r\n";
//echo "sn_http: trailing CRLF\r\n";
$sn_http_state = HTTP_STATE_CHUNK_LEN;
}
else
return 0;
}
if($sn_http_state == HTTP_STATE_CHUNK_LEN)
{
if($rlen = pid_ioctl($sn_http_tcp_pid, "get rxlen \r\n"))
{
$rbuf = "";
pid_recv($sn_http_tcp_pid, $rbuf, $rlen);
$sn_http_chunk_len = bin2int(hex2bin($rbuf), 0, 2, true);
//echo "sn_http: chunk_len $sn_http_chunk_len\r\n";
if($sn_http_chunk_len)
$sn_http_state = HTTP_STATE_CHUNK;
else
$sn_http_state = HTTP_STATE_BODY;
}
else
return 0;
}
if($sn_http_state == HTTP_STATE_CHUNK)
{
if($sn_http_chunk_len)
{
$rlen = pid_ioctl($sn_http_tcp_pid, "get rxlen");
if($rlen > $sn_http_chunk_len)
return $sn_http_chunk_len;
else
return $rlen;
}
else
{
$sn_http_state = HTTP_STATE_CHUNK_CRLF;
return 0;
}
}
return 0;
}
function http_read(&$rbuf, $rlen = MAX_STRING_LEN)
{
global $sn_http_state, $sn_http_tcp_pid;
global $sn_http_chunk_len;
if($sn_http_state < HTTP_STATE_BODY)
return 0;
$state = pid_ioctl($sn_http_tcp_pid, "get state");
if(($state != TCP_CONNECTED) && ($state != SSL_CONNECTED))
{
if(!pid_ioctl($sn_http_tcp_pid, "get rxlen"))
{
sn_http_cleanup();
return 0;
}
}
$rxlen = sn_http_rxlen();
if($rxlen)
{
if($rlen > $rxlen)
$rlen = $rxlen;
if($sn_http_state == HTTP_STATE_CHUNK)
{
$sn_http_chunk_len -= $rlen;
if($sn_http_chunk_len < 0)
{
echo "http_read: chunk underflow $sn_http_chunk_len\r\n";
$sn_http_chunk_len = 0;
}
}
return pid_recv($sn_http_tcp_pid, $rbuf, $rlen);
}
else
return 0;
}
function http_read_sync(&$rbuf, $rlen = MAX_STRING_LEN)
{
global $sn_http_state;
if($sn_http_state < HTTP_STATE_BODY)
return 0;
$rbuf = "";
$frag = "";
$timeout_tick = sn_http_get_tick() + HTTP_RECV_TIMEOUT * 1000;
while($rlen)
{
$len = http_read($frag, $rlen);
if($len)
{
$rbuf .= $frag;
$rlen -= $len;
}
else
usleep(1000);
if($sn_http_state == HTTP_STATE_CLOSED)
break;
if(sn_http_get_tick() >= $timeout_tick)
{
echo "http_read_sync: timeout\r\n";
break;
}
}
return strlen($rbuf);
}
function http_close()
{
sn_http_cleanup();
}
?>
<?php
// camera command
define("CAM_CMD_PREFIX", 0xAA);
define("CAM_CMD_SYNC", 0x0D);
define("CAM_CMD_ACK", 0x0E);
define("CAM_CMD_NAK", 0x0F);
define("CAM_CMD_INITIAL", 0x01);
define("CAM_CMD_DATA", 0x0A);
define("CAM_CMD_RESET", 0x08);
define("CAM_CMD_POWEROFF", 0x09);
define("CAM_CMD_BAUDRATE", 0x07);
define("CAM_CMD_PACKAGESIZE", 0x06);
define("CAM_CMD_SNAPSHOT", 0x05);
define("CAM_CMD_GETPICTURE", 0x04);
define("CAM_CMD_LIGHTFREQ", 0x13);
//Color Type
define("CT_GRAYSCALE_2", 0x01);
define("CT_GRAYSCALE_4", 0x02);
define("CT_GRAYSCALE_8", 0x03);
define("CT_COLOR_12", 0x05);
define("CT_COLOR_16", 0x06);
define("CT_JPEG", 0x07);
//Preview Resolution
define("PR_80x60", 0x01);
define("PR_160x120", 0x03);
// JPEG Resolution
define("JR_80x64", 0x01);
define("JR_160x128", 0x03);
define("JR_320x240", 0x05);
define("JR_640x480", 0x07);
define("PIC_PKT_LEN", 1000); //data length of each read, dont set this too big because ram is limited
// server to client
define("_CMD_CAMERA_DATA_START", 0x14);
define("_CMD_CAMERA_DATA", 0x15);
define("_CMD_CAMERA_DATA_STOP", 0x16);
$camera_uart_id = 0;
$camera_packet_num = 0;
$camera_last_packet_len = 0;
function set_uart($id)
{
global $camera_uart_id;
$camera_uart_id = $id;
}
function clear_rx_buf()
{
global $camera_uart_id;
$rbuf = "";
$len = uart_read($camera_uart_id, $rbuf);
//log
if($len)
{
echo "clear:<<", bin2hex($rbuf), "\r\n";
}
}
function send_cmd($cmd, $CAM_CMD_len)
{
global $camera_uart_id;
for ($i = 0; $i < $CAM_CMD_len; $i++)
{
$wbuf = int2bin(($cmd[$i]&0xff),1);
uart_write($camera_uart_id, $wbuf, 1);
}
}
function read_bytes(&$dest, $len, $timeout)
{
global $camera_uart_id;
$pid_st0 = pid_open("/mmap/st0");
pid_ioctl($pid_st0, "set mode free");
pid_ioctl($pid_st0, "set dir up");
pid_ioctl($pid_st0, "set div ms");
pid_ioctl($pid_st0, "start");
$tick = pid_ioctl($pid_st0, "get count");
$rlen = 0;
while($tick < $timeout)
{
if(($rlen = uart_readn($camera_uart_id, $dest, $len)) == $len)
{
break;
}
$tick = pid_ioctl($pid_st0, "get count");
}
pid_close($pid_st0);
return $rlen;
}
function camera_wait_for_ACK($time_out, $command)
{
$resp = "";
if (read_bytes($resp, 6, $time_out) == 6)
{
if (bin2int($resp, 0, 1) == CAM_CMD_PREFIX
&& bin2int($resp, 1, 1) == (CAM_CMD_ACK )
&& bin2int($resp, 2, 1) == $command )
{
//echo "camera: received ACK\r\n";
return true;
}
}
//echo "camera: not receive ACK\r\n";
return false;
}
function camera_init($uart_id, $color_type, $preview_resolution, $jpeg_resolution)
{
global $camera_uart_id;
$camera_uart_id = $uart_id;
uart_setup($uart_id, 115200);
$cmd = array(CAM_CMD_PREFIX, CAM_CMD_SYNC, 0x00, 0x00, 0x00, 0x00);
$resp = "";
echo "camera: CAM_CMD_SYNC...\r\n";
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
send_cmd($cmd,6);
if (camera_wait_for_ACK(100, CAM_CMD_SYNC))
break;
$retry_cnt++;
if($retry_cnt > 20)
return false;
//system("reboot php 100");
usleep(10000);
}
$cmd[1] = CAM_CMD_ACK ;
$cmd[2] = CAM_CMD_SYNC;
send_cmd($cmd, 6);
//initial
echo "camera: CAM_CMD_INITIAL...\r\n";
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_INITIAL , 0x00, $color_type, $preview_resolution, $jpeg_resolution );
$resp = "";
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
send_cmd($cmd, 6);
if (camera_wait_for_ACK(100, CAM_CMD_INITIAL))
break;
$retry_cnt++;
if($retry_cnt > 20)
return false;
//system("reboot php 100");
}
// set packet size
//echo "camera: set CAM_CMD_PACKAGESIZE\r\n";
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_PACKAGESIZE , 0x08, PIC_PKT_LEN & 0xff, (PIC_PKT_LEN>>8) & 0xff ,0);
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
send_cmd($cmd, 6);
if (camera_wait_for_ACK(100, CAM_CMD_PACKAGESIZE))
break;
$retry_cnt++;
if($retry_cnt > 20)
return false;
//system("reboot php 100");
}
return true;
}
function camera_reset($reset = 0x01)
{
//initial
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_RESET , 0x00, 0x00, 0x00, 0x00 );
$resp = "";
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
send_cmd($cmd, 6);
if (camera_wait_for_ACK(100, CAM_CMD_RESET))
break;
$retry_cnt++;
if($retry_cnt > 20)
system("reboot php 100");
}
}
function camera_capture()
{
//snapshot.
//echo "camera: CAM_CMD_SNAPSHOT...\r\n";
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_SNAPSHOT , 0x00, 0x00, 0x00 ,0x00);
$resp = "";
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
send_cmd($cmd, 6);
if (camera_wait_for_ACK(100, CAM_CMD_SNAPSHOT))
break;
$retry_cnt++;
if($retry_cnt > 20)
system("reboot php 100");
}
}
function camera_get_picture()
{
global $camera_packet_num;
global $camera_last_packet_len;
// send get picture command and get total size
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_GETPICTURE , 0x01, 0x00, 0x00 ,0x00);
$resp = "";
$retry_cnt = 0;
while (1)
{
clear_rx_buf();
$retry_cnt++;
send_cmd($cmd, 6);
if($retry_cnt > 5)
return false;
//system("reboot php 100");
if (camera_wait_for_ACK(100, CAM_CMD_GETPICTURE))
{
if (read_bytes($resp, 6, 1000) != 6)
{
continue;
}
if (bin2int($resp, 0, 1) == CAM_CMD_PREFIX
&& bin2int($resp, 1, 1) == (CAM_CMD_DATA )
&& bin2int($resp, 2, 1) == 0x01)
{
$pic_total_len = (bin2int($resp, 3, 1)) | (bin2int($resp, 4, 1) << 8) | (bin2int($resp, 5, 1) << 16);
//echo "\r\npic_total_len: ", $pic_total_len, "\r\n";
break;
}
}
}
// get data
$camera_packet_num = ($pic_total_len) / (PIC_PKT_LEN - 6);
$camera_last_packet_len = PIC_PKT_LEN;
$mod = $pic_total_len % (PIC_PKT_LEN-6);
if ($mod != 0)
{
$camera_packet_num += 1;
$camera_last_packet_len = $mod + 6;
}
echo "pic_total_len: $pic_total_len\r\n";
return $pic_total_len;
}
function camera_packet_num()
{
global $camera_packet_num;
return $camera_packet_num;
}
function camera_get_packet($packet_id)
{
global $camera_packet_num;
global $camera_last_packet_len;
$packet = "";
$cmd = array( CAM_CMD_PREFIX, CAM_CMD_ACK , 0x00, 0x00, 0x00, 0x00 );
if($packet_id < $camera_packet_num)
{
$cmd[4] = $packet_id & 0xff;
$cmd[5] = ($packet_id >> 8) & 0xff;
$retry_cnt = 0;
$retry = true;
if($packet_id < ($camera_packet_num-1))
$len = PIC_PKT_LEN ;
else
{
$len = $camera_last_packet_len;
}
while($retry)
{
usleep(6000);
clear_rx_buf();
$retry_cnt++;
send_cmd($cmd, 6);
$cnt = read_bytes($packet, $len, 1200);
if($cnt)
{
//checksum funtion
/*
$sum = 0;
for ($y = 0; $y < $cnt - 2; $y++)
{
$sum += bin2int($packet, $y, 1);
}
$sum &= 0xff;
if ($sum != bin2int($packet, ($cnt-2), 1))
{
echo "checksum error";
if ($retry_cnt < 100) $retry = true;
else
{
break;
}
}
else */
{
$retry = false;
}
}
if($retry_cnt > 5)
return false;
//system("reboot php 100");
}
if($retry) break;
$data = substr($packet, 4, $cnt-6);
return $data;
}
else
if($packet_id == $camera_packet_num)
{
$cmd[4] = 0xf0;
$cmd[5] = 0xf0;
send_cmd($cmd, 6);
}
else
return false;
return true;
}
?>
Comments
Please log in or sign up to comment.