@ScottMC I don't recommend you put the OSMODE change in the CMDACTIVE loop. Here is how I would do it; tested this and it works perfectly.
(defun c:C2 (/ cr el *error* fp oe os p p2)
(defun *error* (msg)
(if oe (setvar "cmdecho" oe))
(if os (setvar "osmode" os))
(vla-endundomark (vla-get-activedocument (vlax-get-acad-object)))
(princ (strcat "\n" msg))
)
(vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
(setq oe (getvar "cmdecho")
os (getvar "osmode")
)
(setvar "cmdecho" 0)
(while (and
(setvar 'osmode (boole 7 os 512))
(setq fp (getpoint "\nSpecify 1st Point of 2P.Circle: "))
)
(command "._Circle" "_2P" "_non" fp "_per");; Add "PER" to overide OSNAP here.
(princ "\nSecond Point: ")
(while (= (logand (getvar "cmdactive") 1) 1)
(command pause)
)
(setvar "osmode" os)
(setq el (entget (entlast))
p (trans (cdr (assoc 10 el)) (cdr (assoc 210 el)) 1)
p2 (getvar "lastpoint")
cr (getvar "circlerad")
)
(entdel (entlast)); Delete the Circle
(princ
(strcat
"\n Coordinates: "
(setq C2:pp ;; Global Variable "C2:pp"
(strcat
(rtos (car p) 2 4) ","
(rtos (cadr p) 2 4) ","
(rtos (caddr p) 2 4)
)
)
"\n Diameter: "
(rtos (* cr 2) 2 4)
" | Radius: "
(rtos cr 2 4)
"\n"
)
)
(entmakex (list (cons 0 "POINT") (cons 10 p)))
(entmakex (list (cons 0 "POINT") (cons 10 p2)))
(entmakex (list (cons 0 "CIRCLE") (assoc 10 el) (assoc 8 el) (assoc 40 el))) ; Recreate the Circle
)
(setvar "cmdecho" oe)
(vla-endundomark (vla-get-activedocument (vlax-get-acad-object)))
(princ)
)
If you don't want PERP to be the only snap available, then try your method, but before the CMDACTIVE loop:
(command ".circle" "2p" 1st)
(setvar 'cmdecho 1)
(setvar 'osmode (boole 7 (getvar 'osmode) 128)) ;; added 'perp
(while (= 1 (logand 1 (getvar 'cmdactive)))
(command "\\")
)