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] } }