You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
4.0 KiB

package nfc
import (
"errors"
"fmt"
"os"
"strings"
"github.com/ebfe/scard"
)
var ctx *scard.Context
var readers []string
func die(err error) {
fmt.Println(err)
os.Exit(1)
}
func initReader() error {
var err error
// Establish a context
ctx, err = scard.EstablishContext()
if err != nil {
return err
}
// List available readers
readers, err = ctx.ListReaders()
if err != nil {
return errors.New("讀卡機未連接")
}
fmt.Printf("Found %d readers:\n", len(readers))
for i, reader := range readers {
fmt.Printf("[%d] %s\n", i, reader)
}
return nil
}
func GetNfcId() (string, error) {
err := initReader()
if err != nil {
return "", err
}
if len(readers) > 0 {
//Connect to card
fmt.Println("Connecting to card in ", readers[0])
card, err := ctx.Connect(readers[0], scard.ShareExclusive, scard.ProtocolAny)
if err != nil {
return "", errors.New("請將卡片放置讀卡機上")
}
defer card.Disconnect(scard.ResetCard)
fmt.Println("Card status:")
status, err := card.Status()
if err != nil {
return "", err
}
fmt.Printf("\treader: %s\n\tstate: %x\n\tactive protocol: %x\n\tatr: % x\n",
status.Reader, status.State, status.ActiveProtocol, status.Atr)
apdu := []byte{0xFF, 0xCA, 0x00, 0x00, 0x00}
rsp, err := card.Transmit(apdu)
if err != nil {
return "", err
}
// Parse UID from response
if len(rsp) >= 3 && rsp[len(rsp)-2] == 0x90 && rsp[len(rsp)-1] == 0x00 {
uid := rsp[:len(rsp)-2]
//將uid reverse
reverseBytes(uid)
return strings.ToUpper(fmt.Sprintf("%x", uid)), nil
}
return "NFC ID", nil
}
return "", fmt.Errorf("No NFC reader found")
}
func WriteNfcCard(data string) (string, error) {
err := initReader()
if err != nil {
return "", err
}
if len(readers) > 0 {
// Connect to card
fmt.Println("Connecting to card in ", readers[0])
card, err := ctx.Connect(readers[0], scard.ShareExclusive, scard.ProtocolAny)
if err != nil {
return "", err
}
defer card.Disconnect(scard.ResetCard)
fmt.Println("Card status:")
status, err := card.Status()
if err != nil {
return "", err
}
fmt.Printf("\treader: %s\n\tstate: %x\n\tactive protocol: %x\n\tatr: % x\n",
status.Reader, status.State, status.ActiveProtocol, status.Atr)
url := []byte(data)
ndef := []byte{
0x03, byte(len(url) + 5), 0xd1, 0x01,
byte(len(url) + 1), 0x55, 0x04,
}
//將url加入ndef,最後以0xef結尾
ndef = append(ndef, url...)
ndef = append(ndef, 0xfe)
// for _, b := range ndef {
// fmt.Printf("%02x ", b)
// }
// fmt.Println()
//將ndef 4bytes一組
groupSize := 4
ndefSize := len(ndef)
groupCount := ndefSize / groupSize
if ndefSize%groupSize != 0 {
groupCount++
}
//將ndef分組
groups := make([][4]byte, groupCount)
for i := 0; i < groupCount; i++ {
start := i * groupSize
end := start + groupSize
if end > ndefSize {
end = ndefSize
}
copy(groups[i][:], ndef[start:end])
}
//將ndef分組後的資料寫入卡片
for i, group := range groups {
var cmd = []byte{
0xFF, 0xD6,
0x00,
byte(4 + i),
0x04,
}
cmd = append(cmd, group[:]...)
fmt.Println(cmd)
fmt.Println("Transmit:")
fmt.Printf("\tc-apdu: % x\n", cmd)
rsp, err := card.Transmit(cmd)
if err != nil {
return "", err
}
fmt.Printf("\tr-apdu: % x\n", rsp)
}
apdu := []byte{0xFF, 0x00, 0x52, 0xFF, 0xFF}
rsp, err := card.Transmit(apdu)
if err != nil {
return "", err
}
fmt.Println()
fmt.Printf("\tr-apdu: % x\n", rsp)
fmt.Println("Done")
}
return "", nil
}
func waitUntilCardPresent() (int, error) {
rs := make([]scard.ReaderState, len(readers))
for i := range rs {
rs[i].Reader = readers[i]
rs[i].CurrentState = scard.StateUnaware
}
for {
for i := range rs {
if rs[i].EventState&scard.StatePresent != 0 {
return i, nil
}
rs[i].CurrentState = rs[i].EventState
}
err := ctx.GetStatusChange(rs, -1)
if err != nil {
return -1, err
}
}
}
func reverseBytes(slice []byte) {
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
slice[i], slice[j] = slice[j], slice[i]
}
}