红外无线温度计

前一段,给Arduino做了一个外壳。材料是有机玻璃再加上 3mm 的铜柱螺丝和螺母的组合,做出来效果还不错。最明显的就是放到论坛上会有很多人关注和讨论。相比OpenCV统计骰子点数的装置,这个盒子的人气高很多。【参考1】

淘宝上有更专业的Arduino外壳,只是价格比较贵。有兴趣的朋友可以像我这样,买一块有机玻璃,再买一把各种螺钉螺母的。

shellarduino

果壳网近期有个手机装置设计大赛,翻翻箱子看看手上有什么能够用起来的东西。最后决定做一个“无线温度计”。除了上面的外壳,还有如下材料:

Arduino Uno
TN901 红外温度传感器
蓝牙模块

简单介绍一下 TN901 ,实物如图(实际我使用的比下面的长一截,多出来一段电路板,不知道是不是考虑到太短了用起来容易焊接不亮,或者容易头重脚轻)

tn901

上图从左到右分别是 A:测试 G:地 C:时钟 D:数据 V:电源【参考】。从另外一个方向看过去,顺序刚好颠倒。用的时候先看一下电路板上哪里是 A 哪里是 V 即可确认方向。刚开始的时候我就接反了,不工作,吓得我一身冷汗(这个小东西要 150元,是我一个月购买材料budget。开发品就是贵啊。相比之下,淘宝上还有50元的测温枪,不同的传感器而已)
论坛上有人之前做过【参考1】,有现成的库可以使用【参考2】,方便啊!
连接上蛮简单,VCC供电(建议选 5V),GND接好之后,剩下三根线,根据库初始化时的提示分别将 Data CLK ACK 连接到 Pin 13 12 11。连接好之后,在串口就能看到数据了。

下面再引入蓝牙模块。入手的是专门Arduino 使用的。简单的说Arduino蓝牙模块=单板+底板。而我刚开始入手的是单板。入手单板之后有点傻眼:小是够小,但是没引出来需要的Pin脚。最后还是买了一个专门 Arduino 使用的了事。

有专门的 TN901的库,因此 Arduino 程序编写要简单的多。

#include <Arduino.h> 
#include <Wire.h>
#include "TN901.h"  //引用库文件
TN901 tn;           //实 例 化
void setup()
{
    Serial.begin(9600);
    tn.Init(13,12,11);  //初 始 化 data clk ack
}
void loop()
{
   tn.Read();
   SerialValue();
   delay(2000);
}

void SerialValue()
{
   String s;
   s=">O"+String(tn.OT, DEC)+"E"+String(tn.ET,DEC)+"<"; 
   Serial.println(s);
   //Serial.print(tn.OT, DEC);
   //Serial.print("ET");
   //Serial.print(tn.ET, DEC);
}

 

出来的两个温度分别是目标温度(tn.OT)和当前的环境温度(tn.ET)。上面的程序将结果放在一个下面这样 >Oxx.xxEyy.yy< 的字符串中发送到串口上。再通过串口蓝牙,我们的电脑就能够收到结果了。

dPsth1-sLLasZ1cLCQ3rMfmbswWAUts6clUKxhVVkLTRAQAAZwIAAFBO

gzpTD5eLLIU02MC-PJLVKXZdGj_FxCdSvfSsH1W16H6QBwAAIAoAAEpQ

供电部分使用的是一个USB充电宝,内部是一节 16580 电池。体积适中,价格也不贵。

FkSGBq2NsJR46BrDWXQG6geid3rNpRCUh42Eeq5dNSqAAgAA4AEAAEpQ

电脑端,使用Delphi 设计了一个简单的界面,用类似任务管理器的界面来展示当前的和部分的历史数据

x4k4h5l-_l7mJqz3KqnSmvqPMmoxITAwhYTGsStQ874BBgAAhAMAAFBO

为了方便起见同时还使用了 CPort VCL 来作为串口通讯。但是个人感觉不是很稳定,因此有机会还是直接使用 API 爱进行通讯比较好。程序下载 IRTemp。Arduino相关库下载:tn9

最后还拍摄了一个应用的演示视频。

http://www.tudou.com/programs/view/dDu_7_c58TA/?resourceId=414535982_06_02_99

参考:
1. http://www.geek-workshop.com/thread-10726-1-1.html用有机玻璃做个arduino外壳

2. http://www.geek-workshop.com/thread-8727-1-1.html DIY红外非接触式温度计

3. http://www.geek-workshop.com/thread-1884-1-1.html如何自己编写Arduino支持的C++类库

4. http://www.zytemp.com/products/tn901.asp Tn9 usermanual

libusb(1)

最近看了一下 libusb 这个开源库(Win32)。然后发现LibUsbDotNet给出了一个USB速度测试Demo,包括软件和Firmware部分。对我来说,最感兴趣的还是 USB Firmware,于是乎研究了一番。他的代码在 \LibUsbDotNet\Src\Benchmark\Firmware 下面。从文档中来看,代码基于PIC的 USB 单片机 Demo 板的,又搜了一下对应开发板的价格…….然后我们谈一下其他的吧…….

PIC系列的单片机是 MicroChip 公司开发的系列产品,覆盖范围非常广。考察下来的结论是:PIC属于那种非常适合公司开发的单片机,是那种有钱所有都有的(开发板,Debug,编辑器,编译器一条龙都能下来),美中不足的就是需要钱,烧写都需要专门的工具(也不得不说他的工具非常强大)。但是对于我这样的,很多时候只是三分钟热血看一眼而已,每月预算有限的爱好者只是看看吧。

然后就开始阅读代码了。但是很奇怪的是,代码似乎不完整。又下载了一个 MPLAB的编译器。经过一个晚上的研究发现:缺少USB Stack。又去找这些东西,最后发现MicroChip会将用到的代码 Publish出来。之后我下载了一个最新的,补充到 LibUsbDotNet 给出的代码中,编译之后发现不通过。查找了一下,应该是我下载的库版本太新,而LibUsbDotNet Firmware用的是老库导致的…….最后用的是 MCHP_App_Lib_v2010_10_19_Installer.zip 。即可正常编译,虽然无法运行,但是理论上不缺代码了。

编译结果:

Capture

编译的Source Code,有板子的朋友可以烧一下看看是否正常

PICUSB

OpenCV在捕获的摄像头上写字

这个实验和之前的画圆的类似,先捕捉图像,然后再上面输出文字。

#include "stdafx.h"
#include "highgui.h"
#include "cv.h"
#include "stdio.h"
#include <ctype.h>
#include <time.h>

int main(int argc,char ** argv)
{
	time_t	t;
	char showMsg[256];

	//the font variable    
    CvFont font; 

       CvCapture *capture = 0;

	   //从摄像头读取
       capture = cvCaptureFromCAM(0);

 
       if(!capture)
       {
              fprintf(stderr,"Could not initialize capturing...\n");
              return -1;
       }
 
       cvNamedWindow("Laplacian",1);
 
       //循环捕捉,直到用户按键跳出循环体
       for(;;)
       {
              IplImage * frame =0;
             
              //抓起一祯
              frame = cvQueryFrame(capture);
 
              if(!frame)
                     break;

	time(&t);
	strftime(showMsg, sizeof(showMsg), "%H%M%S", localtime(&t) ); //格式化输出.
   
    // 初始化字体   
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX, 4.5,1,0,2);//初始化字体,准备写到图片上的   
    // cvPoint 为起笔的x,y坐标   
    cvPutText(frame,showMsg,cvPoint(300,100),&font,CV_RGB(255,0,0));//在图片中输出字符  

              cvShowImage("Laplacian",frame);
 
              if(cvWaitKey(10)>0)
                     break;
       }
       cvReleaseCapture(&capture);
       cvDestroyWindow("Laplacian");
       return 0;
}

 

campaint

参考:

1.http://blog.csdn.net/jiadelin/article/details/2916329 strftime()函数用法
2.http://blog.csdn.net/jinshengtao/article/details/20549221 利用OpenCV给图像添加标注
3.http://blog.csdn.net/ycc892009/article/details/6516528 opencv-在图像上显示字符(不包括中文)

Arduino接收串口字符的问题

随手写了一个小程序,目标是串口收到:‘b’关闭 Pin 13 的LED;当收到 ‘s’ 是打开 LED.

程序如下,很奇怪的现象是:板子上 PIN 13 的LED一直是熄灭的。有兴趣的朋友在看答案之前可以先自己琢磨一下。

#define LED_PIN 13

void setup()
{
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);  
}

void loop()
{
    while (Serial.available() > 0)  
    {
        if ('b'==Serial.read();) 
          {
            digitalWrite(LED_PIN, LOW);
          }
        if ('s'==Serial.read();) 
          {
            digitalWrite(LED_PIN, HIGH);            
          }
    }
}

 

1022186_12845416716A28

真相只有一个,当 Serial Port Available之后,如果你取走了字符,下一个判断就是空了,所以第二个条件永远无法满足……

#define LED_PIN 13

void setup()
{
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);  
}

void loop()
{
  char  c;
  
    while (Serial.available() > 0)  
    {
        c=Serial.read();
        if ('b'==c) 
          {
            digitalWrite(LED_PIN, LOW);
          }
        if ('s'==c) 
          {
            digitalWrite(LED_PIN, HIGH);            
          }
    }
}

 

Step to UEFI (13) —– EADK struct tm

EADK 中的时间,还有一种定义(更准确的说是C标准库中的定义),可以在 \EadkPkg_A2\StdLib\Include\time.h 看到

/** A structure holding the components of a calendar time, called the
    broken-down time.  The first nine (9) members are as mandated by the
    C95 standard.  Additional fields have been added for EFI support.
**/
struct tm {
  int     tm_year;      // years since 1900
  int     tm_mon;       // months since January ?[0, 11]
  int     tm_mday;      // day of the month ?[1, 31]
  int     tm_hour;      // hours since midnight ?[0, 23]
  int     tm_min;       // minutes after the hour ?[0, 59]
  int     tm_sec;       // seconds after the minute ?[0, 60]
  int     tm_wday;      // days since Sunday ?[0, 6]
  int     tm_yday;      // days since January 1 ?[0, 365]
  int     tm_isdst;     // Daylight Saving Time flag
  int     tm_zoneoff;   // EFI TimeZone offset, -1440 to 1440 or 2047
  int     tm_daylight;  // EFI Daylight flags
  UINT32  tm_Nano;      // EFI Nanosecond value
};

 

有两个函数 localtime 和 mktime 可以将时间在 time_t 和 struct tm之间进行转换。

/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
    This program and the accompanying materials
    are licensed and made available under the terms and conditions of the BSD License
    which accompanies this distribution. The full text of the license may be found at
    http://opensource.org/licenses/bsd-license.

    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//#include  <Uefi.h>
//#include  <Library/UefiLib.h>
//#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <time.h>

/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @param[in]  Argc    Number of argument tokens pointed to by Argv.
  @param[in]  Argv    Array of Argc pointers to command line tokens.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{

  time_t t,y;
  struct tm *tb;
  
  time(&t);

  printf("%ld\n",t);

  tb=localtime(&t);
  
  printf("localtime: %s",asctime(tb));

  y=mktime(tb); 
  
  printf("mktime   : %s",ctime(&y));
  
  return 0;
}

 

运行结果

time2

参考:

1.http://ganquan.info/standard-c/function/localtime
2.http://ganquan.info/standard-c/function/mktime

如何在XP上部署OpenCV编写的程序

本文使用环境:

1. XP 下,VS2008
2. 只适合你用Release编译出来的结果,不适合Debug版本(因为我测试Debug版本在XP上始终无法成功,所以删除了所有相关的 *d.dll)
3. 只是简单的测试之类的(如果你想更专业,可以只分发用到的DLL;或者重新编译OpenCV生成 Lib,通过静态编译将内容添加到你的EXE中)

步骤:

1.按照Debug编译,然后在工作机上测试OK
2.将生成的 Release 目录下的全部内容拷贝到dll的目录下 OpenCVXPPackage
3.如果目标机之前没有安装过 VS2008 的支持包,需要先安装一次vcredist2008sp1
4.之后在目标机上运行生成的 EXE 即可

注意:
如果出现 “应用程序正常初始化(0xc0000135)失败。请单击‘确定’,终止应用程序”,请安装 Microsoft .NET Framework 2.0

vcredist2008sp1:
vcredist2008sp1

OpenCVXPPackage(其中包含了一个编译好的测试应用程序):
OpenCVXPPackage

应用程序运行结果:
Capture

VS2008 + hidsdi.h 的问题

目标:编写一个枚举系统中所有USB HID设备的程序。在编写过程中遇到编译链接无法通过的情况,尝试各种方法都不成功。 Google上不去,Baidu的方法基本上都尝试了一遍,产生问题的原因大约是 DDK(3790.1830 算是比较老的版本)中的库和VS2008(Express版本)有冲突。最后琢磨了一下,不妨直接将用到的 Lib 和函数(这个例子只用了一个HidD_GetHidGuid,在 hidsdi.h 中定义),直接放到程序中。结果居然很好用~

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <setupapi.h>
extern "C" {
void __stdcall
HidD_GetHidGuid (
   OUT   LPGUID   HidGuid
   );
typedef struct _HIDD_ATTRIBUTES {
    ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)

    //
    // Vendor ids of this hid device
    //
    USHORT  VendorID;
    USHORT  ProductID;
    USHORT  VersionNumber;

    //
    // Additional fields will be added to the end of this structure.
    //
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;

BOOLEAN __stdcall
HidD_GetAttributes (
    IN  HANDLE              HidDeviceObject,
    OUT PHIDD_ATTRIBUTES    Attributes
    );
}

#pragma comment( lib, "hid.lib" )
#pragma comment( lib, "setupapi.lib" )

#define ShowError() ShowError_(_T(__FILE__),__LINE__)

void ShowError_(LPCTSTR file, long line)
{
    LPVOID lpMsgBuf;
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS
        , NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL );
    _tprintf( _T("---ERROR %s(%ld): %s\n"), file, line, (LPCTSTR)lpMsgBuf );
    LocalFree( lpMsgBuf );
}

int main(array<System::String ^> ^args)
{
	 GUID HidGuid;

	//获取HID设备的接口类GUDI
		HidD_GetHidGuid(&HidGuid);
	//输出一下看看GUID
		printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"
		   , HidGuid.Data1, HidGuid.Data2, HidGuid.Data3
		   , HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]
		   , HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7] );
	
	//根据获得的GUID枚举HID设备
	HDEVINFO hDevInfo = SetupDiGetClassDevs( &HidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
    if( INVALID_HANDLE_VALUE != hDevInfo )
    {
        SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
        for( DWORD index=0; SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,&strtInterfaceData); ++index )
        {
            char buf[1000];
            SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];
            strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
            if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
            {
                _tprintf( _T("[%d] path: %s\n"), index, strtDetailData.DevicePath );

                HANDLE hUsb = CreateFile( strtDetailData.DevicePath, 0//GENERIC_READ|GENERIC_WRITE
                    , FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
                if( INVALID_HANDLE_VALUE != hUsb )
                {
                    // 查询设备标识
                    HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };
                    if( HidD_GetAttributes(hUsb,&strtAttrib) )
                    {
                        _tprintf( _T("VendorID : %hX\n"), strtAttrib.VendorID );
                        _tprintf( _T("ProductID: %hX\n"), strtAttrib.ProductID );
                        _tprintf( _T("VerNumber: %hX\n"), strtAttrib.VersionNumber );
                    }
                    else
                        ShowError();

                    CloseHandle( hUsb );
                }
                else
                    ShowError();
            }
            else
                ShowError();
        }
        if( GetLastError() != ERROR_NO_MORE_ITEMS )
            ShowError();

        SetupDiDestroyDeviceInfoList( hDevInfo );
    }
    else
        ShowError();

	system("PAUSE");
    return 0;
}

 

下载 HidTest

参考:

1.http://blog.csdn.net/xuxinhua/article/details/6329182 转: vs2008 hidsdi.h 问题

Step to UEFI (12) —- EADK 中的 Time 函数

这次的工作是基于 EADK 的,编译借用EADK的环境这样做有编译速度快,测试方便的优点,具体配置请参考 ”http://www.lab-z.com/how-to-use-eadk/“

关于 time_t 的定义可以在 \EadkPkg_A2\StdLib\Include\time.h 中看到。测试了一下,sizeof(time_t) == 4。

time()函数取得的结果是当前系统的时间,具体的定义是:返回从GMT1970年1月1日 0:0:0 开始经过的秒数表示的当前时间和日期。

下面可以看到 time() 有两种用法。

代码如下,很简单

/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
    This program and the accompanying materials
    are licensed and made available under the terms and conditions of the BSD License
    which accompanies this distribution. The full text of the license may be found at
    http://opensource.org/licenses/bsd-license.

    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//#include  <Uefi.h>
//#include  <Library/UefiLib.h>
//#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <time.h>

/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @param[in]  Argc    Number of argument tokens pointed to by Argv.
  @param[in]  Argv    Array of Argc pointers to command line tokens.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{

  time_t t;

  time(&t);

  printf("%ld\n",t);

  t=time(NULL);

  printf("%s\n",ctime(&t));

  return 0;
}

 

运行结果

time

下载

main

参考:

1.http://ganquan.info/standard-c/function/time Standard C 语言标准函数库速查 (Cheat Sheet)

2.书籍 《C函数实用手册》 个人感觉这本书不错,蛮实用,实例详尽。缺点是缺少一些新的C函数,可能是因为这本书目标是TC,并且是2003年的书籍。当初是为了用 Turbo C 所以才买的.

Step to UEFI (11)—- 让程序中断运行的方法

前面介绍了 Pasue 一下的方法,这里再介绍一下让程序停止执行的方法。 和 DOS 不同,Shell中的程序通常都像吃过炫迈口香糖那样—-根本停不下来…..要想能够中止运行,可以通过 Shell Environment 2 特别设置一下。

下面的代码设置了 ESC 为Break 键,运行中可以使用它来终止运行,这里的代码和前面 PauseTest的长得几乎一样:

//
// PauseTest.c
//
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/BaseMemoryLib.h>

#define SHELL_INTERFACE_PROTOCOL \
  { \
    0x47c7b223, 0xc42a, 0x11d2, 0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
  }
EFI_GUID        ShellInterfaceProtocol  = SHELL_INTERFACE_PROTOCOL;
EFI_GUID		SEGuid = EFI_SE_EXT_SIGNATURE_GUID;
//
// The shell environment is provided by a driver.  The shell links to the
// shell environment for services.  In addition, other drivers may connect
// to the shell environment and add new internal command handlers, or
// internal protocol handlers.
//
#define SHELL_ENVIRONMENT_INTERFACE_PROTOCOL \
  { \
    0x47c7b221, 0xc42a, 0x11d2, 0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
  }
EFI_GUID        ShellEnvProtocol = SHELL_ENVIRONMENT_INTERFACE_PROTOCOL;

#define EFI_OUTPUT_PAUSE    0x00000002

typedef struct {
  SHELLENV_EXECUTE          Execute;  // Execute a command line
  SHELLENV_GET_ENV          GetEnv;   // Get an environment variable
  SHELLENV_GET_MAP          GetMap;   // Get mapping tables
  SHELLENV_ADD_CMD          AddCmd;   // Add an internal command handler
  SHELLENV_ADD_PROT         AddProt;  // Add protocol info handler
  SHELLENV_GET_PROT         GetProt;  // Get the protocol ID
  SHELLENV_CUR_DIR          CurDir;
  SHELLENV_FILE_META_ARG    FileMetaArg;
  SHELLENV_FREE_FILE_LIST   FreeFileList;

  //
  // The following services are only used by the shell itself
  //
  SHELLENV_NEW_SHELL        NewShell;
  SHELLENV_BATCH_IS_ACTIVE  BatchIsActive;

  SHELLENV_FREE_RESOURCES   FreeResources;
} EFI_SHELL_ENVIRONMENT;

EFI_SHELL_INTERFACE             *SI;
EFI_SHELL_ENVIRONMENT           *SE;
EFI_SHELL_ENVIRONMENT2          *SE2;

EFI_BOOT_SERVICES     *gBS;
EFI_RUNTIME_SERVICES  *gRT;
EFI_SYSTEM_TABLE      *gST;

//Copy from \Shell\Library\Misc.c
BOOLEAN
GrowBuffer (
  IN OUT EFI_STATUS   *Status,
  IN OUT VOID         **Buffer,
  IN UINTN            BufferSize
  )
/*++

Routine Description:

  Helper function called as part of the code needed
  to allocate the proper sized buffer for various 
  EFI interfaces.

Arguments:

  Status      - Current status

  Buffer      - Current allocated buffer, or NULL

  BufferSize  - Current buffer size needed
    
Returns:
    
  TRUE - if the buffer was reallocated and the caller 
  should try the API again.

--*/
{
  BOOLEAN TryAgain;

  //
  // If this is an initial request, buffer will be null with a new buffer size
  //
  if (NULL == *Buffer && BufferSize) {
    *Status = EFI_BUFFER_TOO_SMALL;
  }
  //
  // If the status code is "buffer too small", resize the buffer
  //
  TryAgain = FALSE;
  if (*Status == EFI_BUFFER_TOO_SMALL) {

    if (*Buffer) {
      FreePool (*Buffer);
    }

    *Buffer = AllocateZeroPool (BufferSize);

    if (*Buffer) {
      TryAgain = TRUE;
    } else {
      *Status = EFI_OUT_OF_RESOURCES;
    }
  }
  //
  // If there's an error, free the buffer
  //
  if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {
    FreePool (*Buffer);
    *Buffer = NULL;
  }

  return TryAgain;
}

//Copy from \Shell\Library\Handle.c
EFI_STATUS
LocateHandle (
  IN EFI_LOCATE_SEARCH_TYPE       SearchType,
  IN EFI_GUID                     * Protocol OPTIONAL,
  IN VOID                         *SearchKey OPTIONAL,
  IN OUT UINTN                    *NoHandles,
  OUT EFI_HANDLE                  **Buffer
  )
/*++

Routine Description:

  Function returns an array of handles that support the requested protocol 
  in a buffer allocated from pool.

Arguments:

  SearchType           - Specifies which handle(s) are to be returned.
  Protocol             - Provides the protocol to search by.   
                         This parameter is only valid for SearchType ByProtocol.
  SearchKey            - Supplies the search key depending on the SearchType.
  NoHandles            - The number of handles returned in Buffer.
  Buffer               - A pointer to the buffer to return the requested array of 
                         handles that support Protocol.

Returns:
  
  EFI_SUCCESS           - The result array of handles was returned.
  EFI_NOT_FOUND         - No handles match the search. 
  EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results.

--*/
{
  EFI_STATUS  Status;
  UINTN       BufferSize;

  //
  // Initialize for GrowBuffer loop
  //
  Status      = EFI_SUCCESS;
  *Buffer     = NULL;
  BufferSize  = 50 * sizeof (EFI_HANDLE);

  //
  // Call the real function
  //
  while (GrowBuffer (&Status, (VOID **) Buffer, BufferSize)) {
    Status = gBS->LocateHandle (
                  SearchType,
                  Protocol,
                  SearchKey,
                  &BufferSize,
                  *Buffer
                  );
  }

  *NoHandles = BufferSize / sizeof (EFI_HANDLE);
  if (EFI_ERROR (Status)) {
    *NoHandles = 0;
  }

  return Status;
}

INTN
CompareGuidx (
  IN EFI_GUID     *Guid1,
  IN EFI_GUID     *Guid2
  )
/*++

Routine Description:

  Compares to GUIDs

Arguments:

  Guid1 - guid to compare
  Guid2 - guid to compare

Returns:
  =  0  if Guid1 == Guid2
  != 0  if Guid1 != Guid2 

--*/
{
  INT32 *g1;
  INT32 *g2;
  INT32 r;

  //
  // Compare 32 bits at a time
  //
  g1  = (INT32 *) Guid1;
  g2  = (INT32 *) Guid2;

  r   = g1[0] - g2[0];
  r |= g1[1] - g2[1];
  r |= g1[2] - g2[2];
  r |= g1[3] - g2[3];

  return r;
}
// Copy from \Shell\Library\Init.c
EFI_STATUS
LibInitializeShellApplication (
  IN EFI_HANDLE                   ImageHandle,
  IN EFI_SYSTEM_TABLE             *SystemTable
  )
{
  EFI_STATUS  Status;
  EFI_HANDLE  *HandleBuffer;
  UINTN       HandleNum;
  UINTN       HandleIndex;
  EFI_GUID         SESGuid         = EFI_SE_EXT_SIGNATURE_GUID;
  
  //
  // Connect to the shell interface
  //
  Status = gBS->HandleProtocol (ImageHandle, &ShellInterfaceProtocol, (VOID *) &SI);
  if (EFI_ERROR (Status)) {
    Print (L"InitShellApp: Application not started from Shell\n");
    gBS->Exit (ImageHandle, Status, 0, NULL);
  }

  //
  // Connect to the shell environment
  //
  Status = gBS->HandleProtocol (
                ImageHandle,
                &ShellEnvProtocol,
                (VOID *) &SE2
                );
  if (EFI_ERROR (Status) || !(CompareGuid (&SE2->SESGuid, &SESGuid) == 0 &&
    (SE2->MajorVersion > EFI_SHELL_MAJOR_VER ||
      (SE2->MajorVersion == EFI_SHELL_MAJOR_VER && SE2->MinorVersion >= 
EFI_SHELL_MINOR_VER))
    )
  ) {
    Status = LocateHandle (
              ByProtocol,
              &ShellEnvProtocol,
              NULL,
              &HandleNum,
              &HandleBuffer
              );
    if (EFI_ERROR (Status)) {
      Print (L"InitShellApp: 1Shell environment interfaces not found\n");
      gBS->Exit (ImageHandle, Status, 0, NULL);
    }

    Status = EFI_NOT_FOUND;
    for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
      gBS->HandleProtocol (
           HandleBuffer[HandleIndex],
           &ShellEnvProtocol,
           (VOID *) &SE2
           );
      if (CompareGuidx (&SE2->SESGuid, &SESGuid) == 0)
	  {
        Status = EFI_SUCCESS;
        break;
      }
    }

    FreePool (HandleBuffer);

    if (EFI_ERROR (Status)) {
      Print (L"InitShellApp: 2Shell environment interfaces not found\n");
      gBS->Exit (ImageHandle, Status, Status, NULL);
    }
  }

  SE = (EFI_SHELL_ENVIRONMENT *) SE2;
  
  //
  // Done with init
  //
  return Status;
}

//
// Entry point function 
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
   INTN	i;
   BOOLEAN ExitMark=FALSE;
   
   gST = SystemTable;
   gBS = SystemTable -> BootServices;
   
   LibInitializeShellApplication (ImageHandle,SystemTable);
   
   while (!ExitMark) 
    {
		//Clear Screen
		gST -> ConOut -> ClearScreen(gST->ConOut);
   	    Print(L"You can break by ESC key\n");
		for (i=0;i<80*(25-1);i++)
		{
			if (SE2 -> GetExecutionBreak() ) {ExitMark=TRUE; break;}
			Print(L".");
		} 
	}
	 
  return EFI_SUCCESS;
}

 

运行结果:

BreakTest

代码:

BreakTest

使用Paypal支付外币多付款的问题

如果你使用的是信用卡,那么一定要注意下面的问题:

1.如果你是在国内的 Paypal 注册的,那么无法支付美元。

2.如果你是在国外注册的 Paypal ,那么一定要联系客服(英文服务),否则无法支付美元。

这里解释一下“无法支付美元”是什么意思。比如:你看中了 100美元的货物,然后购买的话,Paypal会先将这100美元转换为 640人民币(比如当天的汇率为6.2,他们会使用比普通中间值要高的汇率!),然后你的信用卡上面会出现你支付了 640人民币的账目,但是月末出账单的时候上面会显示 你有一笔 104.9美元的支付,(银行会使用比如 6.1 来“帮”你折算成美元,因为你的消费并非美元而是“当地货币”),同时银行还会向你收取 1.5% = 1.5美元左右的手续费。这个手续费银行方面的解释是“一般持卡人都是用人民币-美元的双币种卡,在非美元地区使用,就需要先将当地货币转换为美元,而这时候会被国际卡组织收取至少1.5%的货币转换费。”【参考 1】

上面解释了一圈,归结起来就是一句话:你以为自己支付的是美元,实际上却是人民币,因此Paypal和银行都会过来“帮”你转换货币,代价是你要为此多支付4%左右。

下面就是如何解决这个问题:

对于1的情况,Paypal的客服刚开始告诉我说页面可以进行设置,但是我实在无法找到。后来他们改口说请注册国际的 Paypal。之后,我注册了国际的,但是再次支付又出现了同样的问题。他们客服告诉我说这是因为我的信用卡被自动识别为中国区,为我考虑,自动用人民币给我结算。我还和他们确认过在页面上没有相关选项,必须通知他们客服人工进行修改,当然也没有这条必须人工修改的提示. 【参考 2】

所以,新注册并且绑定信用卡之后,请务必联系客服人员,确定币种问题,问题是他们好像只有英文服务哎~ 国内有中文服务,但是很明显他们无法解决问题,并且态度方面要比国际客服差一些。

参考:

1.http://info.cmbchina.com/Stock/Detail.aspx?channel=Mac&topic=GNHG&id=4722460 境外消费用对信用卡可省1.5%货币转换费

2.客服给我的解释。我是想要他们关于这个问题的详细 policy ,但是那个哥们只是给我解释了一下。

Allow me to explain that when you register a PayPal account and add a local credit card to your PayPal account, the primary currency will follow the local currency. For example:

China registered PayPal account, you add a local credit or debit card; the primary currency for the card is in CNY.
Japan registered PayPal account, you add a local credit or debit card; the primary currency for the card is in JPY.
Singapore registered PayPal account, you add a local credit or debit card; the primary currency for the card is in SGD.

However if you have a local credit or debit card that is in USD or another currency, you need to inform PayPal to change the currency for you as this is considered a special case.

I apologize for the inconvenience caused and I appreciate your understanding regarding this matter.

Should you need further assistance at any point of time, please do remember that you have someone right here who is more than happy to assist and resolve your issue for you personally.

Have a wonderful evening ahead!

Thank you for choosing PayPal. Your satisfaction is important to us. We welcome your feedback and hope you recommend us to your friends and family.

Please make sure you have a valid mobile phone number on your PayPal account so that we can contact you if we need to confirm any unusual account activity and protect you from unauthorized account use. To add or update a mobile phone number is easy: Log in to your PayPal account, click ‘Profile’ near the top of the page, and then click ‘Update’ beside ‘Phone.’

Sincerely,
XXXXX
PayPal, an eBay Company

Copyright© 2014 PayPal Inc. All rights reserved.

Consumer advisory: PayPal Pte Ltd, the Holder of the PayPal™ payment service stored value facility, does not require the approval of the Monetary Authority of Singapore. Consumers (users) are advised to read the terms and conditions carefully.